操作系统是MacOS X,特别是PowerPC G4上的10.5(Leopard),但我在运行10.6的x86上遇到了同样的问题。
我正在编写一个动态加载DLL的应用程序。 DLL(我们称之为foo.dylib
)是位于硬盘上其他位置的另一个应用程序的一部分;我的应用程序以编程方式找到foo.dylib
(确切的安置可能会改变,可能是用户通过运行的应用程序本身的GUI指定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
的效果?
答案 0 :(得分:6)
通过阅读dyld source(搜索@executable_path),我会说答案是明确的“不”。 @executable_path替换为主可执行路径,该路径作为全局字符串存储在dyld模块中。
是的,您的怀疑是正确的,dyld在启动时读取并保存其环境变量,因此您无法动态更改它们(您可以搜索我为DYLD_LIBRARY_PATH链接的相同源文件)。您可以拥有一个存根应用程序来设置环境变量,然后启动您的实际应用程序。 dyld在这里没有提供很多解决方案,它并不是真的旨在让你链接到任意私有第三方库。
答案 1 :(得分:2)
如果您维护OtherApp,则可以使用@loader_path而不是@executable_path来查找依赖项:@loader_path始终解析为需要加载库的模块(即库或可执行文件)的路径,因此始终可以找到递归依赖项。
从Mac Os 10.5开始提供 有关详细信息,请参阅“man dyld”。
另一个选项是dlopen
在主库之前的依赖关系。