Обо мне

Моя фотография
Дикий Полярный Сов

вторник, 9 марта 2010 г.

Компилируем бинарники из лиспа - SBCL и clisp

Давно не писал, потому что пока что почти все вечера у меня заняты погружением в Коммон Лисп.

Пощупал 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 мег.

4 комментария:

  1. > 28 мегабайт. Ага, для простенького скрипта.

    Это не простенький скрипт, это весь SBCL целиком, плюс твой function-name.

    ОтветитьУдалить
  2. Ну да, чуть позже я разобрался, откуда берется такой объем

    ОтветитьУдалить
  3. А вот как-нибудь не запуская интерактивный REPL это можно сделать? Чтобы использовать с чем-нибудь вроде make.

    ОтветитьУдалить
  4. На ум приходит вариант - написать отдельный скрипт, который проводит указанные выше операции, и запускать его. Не знаю, насколько это пригодно вообще.

    ОтветитьУдалить