How to build a C ++ program with loadable modules so that the application finds library module files not in the launch directory, but in a separate subdirectory? For example, the executable file requires the library file "db2.dll", which is located in the folder "libs":

Application | +-- main.exe +-- config.txt +-- libs | +-- net.dll +-- db2.dll 

This question only applies to building applications for MS-Windows OS in different compilers / assemblers (MS-VC, MinGW, CodeBlocks, etc.). Under Linux / Unix / * BSD, for such cases the compiler (linker) parameter is simply used: "-Wl, -rpath,. / Libs"

  • one
    In Unix systems, there is a special dynamic loader cache for this, and like you, I do not know. - 0andriy
  • one
    I do not know, but I am sure that everything depends on the dynamic loader and its capabilities on a specific platform. I can also imagine a version with "springboard", when a small program or script is loaded first, the goal of which is to substitute the necessary paths to libraries via variable environments or in some way (in Unix - LD_LIBRARY_PATH ). - 0andriy
  • I forgot to add that in all cases you compose the program as usual, unless, of course, there is a special "feature" for the desired behavior in the build environment itself. - 0andriy
  • one
  • @ 0andry thanks for the link, I also found similar information. I haven't been banned anywhere, and I also do not sin with laziness - just read about the basic idea and tasks of "StackOvrflow" - they are a little different from the communication on LORe. - bigov

2 answers 2

Oddly enough, the task has a solution and the libraries necessary for the application can really be put in a separate directory and without using dynamic loading of libraries using only static linking. This is done with the help of the so-called Assemblies (builds), whose support appeared in Windows XP .

In short, the technology is as follows. A manifest file is inserted into the executable file of the application, which instructs the application to use some assembly. The executable file loader reads this manifest and searches for a directory with an assembly , and among the search paths there is a directory with an executable file of the application.


Now in more detail, on an example and in details.

Let's create the simplest C ++ application:

 #include <iostream> int main(int, char*[]) { std::cout << "Hello, World!" << std::endl; } 

Being compiled using the MinGW compiler (MinGW-builds 6.3.0), this application in my case requires the files libgcc_s_sjlj-1.dll , libstdc++-6.dll and libwinpthread-1.dll . At the same time, the executable file itself imports only libstdc++-6.dll , which, in turn, imports the other two. Let's call our "assembly", for example, libs , create the directory libs in the directory with the main executable file of our application and place the three DLLs mentioned above inside it.

Next, create a manifest. The name of the manifest file must consist of the name of the assembly and have the extension .manifest , that is, in our case, libs.manifest . The contents of the file should be as follows:

 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity name="libs" version="1.0.0.0" type="win32" /> <file name="libstdc++-6.dll" /> <file name="libgcc_s_sjlj-1.dll" /> <file name="libwinpthread-1.dll" /> </assembly> 

It should be noted that although our application imports only one library, you need to register everything in the manifest, otherwise the application will not work. Thus, we have the following directory and file structure ( app.exe is the name of our application):

 β”œβ”€ app.exe └─ libs β”œβ”€ libs.manifest β”œβ”€ libgcc_s_sjlj-1.dll β”œβ”€ libstdc++-6.dll └─ libwinpthread-1.dll 

And finally, the final chord! We create the manifesto which we will implement in our application. Let it be in a file named manifest.xml :

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="libs" version="1.0.0.0" language="*" /> </dependentAssembly> </dependency> </assembly> 

The build parameters specified in this manifest should be the same as the ones we specified earlier. Now it only remains to create a resource file in which to point to our manifest.

 #include <windows.h> CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "manifest.xml" 

and link it to the application (in the case of CMake , for example, by specifying the name of the resource file in the source list).

    Alternatively, you can link the library manually during the execution of functions: LoadLibraryW, GetProcAddress, FreeLibrary.

    Example:

     #include <Windows.h> int main() { typedef void (*fn_t)(int a); HANDLE const dll = LoadLibraryW(L"libs\net.dll"); if (dll == NULL) { return EXIT_FAILURE; } fn_t fn = (fn_t)GetProcAddress(dll, "func_name"); if (fn == NULL) { FreeLibrary(dll); return EXIT_FAILURE; } fn(123); FreeLibrary(dll); return EXIT_SUCCESS; } 
    • @bigov, the answer is just about run-time linking - insolor