Delayed (dynamic) loading of framework(or dylib) on Mac - macos

I'm trying to load a framework (or dylib) on mac where I know the path only at runtime.
Windows solution:
Link library with /DELAYLOAD
Just before a function from the library is used, change the current directory in the program to the directory where the dll resides
Call some function from this library. The dll is loaded from the current directory
On mac, I can use weak linking to make the application startup without the library being available yet. However, as soon as some function from the library is needed, I get "image not found", and the application is aborted.
How can I tell the Mac dynamic linker during runtime where to look for the library? "dlopen" does not work, since it only loads the library and does not resolve the symbols. Setting rpath to "." (the current directory) and changing the current directory does not work. Setting typical environment variables (DYLD_LIBRARY_PATH) only works when done before running the executable, not during runtime.
Any other ideas?

Write a wrapper script or executable that discovers the path at runtime, add the path to DYLD_LIBRARY_PATH, then calls execve to the real executable.

Use dlopen() to open the library and then dlsym() to find the symbols. If you are relying on the dynamic linker, you must know the path in advance and set it either via the rpath or with environment variables. The rpath can take relative paths, so that may work for you... but most likely, dlopen() and friends is the best solution here (although it may take some work to convert to using function pointers).
The advantage of dlopen() etc, is the same (or similar) code will work on other *nix's.
You can also look at NSAddImage(), which is OSX specific but should also do what you want.

Related

Using dynamic library

When I would like to compile a program which uses a dynamic library, do I have to install (i.e. copy to a specific place, say, /usr/share/lib) this library? Or is it ok, if I put this library to any place somewhere and later during linking I point the linker to it, e.g. '-L ./thelibfolder'?
do I have to install (i.e. copy to a specific place, say, /usr/share/lib) this library?
No.
For a UNIX shared library, you need to arrange for two things:
You have to make the library known to the static linker, while linking main executable. Usually this is achieved by adding -L/path/to/directory -lfoo link flags to the link line.
You have to make runtime loader search /path/to/directory as well. This is system-specific. On many systems, setting LD_LIBRARY_PATH environment variable achieves the desired result, though this is usually not the preferred method. Another method is to encode this path into the application itself, e.g. on Linux one would add -Wl,-rpath=/path/to/directory to the application link line.

Is there any way to simulate LD_LIBRARY_PATH in Windows?

I have a program do so some graphics. When I run it interactively, I want it to use OpenGL from the system to provide hardware accelerated graphics. When I run it in batch, I want to be able to redirect it to use the Mesa GL library so that I can use OSMesa functionality to render to an offscreen buffer. The OSMesa functionality is enabled by doing a LoadLibrary/GetProcAddress if the batch start up option is selected.
On Linux, its fairly easy to make this work. By using a wrapper script to invoke the program, I can do something like this:
if [ "$OPTION" = "batch" ]; then
export LD_LIBRARY_PATH=$PATHTO/mesalibs:$LD_LIBRARY_PATH
fi
It is possible to do something this in Windows?
When I try adding a directory to the PATH variable, the program continues to go to the system opengl32.dll. The only way I can get the program to use the Mesa GL/OSMesa shared libraries is to have them reside in the same directory as my program. However, when I do that, the program will never use the system opengl32.dll.
If I've understood what you're saying correctly, the wrong version of opengl32.dll is being loaded when your process starts up, i.e., load-time dynamic linking. There is probably no good way to solve your problem without changing this.
You say you can't use conveniently use run-time dynamic linking (LoadLibrary/GetProcAddress) for opengl32.dll because the calls to it are coming from the Qt library. I presume that the Qt library is itself dynamically linked, however, so you should be able to solve your problem by using run-time linking for it. In this scenario, provided you load opengl32.dll before you load the Qt library, you should be able to explicitly choose which version of opengl32.dll you want to load.
You might want to consider using delayed loading in order to simplify the process of moving from load-time to run-time linking. In this scenario, the first call into the Qt library causes it to be loaded automatically, and you'll just need to explicitly load opengl32.dll first.
There are a few ways you could handle this, depending on the libraries and their names/locations:
If both have the same name (opengl32.dll), then you need to add the Mesa DLL location to the search path such that it is searched before the system directory. The order directories are checked in is detailed here. As you can see, $PATH comes last, after system, so you can't just add the directory to that. However, you can make use of the second step ("The current directory") by setting the working directory to a path containing the mesa files. Generally this means starting the application using an absolute path while in the directory containing the files.
That's still not particularly pleasant, though. If you can, you should use LoadLibrary and check for an environment variable (OPENGL_LIBRARY_PATH) when your app starts up. Assuming the exports from opengl32.dll and Mesa's DLL are the same, you can do something like:
void LoadExports()
{
char location[MAX_PATH];
getenv("OPENGL_LIBRARY_PATH", location);
HMODULE oglLib = LoadLibrary(location);
function1 = GetProcAddress(oglLib, "glVertex2f");
...
}
This will work perfectly fine, doing almost exactly what you want.
However, if you want to do that, you can't import opengl32.dll, which you're probably doing, you have to dynamically link throughout. Make sure not to link against opengl32.lib and you should be fine. Depending on how many functions you use, it may be a pain to set up, but the code can easily be scripted and only needs done once, you can also use static variables to cache the results for the lifetime of the program. It's also possible to use different function names for different libraries, although that takes a bit more logic, so I'll leave the details to you.
Though this should be possible in the cmd window, it seems you're having no luck.
Try: set a variable in your script (RUNNING_IN_SCRIPT=Y) and then parse for that variable in your executable and LoadLibrary from the absolute path of installation - be sure to clear the variable when you exit.
Windows used to search different paths for dynamic libraries, but due to security consideration, the system path is searched first.
You could, however use Delay Load Imports to get a workaround:
If you're using MSVC, you could single-out the DLLs you're interested in loading on your own with /DELAYIMPORT flag to the linker.
Then, override the delay load helper function and use LoadLibrary to find the proper DLL (and not trust it to the system).
After loading the correct DLL, have your helper function just call the original one that will do all the GetProcAddress business by itself.

