Как я могу убедить mkbundle включить MonoPosixHelper?
Я использую mkbundle и пытаюсь создать встроенную версию маленькой программы IdaTester, которая использует Isis2. Эта система в свою очередь использует функции Mono, которые зависят от MonoPosixHelper
Моя проблема в том, что mkbundle не распознает зависимость, и я получаю исполняемый файл, который все еще должен динамически связываться с ~/bin/lib/libMonoPosixHelper.so, вызывая проблемы, когда я перемещаю этот исполняемый файл в систему, где я не установить моно. По сути, в пакете отсутствует одна из вещей, с которой он должен быть статически связан.
Мой исполняемый файл работает, но только в том случае, если я запускаю его только на машинах с динамической библиотекой в "правильном месте". Это противоречит цели встроенного исполняемого файла... Я надеялся, что смогу дать людям эту программу в качестве сервера, который они могли бы разместить в любом месте и запустить как двоичный файл, и, очевидно, если им нужно будет установить библиотеку, чтобы это работало сервер не совсем автономен!
Я вижу, как заставить mkbundle включать любые файлы dll, от которых зависит программа, но MonoPosixHelper не существует как dll; это библиотека только для Linux и существует только как общая библиотека. Кто-нибудь знает способ "заставить" пакет статически встраивать его?
Если это поможет, мой маленький скрипт компиляции выглядит следующим образом:
mcs -debug+ IdaTester.cs Isis.cs -r:System.dll -r:Microsoft.CSharp.dll -r:Mono.Posix.dll
mkbundle --static -o IdaTester IdaTester.exe --deps
Затем я запускаю IdaTester; это работает на платформах, где может быть найдена библиотека libMonoPosixHelper, но завершится с ошибкой во время выполнения при попытке динамически загрузить эту библиотеку, если она работает на платформе, где libMonoPosixHelper не была установлена ...
2 ответа
Нужно распространять libMonoPosixHelper.so с приложением и изменить карту DLL, чтобы сделать эту работу.
Предыстория проблемы - библиотека загружается во время выполнения
libMonoPosixHelper не является статически связанным, но выполняется поиск и загрузка в виде вызова P/Invoke, как в примере ниже:
[DllImport ("MonoPosixHelper")]
static extern int zipClose (ZipHandle handle, string globalComment);
То есть он запрашивается только во время выполнения, а не во время компиляции, и поэтому не может быть связан заранее.
Исправление - Распространение libMonoPosixHelper.so
Требуются четыре шага.
- Скопируйте libMonoPosixHelper в каталог, с которым вы будете распространять программу.
- Обновите файл конфигурации DllMap, чтобы избежать жесткого расположения.
- Вставить файл конфигурации с помощью mkbundle
- Добавьте путь с помощью libMonoPosixHelper.so к LD_LIBRARY_PATH на установочном компьютере.
Для выполнения каждого:
1. Скопируйте libMonoPosixHelper в каталог, с которым вы будете распространять программу.
libMonoPosixHelper обычно находится в папке lib, просто скопируйте его в папку, из которой вы будете делать архив.
cp $MONO_ROOT/lib/libMonoPosixHelper.so ~/MY_PROGRAM/
2. Обновите файл конфигурации DllMap, чтобы избежать жестко закодированного местоположения.
Это важный бит, чтобы избежать проблемы жестко закодированных путей. Нам нужно встроить файл конфигурации с mkbundle, в котором не указан путь. Для этого сначала найдите файл конфигурации mono, а также скопируйте его в локальный каталог.
cp $MONO_ROOT/etc/mono/config ~/MY_PROGRAM/config
Теперь нам нужно изменить этот файл, чтобы удалить конкретный путь для DLL, открыть его в вашем любимом редакторе и изменить пути, чтобы избежать конкретного префикса:
<dllmap dll="MonoPosixHelper" target="MACHINE_SPECIFIC/lib/libMonoPosixHelper.dylib" os="!windows" />
в
<dllmap dll="MonoPosixHelper" target="libMonoPosixHelper.dylib" os="!windows" />
3. Вставьте файл конфигурации с помощью mkbundle.
Добавьте следующую опцию в команду mkbundle, чтобы встроить недавно отредактированный файл конфигурации:
--config MY_PROGRAM/config
4. Добавьте путь с помощью libMonoPosixHelper.so к LD_LIBRARY_PATH на установочном компьютере.
Теперь вы можете заархивировать ваш исполняемый файл mkbundled, libMonoPosixHelper.so и любые другие файлы для распространения. Разархивированный и запущенный на машине, dlopen теперь будет искать libMonoPosixHelper.so, как и любой другой dll. Поэтому просто добавьте любой каталог, содержащий вашу распределенную версию libMonoPosixHelper, в их переменную среды LD_LIBRARY_PATH
Насколько я могу судить, лучший доступный для меня вариант - это создать библиотеку Mono без общего доступа, содержащую те же методы, которые в настоящее время находятся в MonoPosixHelper.so, либо предоставить копию MonoPosixHelper.so в качестве компонента, который будет установлен в той же папке, что и мой сервер. Ни то, ни другое не кажется идеальным: первое вынуждает меня "добраться до" дистрибутива Mono, что создает проблему более длительного обслуживания, а второе вынуждает меня переходить в более сложный режим дистрибуции и установки. Но, похоже, что когда вы создаете общую библиотеку, вы просто не можете статически связываться с этой версией библиотеки; загрузчик Linux просто не рассматривает такую вещь как библиотеку так, как она обрабатывает больше стандартных библиотек.
Напротив, если я сгенерирую стандартную библиотеку из тех же файлов.o, загрузчик будет рад статически скомпоновать ее, а поскольку в конечном итоге mxbundle запускает cc и, следовательно, использует стандартный ld, эта опция будет работать для меня. Так что я думаю, что это ответ на мой вопрос.