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
?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With