8

操作系统是 MacOS X,特别是 PowerPC G4 上的 10.5 (Leopard),但我在运行 10.6 的 x86 上遇到了同样的问题。

我正在编写一个动态加载 DLL 的应用程序。DLL(我们称它为foo.dylib)是另一个应用程序的一部分,位于硬盘的其他位置;我的应用程序foo.dylib以编程方式找到(确切的位置可能会改变,可能用户通过 GUI 从正在运行的应用程序本身指定 DLL 路径)。例如,假设我的应用程序位于 directory 中/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

4

2 回答 2

6

通过阅读dyld 源(搜索 @executable_path),我会说答案是明确的“不”。@executable_path 替换为主可执行文件路径,该路径作为全局字符串存储在 dyld 模块中。

是的,您的怀疑是正确的,dyld 在启动时读取并保存其环境变量,因此您无法动态更改它们(您可以搜索我为 DYLD_LIBRARY_PATH 链接的同一源文件)。您可以有一个存根应用程序来设置环境变量,然后启动您的真实应用程序。dyld 在这里没有为您提供很多解决方案,它并不是真正旨在让您链接到任意私有第三方库。

于 2011-03-24T12:24:47.253 回答
2

如果您维护 OtherApp 您可以使用 @loader_path 而不是 @executable_path 来定位依赖项:@loader_path 总是解析为需要加载库的模块(即库或可执行文件)的路径,因此总是找到递归依赖项。

这从 Mac Os 10.5 开始可用。
有关详细信息,请参阅“man dyld”。

另一种选择是dlopen在主库之前添加依赖项。

于 2011-06-07T08:58:12.280 回答