overriding @executable_path in a DLL loaded with dlopen()
Asked Answered
P

2

8

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 ?

Persephone answered 22/3, 2011 at 23:12 Comment(0)
G
7

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.

Goy answered 24/3, 2011 at 12:24 Comment(0)
A
2

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 dlopening dependencies before main library.

Alton answered 7/6, 2011 at 8:58 Comment(1)
I do not maintain OtherApp (if I did, I would simply include the DLL in MyApp directly). dlopen-ing the dependencies before the main library does not work: from the point of view of dyld, @executable_path/bar.dylib and /Application/OtherApp.app/Contents/MacOS/bar.dylib are not the same file (there is no concept of "SONAME" here; the path under which the DLL was searched serves as DLL name), so dyld refuses to use the manually loaded bar.dylib (I have tried).Persephone

© 2022 - 2024 — McMap. All rights reserved.