Переопределение @executable_path в DLL, загруженной с помощью dlopen()
Операционная система - MacOS X, в частности 10.5 (Leopard) на PowerPC G4, но у меня та же проблема на x86 под управлением 10.6.
Я пишу приложение, которое динамически загружает DLL. DLL (назовем это foo.dylib
) является частью другого приложения, расположенного в другом месте на жестком диске; мое приложение находит foo.dylib
программно (точное расположение может измениться, возможно, пользователь определяет путь к DLL через графический интерфейс непосредственно из запущенного приложения). Например, предположим, что мое приложение находится в каталоге /Application/MyApp.app/Contents/MacOS
, а также foo.dylib
случается в /Application/OtherApp.app/Contents/MacOS
, Загрузка DLL использует dlopen()
,
Теперь получается, что foo.dylib
сама по себе нужна куча других DLL, которые находятся в том же каталоге, но о которых я ничего не знаю заранее. Каждая такая дополнительная DLL зарегистрирована в foo.dylib
с таким путем, как @executable_path/bar.dylib
, Семантика @executable_path
в том, что он должен быть заменен каталогом, в котором был найден текущий исполняемый файл процесса. Это прекрасно работает для OtherApp, а не для меня: когда я открываю foo.dylib
, он пытается загрузить bar.dylib
и ищет это в /Application/MyApp.app/Contents/MacOS/bar.dylib
, который не является правильным каталогом.
Обходной путь должен установить DYLD_FALLBACK_LIBRARY_PATH
переменная среды для /Application/OtherApp.app/Contents/MacOS
, но это нужно сделать перед запуском моего приложения (эта переменная среды читается динамическим компоновщиком только один раз; программно изменяя ее значение с помощью setenv()
или же putenv()
не имеет никакого эффекта). Это несовместимо с динамическим обнаружением местоположения foo.dylib
файл.
Есть ли программный способ переопределить эффект @executable_path
?
2 ответа
Читая исходный код dyld (ищите @executable_path), я бы сказал, что ответ однозначно "нет". @executable_path заменяется на основной путь к исполняемому файлу, который хранится в виде глобальной строки в модуле dyld.
И да, ваше подозрение верное, dyld читает и сохраняет переменные окружения при запуске, поэтому вы не можете изменять их на лету (вы можете искать тот же исходный файл, который я связал для DYLD_LIBRARY_PATH). Вы могли бы иметь приложение-заглушку, которое устанавливает переменные среды и затем запускает ваше реальное приложение. Здесь Dyld не предлагает вам много решений, он не предназначен для того, чтобы позволить вам ссылаться в произвольных частных сторонних библиотеках.
Если вы поддерживаете OtherApp, вы можете использовать @loader_path вместо @executable_path для определения местоположения зависимостей: @loader_path всегда разрешает путь к модулю (то есть библиотеке или исполняемому файлу), который требует загрузки библиотеки, поэтому рекурсивные зависимости всегда найдены.
Это доступно с Mac Os 10.5 и далее.
Смотрите "man dyld" для подробной информации.
Другой вариант будет dlopen
Зависимости перед основной библиотекой.