Is there any way to simulate LD_LIBRARY_PATH in Windows?
Asked Answered
D

4

12

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.

Disembarrass answered 25/1, 2012 at 19:4 Comment(0)
V
8

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.

Verdugo answered 1/2, 2012 at 4:4 Comment(1)
The delayed loading is the key, and I also found that both opengl32.dll and glu32.dll must be set for delayed load. I set my executable to delay load opengl32.dll and glu32.dll and then put code in to call LoadLibrary on these two dlls if the program is started in batch mode. This code was inserted before the first call into the Qt library.Disembarrass
I
2

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.

Irrelevancy answered 30/1, 2012 at 13:58 Comment(6)
Yes, both have the same name, opengl32.dll. I have already tried to use the "current directory" - it does not work. The current directory comes after the system directory in the search order. I had also thought about modifying the code to do GetProcAddress, but that isn't desirable since all the OpenGL calls are coming from the Qt library. At the moment, I'm resorting to the stupid technique of having the same executable reside in different directories, with one of the directories having the Mesa libraries reside with the executable, so that they get loaded based on the dll search order.Disembarrass
There is a trick you can use, if you know for sure that your library will load before Qt (or you can make a stub that will do so): call LoadLibrary on the desired library from there, so that a loaded module with the name exists when the Qt library loads. The linker will check for opengl32.dll, and if one is already loaded, use that. Otherwise, you'll have to work with load order, and maybe check in a dependency/process trace tool what paths it's searching.Irrelevancy
Do you have more info on this "trick"? I tried to do something like this in a simple test program (as suggested already by KevinDTimm), where I did the LoadLibrary on the Mesa opengl32.dll and osmesa32.dll and then made calls to OSMesaCreateContext, OSMesaMakeCurrent, and glGetIntegerv. The test program would always grab the system opengl32.dll unless I specifically put the Mesa library in the same directory.Disembarrass
The Windows runtime linker appears, in my experience (and I'm currently using it in a released project, and it seems to be working), to rely on two basic checks: 1) the library imports another library by name, which is always relative if you linked against a standard LIB, and 2) won't reload a library if it finds a loaded library with the same path. In my case, I have plugins in multiple directories depending on Devil.dll; I load that from the main DLL using LoadLibrary("DevIL.dll") and all the plugins use that copy without reloading it from another directory.Irrelevancy
Now, the "trick" part comes in when you're doing that on an imported (start-time linked) library. The linker will load the library while loading the application, so you have to get it in before that. However you manage to do that is fair game, be it a launcher that starts the process suspended and injects the library, a shim of some sort, even replacing another library and dynamically loading yours first. I'm sure there's an easier way, which you can probably find by watching the load attempts, but this short-circuit appears reliable at least in my use case.Irrelevancy
@Irrelevancy How would you go about this if the library names were different, lets say opengl32.dll and opengl_mesa.dll?Baseman
C
0

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.

Chemush answered 25/1, 2012 at 19:8 Comment(6)
Perhaps I was being unclear - I only do a LoadLibrary for osmesa32.dll. The opengl32.dll is implicitly linked. I'm trying to find a way to substitute the system opengl32.dll with the Mesa opengl32.dll. On Linux, I can use LD_LIBRARY_PATH to do this, but on Windows, I think I'm stuck - but I'm hoping I'm not.Disembarrass
Sure, just call LoadLibrary when the variable is set to 'Y', skip that code otherwise. Note this isn't a great solution but it will workChemush
This is the part I don't understand. Lets say my script sets a variable and then launches my program in batch mode. My program starts up and automatically will load the system opengl32.dll. By the time my program gets to the part where it checks if it was started in batch mode, the system opengl32.dll has already loaded. If I now try to do a LoadLibrary("H:\\PATH\\TO\\mesa\\opengl32.dll"), how can it replace the system opengl32.dll that has already loaded?Disembarrass
load the library as the program starts, this should preclude it's need to load the system dllChemush
I'm probably not understanding you correctly. What do you mean by "load the library as the program starts"? I thought you meant to insert a LoadLibrary("H:\\PATH\\TO\\mesa\\opengl32.dll") into the program, but I tried that and it doesn't work.Disembarrass
It's been a long time since I've done windows dll's, it would appear that my mechanisms are not complete enough to do what you need to do.Chemush
S
0

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.

Sanyu answered 1/2, 2012 at 12:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.