Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

overriding @executable_path in a DLL loaded with dlopen()

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 ?

like image 986
Thomas Pornin Avatar asked Mar 22 '11 23:03

Thomas Pornin


2 Answers

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.

like image 129
Ted Mielczarek Avatar answered Nov 05 '22 00:11

Ted Mielczarek


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.

like image 41
pqnet Avatar answered Nov 04 '22 23:11

pqnet