Допустим, у вас есть классная маленькая программка на Common Lisp под названием filter
. Она занимает всего один файл исходного кода под названием filter.lisp
примерно в 200 строк длиной. В этом файле вот такой заголовок:
(defpackage :localhost.me.filter
(:use :common-lisp)
(:export :run))
(in-package :localhost.me.filter)
И дальше собственно сама программа. Допустим также, что вы пользуетесь своей программой часто. Загвоздка в том, что для того, чтобы её запустить, вам необходимо сделать слишком много действий:
$ cd $PROGRAMDIR
$ sbcl
CL-USER> (load "filter.lisp")
CL-USER> (:localhost.me.filter:run)
Рассмотрим два решения, одно простое, но не всегда поможет, другое посложнее и поможет уже в большем числе случаев.
Решение первое
SBCL умеет запускать программы на CL в режиме скриптов командной строки, для этого используется специальный флаг --script
. Более того, благодаря этому можно написать лисп-программу, добавить к ней типичный юниксовый шебанг, вызывающий SBCL с этим флагом, и она будет работать как любой другой шелл-скрипт (за исключением того, что рантайм SBCL весит 50MB бгг). Так что напишем этот скрипт:
#!/usr/bin/sbcl --script
(load "filter.lisp")
(:localhost.me.filter:run)
Теперь положим этот скрипт в ту же директорию, что и filter.lisp
, в файл с именем run
и можно будет запускать нашу программу так:
$ ./run
Что и требовалось.
Решение второе
Однако, у флага --script
есть одна особенность: SBCL не загружает никакие пользовательские скрипты инициализации при старте, так что скрипт будет выполняться в 100% дефолтном рантайме. Это плохо, если, допустим, вы используете Quicklisp и у вас в filter.lisp
есть такой вызов:
...
(ql:quickload :CL-FAD)
(use-package :CL-FAD)
...
Ну или вызов любой другой библиотеки, неважно. Если запустить такой скрипт первым способом, то SBCL будет грязно ругаться по поводу того, что он не знает, что такое ql:quickload
.
Для решения этой проблемы мы смухлюем, подменив бинарник SBCL таким бинарником, у которого все нужные библиотеки уже загружены. В SBCL есть функция save-lisp-and-die
, которая выгружает текущее состояние рантайма в файл с указанным именем. Дальше этот файл можно использовать как обычный бинарник SBCL, в том числе, и для вызовов с использованием --script
. Поэтому если запустить SBCL и сразу выгрузить его в файл, то полученный бинарник будет содержать всё, что SBCL подключил при загрузке, основываясь на пользовательских конфигах.
(save-lisp-and-die "/абсолютный/путь/до/файла")
Теперь в скрипте run
, который написан по первому варианту, заменяем путь до системного SBCL путём до выгруженного бинарника, и скрипт начнёт работать как должен.
Комментариев нет:
Отправить комментарий