вторник, 1 декабря 2009 г.

ASDF и Windows

Что к чему

В asdf есть переменная *central-registry*, содержащая список директорий в которых ищутся asdf-системы. То есть, чтобы система была доступна
для загрузки, нужно чтобы путь к её asd-файлу был в *central-registry*.

Но систем много, и каждую прописывать в *central-registry* утомительно. Поэтому принято делать несколько иначе: прописывается путь к какой-то одной директории (например ~/.sbcl/systems/), а в эту директорию помещаются символические ссылки на asd-файлы.

Windows

Очевидно, что в windows нет ссылок и, казалось бы, такой вариант не подходит. Но, к счастью, asdf неплохо настраивается и можно это
ограничение обойти. Переменная *system-definition-search-functions* содержит список функций поиска asdf-систем.

Вот такая функция и код добавления её в asdf. Эта функция обходит все директории из *central-registry* и просматривает в них все lnk-файлы,
извлекает путь ссылки и сравнивает с именем искомой системы.

(defun search-for-system-in-windows (system)
  (let ((system-name (asdf::coerce-name system)))
    (dolist (dir asdf:*central-registry*)
      (dolist (lnk (directory (merge-pathnames (eval dir) "*.lnk")))
        (let ((system-path (parse-windows-shortcut lnk)))
          (when (string-equal system-name (pathname-name system-path))
            (return-from search-for-system-in-windows system-path)))))))

(pushnew #'search-for-system-in-windows
  asdf:*system-definition-search-functions*)


Этот код был бы неполным без этого фрагмента http://paste.lisp.org/display/91121

Здесь вся машинерия разбора lnk-файлов.

Варианты

Очевидно, что можно сделать всё это ещё проще. Можно вместо lnk-файлов придумать, скажем, symlink-файлы -- простые текстовые файлы с путями внутри. Тогда чтение таких файлов будет тривиальным и кода будет поменьше.

Любители Windows могут сделать регистрацию и поиск asd-файлов даже в реестре. :)

Ну а так как функций поиска может быть несколько, то можно все эти способы сочетать.

Резюме


Остаётся добавить этот код в пользовательский файл инициализации, и можно пользоваться.
Для SBCL это будет $HOME/.sbclrc
для Clozure CL: $HOME/ccl-init.lisp