Как сделать дамп исполняемого образа SBCL, использующего osicat

У меня есть простая серверная программа Common Lisp, которая использует библиотеку osicat для взаимодействия с файловой системой posix. Мне нужно сделать это, потому что система создает символические ссылки на файлы и использует метаданные статистики POSIX, а ни одну из этих вещей нельзя сделать в переносимом лиспе.

Я управляю зависимостями с помощью quicklisp, и все это привязано к рабочему дистрибутиву. Приложение переносимо между CCL и SBCL, и я обычно создаю его в первом и развертываю, используя последний. Я объявляю зависимости для приложения с помощью asdf defsystem и могу использовать quicklisp, чтобы загрузить его для упрощения разработки из локальных проектов.

Для развертывания я просто использовал несколько нестандартных плейбуков, которые копировали среду разработчика на удаленном компьютере (например, настройка quicklisp, загрузка кода в локальные проекты, запуск из домашнего каталога пользователя), что было хакерским, но в основном нормальным. Совсем недавно, когда он стал более стабильным, я компилировал его с помощью sb-ext:save-lisp-and-die, используя простой скрипт компиляции. Это означает, что я получаю исполняемый файл, который я могу запускать больше как сервер, со сценариями управления службами и анонимной учетной записью пользователя.

Это работает очень хорошо, и поэтому я недавно перевел этот шаг на следующий уровень, и я создаю пакеты .deb с помощью моего сценария компиляции, поэтому я могу собрать все в перемещаемый двоичный файл. Это тоже работает, но результирующие двоичные файлы нельзя перемещать с исходного хоста сборки. Они отказываются запускаться, и, похоже, они пытаются динамически загрузить общую библиотеку для osicat.

Unhandled SIMPLE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING
Mar 15 12:47:14 annie [479]:                                     {10005C05B3}>:
Mar 15 12:47:14 annie [479]:   Error opening shared object "libosicat.so":
Mar 15 12:47:14 annie [479]:   libosicat.so: cannot open shared object file: No such file or directory.

похоже, что изображение ожидает найти это в архивах quicklisp исходного дерева сборки

(ERROR "Error opening ~:[runtime~;shared object ~:*~S~]:~%  ~A." "/home/builder/buil...quicklisp/dists/quicklisp/software/osicat-20180228-git/posix/libosicat.so
(SB-SYS:DLOPEN-OR-LOSE #S(SB-ALIEN::SHARED-OBJECT :PATHNAME #P"

поэтому, копаясь в исходниках, я понимаю, что когда quicklisp извлекает osicat и выполняет свою операцию сборки, он компилирует эту DLL, чтобы обернуть свой интерфейс системными библиотеками, а не просто подключаться к ним напрямую — возможно, потому, что он использует cffi groveller, я не знаю я действительно много знаю о cffi (пока). Это нормально, но вместо того, чтобы ссылаться на .so с помощью системного компоновщика, он пытается dlopen получить его по фиксированному пути, который не очень переносим и как бы нарушает полезность save-image

На данный момент я немного озадачен, но прежде чем я углублюсь в сборки QL и cffi, я задался вопросом, есть ли какая-то конфигурация сборки или компиляции, которую мне не хватает, что сделало бы ее загрузку более «статичной» или влиять на производство упакованной библиотеки. В идеале мне просто нужен один большой двоичный объект, который я могу обернуть в установщик и связать его с системными библиотеками, но если мне нужно развернуть некоторые дополнительные артефакты, это, вероятно, нормально. Я не знаю, как сделать так, чтобы автоматически сгенерированные общие объекты появлялись на более контролируемом пути.

Однако в этот момент я также могу написать .so для своих вызовов posix и распространить его вместе с приложением и попытаться использовать FFI для него более напрямую. Это было бы немного больно, поэтому я бы предпочел этого не делать.


person cms    schedule 15.03.2019    source источник


Ответы (2)


Вы правы, когда образ с дампом запускается, он пытается перезагрузить общие библиотеки. Что, как вы понимаете, не работает, если образ не запускается на машине, на которую он был сброшен.

Это почти то, что установил static-program-op. выйти решить. Такое простое определение системы должно помочь вам скомпилировать статическую программу:

(defsystem "foo"
  :defsystem-depends-on ("cffi-grovel")
  :build-operation "static-program-op" ; "asdf" package is implied
  :build-pathname "foo" ; path of the generated binary
  :entry-point "foo:main" ; function to use as the entry point
  ;; ... everything else ...
  )

Если ваша система зависит от файлов grovel (определяемых :cffi-wrapper-file, :c-file или :o-file), таких как файлы, предоставляемые osicat, тогда она статически свяжет их с вашим выгруженным образом.

Однако это не идеально.

По сути, есть еще некоторые проблемы. Некоторые из них исправляются самой CFFI (например, не перезагружаются разделяемые библиотеки статически встроенных библиотек), другие немного сложнее. (Например, параметры компиляции SBCL по умолчанию не позволяют использовать static-program-op по умолчанию. Это исправлено в сборках SBCL Debian, но другие дистрибутивы менее отзывчивы.)

Это, очевидно, проблема, с которой столкнулось сообщество в целом, и есть несколько библиотек, которые могут помочь:

  • Первый, который существует уже некоторое время, — это Deploy. Подход, который он использует, заключается в том, что он встраивает выгруженный образ и библиотеки в архив и перестраивает вещи для двоичного файла, чтобы загружать их из любого места, куда они были извлечены.
  • Второй, к которому я склоняюсь, потому что я его создал, — это linux-packaging. Он использует подход исправления static-program-op путем его расширения, но требует создания пользовательского SBCL. Однако он генерирует дистрибутивные пакеты, такие как .deb и .rpm, чтобы иметь возможность указывать зависимости для системных общих библиотек (например, если вы зависите от sqlite, он выяснит, какой пакет его предоставляет, и добавит его в качестве зависимости в .deb). Я настоятельно рекомендую ознакомиться с .gitlab-ci.yml. Например.

Я рекомендую прочитать веб-страницы обеих этих библиотек, чтобы сделать свой выбор, у них обоих есть свои преимущества и недостатки. <joke>Очевидно, что Linux-упаковка лучше.</joke>

person Florian Margaine    schedule 08.08.2020

Возможно, вместо этого вы можете использовать sb-posix:symlink и sb-posix:fstat в SBCL, удалив зависимость от osicat с помощью переключателя функций.

person Svante    schedule 15.03.2019
comment
вау, я понятия не имел о sb-posix. это хороший совет. Я потерял бы переносимость для ccl, но я использую это только в локальной разработке, поэтому я мог бы перевернуть его с помощью условий чтения. Я думаю, это также сработает для зависимостей в defsystem - person cms; 15.03.2019
comment
было довольно просто заставить приложение собираться с этим изменением, и его можно перемещать, так что это полезный обходной путь. Жаль, что он не переносим, ​​хотя в сценариях сборки уже есть хлам, чтобы справиться с различиями. - person cms; 17.03.2019