覆盖使用 dlopen() 加载的 DLL 中的 @executable_path
操作系统是 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
的效果?
Operating system is MacOS X, specifically 10.5 (Leopard) on a PowerPC G4, but I have the same problem on an x86 running 10.6.
I am writing an application which dynamically loads a DLL. The DLL (let's call it foo.dylib
) is part of another application, located elsewhere on the harddisk; my application finds foo.dylib
programmatically (exact emplacement may change, possibly the user designates the DLL path through a GUI from the running application itself). For instance, assume that my application is located in directory /Application/MyApp.app/Contents/MacOS
, and foo.dylib
happens to be in /Application/OtherApp.app/Contents/MacOS
. DLL loading uses dlopen()
.
Now, it turns out that foo.dylib
itself needs a bunch of other DLL, which are in the same directory, but about which I do not know anything beforehand. Each such extra DLL is registered in foo.dylib
with a path such as @executable_path/bar.dylib
. The semantics of @executable_path
are that it should be replaced by the directory in which the current process executable was found. This works great for OtherApp, not for me: when I open foo.dylib
, it tries to load bar.dylib
, and it looks for it in /Application/MyApp.app/Contents/MacOS/bar.dylib
, which is not the right directory.
A workaround is to set the DYLD_FALLBACK_LIBRARY_PATH
environment variable to /Application/OtherApp.app/Contents/MacOS
, but this must be done before launching my application (that environment variable is read only once by the dynamic linker; changing its value programmatically with setenv()
or putenv()
has no effect). This is not compatible with the dynamic discovery of the location of the foo.dylib
file.
Is there a programmatic way to override the effect of @executable_path
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
通过阅读 dyld 源(搜索 @可执行文件路径),我想说答案是明确的“否”。 @executable_path 替换为主可执行路径,该路径作为全局字符串存储在 dyld 模块中。
是的,您的怀疑是正确的,dyld 在启动时读取并保存其环境变量,因此您无法动态更改它们(您可以搜索我为 DYLD_LIBRARY_PATH 链接的同一源文件)。您可以有一个存根应用程序来设置环境变量,然后启动您的实际应用程序。 dyld 在这里没有为您提供很多解决方案,它并不是真正设计让您链接任意私有第三方库。
From reading the dyld source (search for @executable_path), I would say the answer is unequivocally "no". @executable_path is replaced with the main executable path, which is stored as a global string in the dyld module.
And yes, your suspicion is correct, dyld reads and saves its environment variables on startup, so you can't change them on the fly (you can search that same source file I linked for DYLD_LIBRARY_PATH). You could have a stub application that sets the environment variables and then launches your real application. dyld doesn't offer you many solutions here, it's not really designed to let you link in arbitrary private third-party libraries.
如果您维护OtherApp,您可以使用@loader_path而不是@executable_path来定位依赖项:@loader_path始终解析为需要加载库的模块(即库或可执行文件)的路径,因此始终会找到递归依赖项。
Mac OS 10.5 及以上版本提供此功能。
详细信息请参阅“man dyld”。
另一种选择是在主库之前
dlopen
ing依赖项。if you maintain OtherApp you could use @loader_path instead of @executable_path to locate dependencies: @loader_path always resolve to the path of the module (i.e. library or executable) which requires to load the library, so recursive dependencies are always found.
This is available from Mac Os 10.5 onwards.
See "man dyld" for detailed information.
Another option would be
dlopen
ing dependencies before main library.