How can I install a DYLD loader command that is not explicitly supported by ld?

On Mac OS X, binary executables in the DYLD format contain "loader commands" that instruct the library loading system how to handle the contents of the file. In particular, the loader command instruct the system where dependent libraries should be searched for, etc.
You can see the complete list of loader commands for any binary on your system by running "otool -l /path/to/your/app".
Generally speaking these loader commands are set by the "ld" tool during the link phase of a project's compilation.
My question is, what do I need to do to add loader commands for publicized types that are not supported (apparently) by ld?
In particular, I would like to take advantage of the LC_DYLD_ENVIRONMENT loader commmand, which can be used to specify a string in the loader commands table of a binary that should be loaded and evaluated as environment variable settings in the context of the executable.
I don't see any argument to ld that would facilitate this. Something like "-sectcreate" but for specifically adding to the content of the loader commands, is what I'm after.
I know this is possible because at least one standard app on Mac OS X uses it: Safari. But I don't know whether they achieve this by some kind of post-link massage of the binary, if they're using a custom version of ld that knows how to build and chain the custom loader command in, or if they are exploiting a general-purpopse feature of the ld command that I haven't been able to figure out.
It looks like you can use -dyld_env, like so: "-dyld_env DYLD_FRAMEWORK_PATH=/". This isn't documented in the man page, but can be found in ld64's Options.cpp and mentioned in the Changelog file. If you're trying to do it from Xcode, you'll probably have to do it like this: "-Xlinker -dyld_env -Xlinker DYLD_FRAMEWORK_PATH=/".
One thing to note: if you look at dyld's dyld.cpp, you'll see that it only allows environment variables that start with DYLD_ and ends with _PATH.
If your executable is structured as part of a standard OS X application bundle (i.e. a .app that can be launched by a user), the conventional way to specify application specific environment variables is through its plist file using the LSEnvironment key. See here for more information.

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

How do I force Xcode to link to a custom version of a system framework?

I have a project that uses OpenAL. The project is built against the 10.5 SDK, and the version of the OpenAL.framework in 10.5 causes some problems. I want to link to a custom-built version of the OpenAL.framework that resides in my source tree.
However, Xcode resolutely refuses to do this. No matter what I try, it insists on linking to the framework located at /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/OpenAL.framework/OpenAL. Here are a couple of things I've tried without success:
Set the path to the framework directory in a variety of ways (relative, absolute) using -F.
Pass the linker the -Z flag to eliminate default link paths, then explicitly pass /System/Library further on in the link process, to ensure that it sees the system paths after my custom library path.
Build my library using a prelinking pass, and explicitly pass the library inside the framework to THAT.
According to man gcc, passing the -F parameter should be sufficient to ensure that a link path is searched before the default paths. Either this isn't happening correctly or I'm misunderstanding the problem, and it seems too simple and obvious to be a linker problem :-)

Resources