Регистрация | Войти
Lisp — программируемый язык программирования

Hello World с GUI на Common Lisp

Автор: Кальянов Дмитрий

Источник: http://dmitry-vk.livejournal.com/21752.html

Создадим простую программу с GUI, которую можно будет запускать как отдельное приложение. Программа не будет делать ничего полезного, и будет просто показывать окно с надписью “Hello, world”.

Для построения GUI воспользуемся библиотекой cl-gtk2.

Опишем процесс по шагам

Запускаем Slime, загружаем cl-gtk2:

(asdf:oos 'asdf:load-op :cl-gtk2-gtk)

Создаем исходный файл (назовем его hello-world.lisp) со следующим текстом:

(defpackage :hello-world
  (:use :cl :gobject :gtk)
  (:export :main :run)
)


(in-package :hello-world)

(defun main ()
  (within-main-loop
    (let ((w (make-instance 'gtk-window :title "Hello, world"))
          (l (make-instance 'label :label "Hello, world!"))
)

      (container-add w l)
      (connect-signal w "destroy" (lambda (w)
                                    (declare (ignore w))
                                    (gtk-main-quit)
)
)

      (widget-show w)
)
)
)


(defun run ()
  (main)
  (join-main-thread)
)

В этом исходнике определяется пакет hello-world, в котором определяются две функции: main и run. Функция main нужна во время разработки – она запускает программу в другой нитке (за это отвечает макрос within-main-loop), а run используется при запуске программы отдельно, не из slime.

Функция join-main-thread ожидает, когда главный цикл обработки сообщений в Gtk+ будет завершен. Этот цикл завершается, когда окно закрывается и получает сигнал “destroy”.

Можно протестировать программу прямо из Slime:

(hello-world:main)

После ввода этой формы в REPL будет запущена фоновая нить (thread), в которой работает Gtk+, и управление сразу вернется в REPL.

Теперь перейдем к созданию программы, которая может запускаться отдельно.

Для начала, следует определить ASDF-систему для нашего hello-world'а.

Создаем файл hello-world.asd в одном каталоге с hello-world.lisp следующего содержания (хотя названия системы и пакета в данном примере совпадают, это совсем не обязательно):

(defsystem :hello-world
  :name "hello-world"
  :components ((:file "hello-world"))
  :depends-on (:cl-gtk2-gtk)
)

В этом описании системы указывается, как следует собирать программу: программа зависит от системы cl-gtk2-gtk и состоит из одного исходного файла hello-world.lisp (расширение .lisp добавляется автоматически).

Обычно с помощью ASDF определяются системы, содержащие код библиотек и помещаются в общесистемный каталог /usr/share/common-lisp/systems. В данном случае, определяется система для отдельной программы.

С помощью cl-launch можно превратить описание этой системы в запускающий бинарник.

Сперва надо установить cl-launch. В gentoo linux с подключенным lisp-overlay это делается вводом команды

emerge dev-lisp/cl-launch

В других дистрибутивах можно воспользоваться ASDF-INSTALL для установки в общесистемный каталог или каталог пользователя:

(require :asdf-install)
(asdf-install:install :cl-launch)

cl-launch содержит шелл-скрипт cl-launch.sh, который используется для приготовления лисповских программ к запуску как отдельные приложения.

Сперва создадим образ лиспа, в котором содержатся cl-gtk2-gtk и наш hello-world. Если не создавать образ, то придется загружать cl-gtk2-gtk из исходников или fasl'ов. Загрузка и компиляция из исходников – очень долгий процесс; загрузка из fasl'ов происходит быстрее, но все равно долго (на моем компьютере загрузка из fasl'ов занимает 30 секунд). Для разработки программ создавать образ не нужно, так как все загружается один раз при запуске.

Для того, чтобы создать образ, введем команду (находясь в одном каталоге с hello-world.lisp и hello-world.asd):

cl-launch.sh -s hello-world -d hello-world-image

cl-launch загружает систему hello-world вместе со всеми зависимости (cl-launch добавляет текущий каталог в список каталогов, в которых ASDF ищет системы, поэтому никаких симлинков на hello-world.asd создавать не нужно) и сохраняет образ в файл hello-world-image.

Если установлено несколько реализаций лиспа, то можно выбрать, какую из них использовать:

cl-launch.sh --lisp sbcl -s hello-world -d hello-world-image

Далее надо с помощью cl-launch создать шелл-скрипт, запускающий программу из созданного образа:

cl-launch.sh -m hello-world-image -i '(hello-world:run)' -o hello-world

(если установлено несколько реализаций лиспа, то также можно добавить ключ –lisp)

В результате этой команды будет создан скрипт hello-world, который запускает программу.

Попробуем запустить его:

./hello-world

Должно практически сразу же появиться окошко:

Изображение

Время запуска программы из образа можно назвать вполне приемлемым: окошко появляется спустя едва различимый интервал времени.

Но у рассмотренного способа создания приложений есть один недостаток – размер получаемого образа. В моем случае (для SBCL на 64-битной машине) размер составил 64 мегабайта. Основная часть этого образа – сам SBCL (размер основного образа SBCL на моей машине – 42 мегабайта), остальная часть – это cl-gtk2-gtk и совсем небольшая часть – собственно приложение. То есть, при усложнении собственной программы и добавлении к ней кода размер образа не будет сильно расти.

Чтобы исправить эту проблему, можно сжать исполняемый образ с помощью программы gzexe.

gzexe hello-world-image

На моей машине размер образа уменьшается с 64Mb до 12Mb и несколько увеличивается время загрузки программы (с 0.5 с до 1.4 с). 12Mb – это уже более приемлемо даже для загрузки программы из интернета, но все равно много. Разные реализации лиспа создают образы по-разному, и размеры варьируются от реализации к реализации, поэтому из приведенных чисел не следует, что приложения всегда будут получаться большими.

Одним из приемлемых способов распространения приложений на лиспе для дистрибутивов линукса, по-видимому, является сборка образа из исходников на конечной машине. При таком способе общий объем загружаемых из интернета данных получается не настолько большим (при условии, что в составе дистрибутива имеется компилятор лиспа), и время запуска приложения приемлемое. При этом все используемые лисповые библиотеки можно как брать с машины пользователя (для gentoo- или debian-подобных дистрибутивов), так и держать рядом с исходниками (если нет пакетного менеджера, в репозитории которого имеется необходимый софт)

Замечание: сохранение образов с загруженным cl-gtk2 пока работает лишь в SBCL. Работоспособность сохраненных образов с cl-gtk2 в других лиспах - вопрос времени.

@2009-2013 lisper.ru