Пощупал Clojure, и она мне, в целом, понравилась, если бы не одно "но" - совершенно неочевидные внутренние механизмы джавы, благодаря которым я вообще не понимаю, что к чему, что это за classpath, зачем он нужен, почему его надо явно указывать и с какой стати мой простейший скрипт на две строчки тормозит полторы секунды перед выполнением. Конечно же, если вникнуть во внутреннее устройство джавки и научиться компилировать мои clojure-произведения в *.jar, все будет работать быстрее. Но это впереди, а пока что я решил закончить-таки Practical Common LISP.
И сегодня я расскажу, как компилировать бинарник в SBCL и clisp.
Итак, начнем с SBCL. Подготовив наш файл к запуску, а именно - написав функцию, которая будет запускаться первой (этакий int main() :] ), мы грузим sbcl-овский REPL и пишем там:
(load "our-file-name")
Получив в ответ "Т", мы, в принципе, готовы приступать к компиляции. Вводим в REPL:
(sb-ext:save-lisp-and-die "binary-file-name" :executable t :toplevel 'function-name)
По идее, функция #'save-lisp-and-die просто сохраняет состояние интерпретатора лиспа, если бы не... параметр :executable вместе с :toplevel. Они содержат явное указание - скомпилировать бинарник, при запуске которого выполнится функция function-name. В качестве дополнительного требования к function-name sbcl просит явно вызывать функцию (quit).
Итак, когда я попробовал указанные выше манипуляции впервые и получил результат, радости моей не было предела. До тех пор, пока я не взглянул на размер бинарника - а он оказался, ни много ни мало, 28 мегабайт. Ага, для простенького скрипта. Ну, это остается на совести создателей SBCL, тем более, думаю, вряд ли сейчас для кого-то проблема бинарники в 20+ мег. Впрочем, глубоко этот вопрос я не ковырял, скорее всего, можно и сократить объем файла.
Теперь перейдем к clisp:
(load "our-file-name")
(ext:saveinitmem "binary-file-name" :executable t :init-function 'function-name :quiet t)
Здесь видим, что :toplevel меняется на :init-function и, кроме того, добавляется параметр :quiet, который препятствует показу баннера clisp перед запуском вашей программы. Меня такие вещи бесят. Кому нравится - не указывайте :quiet вообще.
Добавлю, что ваша программа должна содержать вызов функции #'ext:exit, чтобы она нормально завершила работу (иначе после того, как ваша программа завершится, пользователю покажут clisp-овский REPL).
Бинарник таким образом получается всего 5,5 мег.
> 28 мегабайт. Ага, для простенького скрипта.
ОтветитьУдалитьЭто не простенький скрипт, это весь SBCL целиком, плюс твой function-name.
Ну да, чуть позже я разобрался, откуда берется такой объем
ОтветитьУдалитьА вот как-нибудь не запуская интерактивный REPL это можно сделать? Чтобы использовать с чем-нибудь вроде make.
ОтветитьУдалитьНа ум приходит вариант - написать отдельный скрипт, который проводит указанные выше операции, и запускать его. Не знаю, насколько это пригодно вообще.
ОтветитьУдалить