вторник, 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

6 комментариев:

archimag комментирует...

Э... Ты зачем так настроил фиды? ;)

Sectoid комментирует...

Осталось теперь только asdf-install заломать, чтобы создавал правильно линки и высыпал системы куда надо.

Спасибо, Энди)

tymmym комментирует...

> Очевидно, что в windows нет ссылок

NTFS поддерживает ссылки - жесткие ссылки на файлы, символьные ссылки на директории, начиная с Windows Vista доступны символьные ссылки и на файлы.

Анонимный комментирует...

спасибо за идею, очень в тему пришлось. правда необходимость была больше в относительных линках, желательно еще и приспособленных к жизни в репозитории, так что остановился на файлах *.asd.location c pathname внутри.

и еще небольшое уточнение: ccl читает %HOMEPATH%/ccl-init.lisp, по меньшей мере в 1.4 так. Точно знаю, потому что %HOME% у меня в другом месте.

Дмитрий Статывка

andy128k комментирует...

@tymmym

Всё так. Ссылки в NTFS есть. Но, дело не столько в их наличии, сколько в API. Смысл их использования в том, что asdf находит их в одном месте, но может получить truename. В NTFS же, так не получится, по крайней мере ни SBCL, ни CCL, ни Clisp не знают ничего об этих ссылках.

andy128k комментирует...

@Дмитрий Статывка

Ага, *.asd.location (я их назвал symlink-файлами) лучше.

У меня %HOME% тоже в другом месте, но CCL всё равно грузил из C:/Users/%username%. Странно всё это. А вот SBCL грузит как надо: из %HOME%/.sbclrc.