Сравнение ASDF и LispWorks Common Defsystem

Большая часть библиотек с исходным кодом на языке Коммон Лисп сопровождается файлом определения системы в формате ASDF (Another System Definition Facility). В LispWorks встроен собственный способ определения систем исходных файлов - макрос lw:defsystem и сопутствующие функции. Стоит ли их использовать, несмотря на наличие более универсальной и работающей на разных реализациях Лисп asd:defsystem?

За годы работы сложилось впечатление, что стоит. Ниже приведённые выводы подтверждаются: в дискуссиях эхоконференции comp.lang.lisp высказано немало сомнений в универсальности ASDF.

1. Определение в специальном пакете.

asd:defsystem рекомендуют помещать в собственный уникальный пакет. В целом, это слегка обременяет пакетную систему реализации Лисп и выглядит не очень элегантно. Можно этого не делать и помещать в пакет cl-user, что грозит конфликтами символов.

lw:defsystem не требует пакета - все будет работать без проблем в пакете cl-user.

2. Разделение скомпилированных файлов.

lw:defsystem позволяет отдельно хранить бинарники в собственных папках в зависимости от опций, например:

 (lw:defsystem my-system (:object-pathname 
                          (lw:current-pathname #+debug "bin/debug/"
                                               #-debug "bin/"))
   ...)
Значит, отладочная версия проекта всегда будет храниться отдельно от окончательной, причем обе отделены

Напротив, asd:defsystem помещает бинарники в тот же директорий, где и исходные Лисп-файлы. Разделение разных версий скомпилированных файлов невозможно встроенными средствами. Можно, конечно, определить подкласс asd:system, но это будет уже другая система :-). Пример определения можно найти в исходных текстах YstokHelp.

3. ASDF не поддерживает логические пути (logical pathnames).

Это значит, что если требуется компонент с исходником вне директория системы, в опции :pathname необхдимо указывать физический путь. Это весьма странно, ибо логические пути - весьма гибкий механизм, почти незаменимый, если Вы отлаживаетесь на разных компьютерах.

Пример задания логического пути:
  :pathname #P"LIB:doc;settings;general.html"

Обработку логических путей можно добавить (проверено для ASDF 1.131), определив следующий метод.

;;; Позволяет в качестве аргумента инициализации :pathname
;;; любого компонента указывать логический путь

(defmethod reinitialize-instance :after ((component asdf:component) 
                                         &key pathname)
  (setf (slot-value component 'asdf::relative-pathname)
        (translate-logical-pathname pathname)))

4. Inline-медоды в ASDF (:perform и прочие)

Обработка inline-методов довольно неэллегантна ASDF (видимо, в попытке достичь портативностьи). Функция %remove-component-inline-methods (см. asdf.lisp)  пытается удалять метод из обобщённой функции, к которой он явно не относится. Реализация функции remove-method в LW 4.4, мягко говоря, нестандартна и вызывает ошибку при таком обращении. Поэтому попытка повторно оценить определение системы asd:defsystem, содержащее опции :perform, :explain и т.п., выдаёт ошибку.

5. Браузер систем (System Browser) LispWorks

Определение системы в формате lw:defsystem может быть представлено в виде графа в браузере систем, который встроен в среду разработки LispWorks. Это обеспечивает наглядность и дополнительные удобства.

При желании можно загнать в браузер и ASDF-определение: утилита из комплекта lw-add-ons позволяет транслировать на лету определение системы: asd:defsystem -> lw:defsystem.

Вдобавок, в версии LW6 браузер может самостоятельно визуализировать ASDF-определение системы.

6. Резюме

В целом, для процесса разработки lw:defsystem лучше подходит. Она отработана годами и берёт начало от Лисп-машин.

Для дистрибуции же готового проекта asd:defsystem вполне достаточно. Даже inline-методы допустимы, если определение системы загружается единожды.

Ссылки

  1. ASDlite — легкая версия ASDF
  2. ASDF: how to locate resources (comp.lang.lisp)
  3. Preliminary analysis of existing ASDF practices (comp.lang.lisp)