Roswell - Common Lisp environment setup Utility

23 February 2017 #lisp

Есть такой интересный проект, связанный с Common Lisp, как Roswell, который предназначен для установки и одновременного использования различных версий лиспа в систему. А так же интегрирован с quicklisp, несколько расширяя его возможности. Помимо прочего предоставляет возможность создания своих собственных скриптов на лиспе.

Использовать можно на целом ряде систем, в MacOS ставить очень просто:

$ brew install roswell

Есть пакет для Arch Linux, и предполагается подготовить для других дистрибутивов. Под Windows мне так и не удалось заставить его работать. Во всех остальных случаях предлашается устанавливать Roswell с помощью компиляции исходников.

По возможностям Roswell отправлять почитать официалную страницу. Довольно подробно описано все, что нужно. А сейчас хотел бы остановиться на некоторых проблемах.

Roswell особо привлекает к себе внимание из-за возможности создавать скрипты, в которых очень просто использовать quicklisp. SBCL в режиме скрипта данной возможности не имеет. Вроде все просто, создаем скрипт:

$ ros init script
$ cat script.ros
#!/bin/sh
#|-*- mode:lisp -*-|#
#| <Put a one-line description here>
exec ros -Q -- $0 "$@"
|#
(progn ;;init forms
  (ros:ensure-asdf)
  ;;#+quicklisp (ql:quickload '() :silent t)
  )

(defpackage :ros.script.script.3696842266
  (:use :cl))
(in-package :ros.script.script.3696842266)

(defun main (&rest argv)
  (declare (ignorable argv)))
;;; vim: set ft=lisp lisp:

Теперь достаточно прописать требуемые действия в функцию main и все будет работать. При этом можно парсить аргументы командной строки, что передаются при запуске скрипта, и хранятся в переменной argv. К примеру, чтобы вывести первый аргумент (без проверки на его существование), добавляем вызов одной команды:

(defun main (&rest argv)
  (declare (ignorable argv))
  (print (first argv)))

Теперь при запуске с передачей аргумента увидим ее значение:

$ ./script.ros 234
"234"

Вроде все замечательно и все хорошо. Но я попытался использовать roswell-скрипт Александра Артеменко, что он написал для запуска генератора статических сайтов coleslaw: coleslaw-cli. И сколько я не пытался, скрипт у меня ни разу нормально не отработал.

Для парсинга командной строки Александр использовал библиотеку clon. Да, она очень удобна и функциональна, но подружить ее с Roswell мне так и не удалось. При запуске в режиме скрипта clon просто не отрабатывал. А вот если преобразовать скрипт в образ, то парсинг начинает нормально работать.

Хорошо, решил переписать скрипт, отказавшись от clon. В итоге получил следующее:

#!/bin/sh
#|-*- mode:lisp -*-|#
#| <Put a one-line description here>
exec ros -Q -- $0 "$@"
|#
(progn ;;init forms
  (ros:ensure-asdf)
  #+quicklisp (ql:quickload '("coleslaw") :silent t)
  )

(defpackage :ros.script.col.3696839213
  (:use :cl :coleslaw))
(in-package :ros.script.col.3696839213)

(defun main (&rest argv)
  (declare (ignorable argv))
  (if (< (length argv) 1)
      (progn
        (format t "Please fill directory")
        (SB-EXT:EXIT))
      (progn
        (let ((directory (nth 0 argv)))
          (format t directory)
          (coleslaw:main directory)))))

И тут столкнулся очень интересной багой. По другому даже не знаю как назвать. Вызов coleslaw:main приводит к запуску функции main данного скрипта, что приводит к бесконечному выполнению.

Update: После того, как написал статью, Александр указал мне на мою ошибку. Как оказалось, после использования ql:quickload не нужно было еще дополнительно прописывать coleslaw в секции use. Убрал, все заработало. Более того, используя команду ros build col.ros в короткий промежуток времени получил бинарник, который позволяет запускать coleslaw. Век живи, век учись…