In the project I am working on, we provide the possibility to dynamically load additional features. For that we use dlopen.
To find this libraries we have something we call module path. There we have a default path, where the shared libraries are (a lot of them are shipped).
At the moment we have two default paths: we first look in the build directory for the shared library and afterwards in the install directory. This is because it should also be possible to run the application without installing it (so in that case it needs to look first in the build directory).
Now the problem ist, if a user builds the application from source and installs it with make install, the libraries in her build directory are loaded by default. This will result in a crash. So it only works if the user afterwards removes or renames the build directory.
No the question: is there a trick (either by C++ or by the build system) to know whether the application is installed or not. The problem is, that the functionality is implemented in a shared library and the implemented way to search for modules has to work also for other applications that link against our library (so we can not rely on the path of the executable). We use CMake as a build system.
To make the situation even harder, the solution has to work on Windows, Linux and Mac OS X.
EDIT:
I further investigated and the problem is more complicated. This is the situation:
There is a small executable a
Furthermore there is a "main" library main.so
then there is a dynamically loaded library lib.so
lib.so links against main.so
The problem is, that lib.so has the absolute path to main.so in the build directory in its rpath. Thanks to the tip of #MSalters I now was able to make a hack to make sure to load the correct version of lib.so (the one in the install directory) but since it has the build path in the rpath it loads the wrong main.so (so in fact there are two copies of main.so in the memory - this messes things up).
Is there a way to remove this reference to the build path from the library? I tried all options of cmake related to rpath without success
Can't you check where the executable itself is? If it's in the build directories, use build libraries -- if it's in the install, use install?
getcwd() has equivalents on all of those platforms, but it might not be what you want -- it depends on how you run the executable.
To get the process's location is system specific, I think, but it shouldn't be too hard to wrap that.
The installed version should not have the build directory in the rpath.
You might want to do the linking twice (once for the build version and once for the installed version). Usually, on *nix systems, the installed binary has some static path where it tries to find plugins. You might define some environment variable (or command-line argument) to overload it for the build execution (and use a wrapper script to set it in the build environment).
Check how it is solved by some projects (Firefox for example).
I don't know much about windows system but I think the standard way of doing this is to search plugins in the same directory as the executable.
Related
I'm developing a shared library, and on my machine there could be two copies of the same shared library:
the one I installed to the system path: /usr/lib/libmyproject.so
the one I built in my workspace during my development: /home/ziqi.liu/workspace/myproject/build/src/libmyproject.so
So during my development, there're some executables under /home/ziqi.liu/workspace/myproject/build. I want them to use the dynamic library in /home/ziqi.liu/workspace/myproject/build/src/libmyproject.so, however it turns out that they're actually using /usr/lib/libmyproject.so when I use ldd to check the link library.
Is there anyway to specify which dynamic library to use when there are multiple? It would be better if I can specify this for all executables under "this project", since it's very intuitive to link the dynamic library in the same repo I just built, instead of the one installed to the system path.
UPDATED:
I've found this post: Where do executables look for shared objects at runtime?
It seems that the dynamic library searching has something to do with
the rpath and LD_LIBRARY_PATH environment variables.
What I want is to search for rpath first, and then LD_LIBRARY_PATH.
According to rpath wiki, the rpath is named DT_RPATH, however when I objdump that executable, the only thing I can find is RUNPATH section. I'm not sure if this is a compiler-specific behavior... (I'm running g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0)
Is there anyway to specify which dynamic library to use when there are multiple?
The best way to achieve this is to use the special $ORIGIN tag in the executable.
Assuming you have $D/build/exe and you want that exe to use $D/build/src/libmyproject.so, link your exe with: -rpath '$ORIGIN/src'.
This would allow you to have several build directories (e.g. "release" and "debug" builds), and each binary will pick up the library from its own build tree.
It would also allow you to not install libmyproject.so into /usr/lib at all -- you can keep the binary and the all the required libraries in e.g. /usr/local/$project/{bin/exe,lib/libmyproject.so} and have it all just work(TM).
See also this answer.
Just modify LD_LIBRARY_PATH and put your home folder first, like
export LD_LIBRARY_PATH=/home/ziqi.liu/workspace/myproject/build/src/:${LD_LIBRARY_PATH}
Then it should be fine.
I have an issue where I'm developing on one system where Boost is installed on:
/usr/include
/usr/lib
On a system I will deploy this on, the libboost libraries are at:
/nfs/mount/boost
/nfs/mount/lib
And I can't go about changing every system I deploy on to install libboost in the same place.
Is there a way to either:
include libboost as part of the binary executable such that loading from the system lib paths is not needed.
make the executable search for different directories when trying to load to libboost?
I'm using g++ 8
Sounds like you need a more sophisticated build environment.
I'm not sure what you mean here:
include libboost as part of the binary executable such that linking is not needed
Linking is not something you can skip. If you are trying to avoid distributing .dll/.so files with your executable, you need to avoid using the portions of the boost library that require compilation of the boost binaries (i.e. those not listed here https://www.boost.org/doc/libs/1_62_0/more/getting_started/windows.html#header-only-libraries).
Of course, that is not often the case. So...
make the executable search for different directories when trying to link to libboost?
This will never work reliably as you scale and is a nightmare in the CI world. This is where package managers such as conan (https://conan.io/) come to save the day. Delegating the package management to a third-party is the most reliable way of getting your code to build across multiple environments/platforms.
Also, building your executable and distributing it are separate operations. Any dynamically linked libraries will need to be discoverable on the system path at runtime.
Context: I have built a c++ executable using Qt 5.13.1 on an OpenSUSE platform (some Linux distribution).
I have to install it on a platform that already have an old Qt version installed and I can't get rid of it.
So I have installed the proper version of the needed Qt shared libraries (plus the platforms plugins) at a custom location and set up a qt.conf file that will specify the library path to use (same thing for the plugin path).
My own Qt installation folder contains:
A lib/ directory which contains the libraries to use.
A plugins/ directory which contains the platforms/ plugin folder.
The qt.conf file is installed alongside my executable and is filled as follows:
[Paths]
Prefix = relative_path/from/executable_location/to/install_dir/
I don't need to specify the lib/ and plugins/ directories in the entries Libraries and Plugins because they are defaulted at these values.
But even if I set them explicitly, it changes nothing.
I also tried with absolute paths but it changes nothing too.
Issue: The issue I encounter is that my executable does not load the libraries, neither find the platforms plugins, despite the qt.conf file is successfully loaded.
I have displayed the output of the following instructions:
QLibraryInfo::location(QLibraryInfo::PrefixPath);
QLibraryInfo::location(QLibraryInfo::LibrariesPath);
QLibraryInfo::location(QLibraryInfo::PluginsPath);
And they contains what's I specified in my qt.conf file. So the issue does not come from here.
Question: I have checked that QLibraryInfo field members had been properly initialized but it seems that my QApplication instance just ignore it.
How to make the QLibraryInfo configuration to be applied by the QApplication instance ?
I know that there exist a QCoreApplication::addLibraryPath() member than could be used to load libraries but I can't find anything alike for the Qt plugins as well.
But I'm pretty sure that we don't have to use this function since the information are already loaded by QLibraryInfo.
EDIT:
After some more investigations, I've found that it works fine for loading the plugins.
The problem remains the same for loading the libraries. It seems that I missed something but I cannot figure it out.
For now, I use the LD_PRELOAD environment variable in order to make it work (which is quite ugly).
EDIT 2:
I found two threads on internet about guys having the same issue:
https://forum.qt.io/topic/58499/solved-problems-with-setting-paths-to-libs-and-plugins-in-qt-app-s-executable-file
https://www.qtcentre.org/threads/32236-qt-conf-(again)-on-windows
The second one is explaining why the library load does not work.
Actually, in order to be able to parse the qt.conf file, the application needs to have the Core module loaded (libQt5Core.so.5 in my case) which makes sense (I should have thought of it).
The issue here is that libQt5Core.so.5 is one of the libraries to load (it's a vicious circle), so the executable cannot run at all.
Solution (still not load any library): It seems that I can't avoid to either load libQt5Core.so.5 with LD_PRELOAD or add it alongside the executable location.
Note: We can use LD_LIBRARY_PATH instead of LD_PRELOAD if there is no already existing Qt installation in the system "lib" directories.
I use LD_PRELOAD here because I want my Qt installation to take precedence over the already existing one (and be loaded first/instead of the system installed ones).
The problem with your libraries is that the Linux dynamic linker only searches a few standard locations, and other paths configured in /etc/ld.so.conf. One workaround is the environment variable LD_LIBRARY_PATH with the paths of your libraries. Another is the RPATH/RUNPATH values embedded in your binaries. CMake uses RPATH by default, and you can use QMAKE_RPATH in Qmake projects too. You can assemble by hand a directory with programs and libraries related using RPATH, but my advice is to create AppDir / AppImage packages using linuxdeployqt which is very similar to using the official Qt tools windeployqt and macdeployqt.
I have finally found out what was wrong.
qt.conf is parsed by Qt Core at runtime.
But the executable dependencies are loaded before the QApplication even exists. If they are not found, the program will just crash right at the beginning (dependencies loading step). And so, qt.conf will never be parsed.
In my case, I have an already existing installation of Qt in the system libraries folder. These are the ones that are found by the loader.
In this case, the dependencies are found and the programs runs (assuming there's no incompatibility between the two versions).
But even if the qt.conf is now parsed, the good version of the library will still not be loaded because the loader already has loaded the dependencies from the wrong Qt install (found at loading step).
Therefore the morality is: We cannot load executable dependencies by using qt.conf because they must be known before execution time (when the loader is looking for them).
Possible solutions:
Install the libraries in one of the folder searched by the loader (/usr/lib/ for example). If there is an already installed version of the libraries, remove it if possible, or if not, do ensure/check that you placed the proper version in a folder that will be searched first by the loader.
Use LD_LIBRARY_PATH to tell the loader where to search for libraries (if a wrong version is already installed, use LD_PRELOAD instead because LD_LIBRARY_PATH will not take precedence over what's inside /etc/ld.so.conf).
Set a rpath (which locates the proper installation directory of the libraries) when building the executable.
Add the required shared libraries in the executable directory.
(Not tested) Explicitly call the loader at application startup with the --library-path option (for example: "$ /lib/ld-linux.so.2 --library-path my_lib_path executable").
I may have missed other workarounds, this list is not guaranteed to be exhaustive.
I have a question related to how to install a built executable program with cmake when it relies on some external libraries. Suppose my executable is abc, and it relies on two external libraries: lib1.so and lib2.so. The structure of the codes are as follows:
-.........
|----bin (lib1.so lib2.so)
|----include(lib1.h lib2.h)
|----src(main.cpp)
When the executable program is installed using the following cmake commands:
INSTALL(TARGETS ${Exe_Name}
RUNTIME DESTINATION Path to bin
LIBRARY DESTINATION Path to bin)
I expect that the executable program will be in the same directory with lib1.so and lib2.so. However, when I execute the built program in the installation folder, I met the following error:
error while loading shared libraries: lib1 can not open shared object file No such file or directory
If I use ldd to check the executable, I found lib1.so and lib2.so not found. After searching for possible solutions, I found if I call the executable in this way, then it worked:
LD_LIBRARY_PATH=./ ./my_program_run
Then my question is how I can let my executable program knows the locations of the shared libraries with cmake when it is installed? Thanks.
This is best solved this with the RPATH of the final executable. RPATH is a hardcoded search path for the executable itself, and allows the use of the string $ORIGIN, which expands to the location of the executable at runtime. See this reference: http://man7.org/linux/man-pages/man8/ld.so.8.html
CMake strips the rpath of a binary at installation time, to avoid the binary picking up libraries littered around your development tree. But it also provides a simple way to modify the installation rpath for exactly this reason. Here's the short answer:
IF(UNIX)
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:\$ORIGIN/../bin:\$ORIGIN")
ENDIF()
This particular example appends to the existing rpath, and adds . and ../bin to the search path, all relative to the location of the binary.
Some developers claim that adjusting the RPATH of the binary is not a good idea. In the ideal world, all the libraries would live in the system library directories. But if you take this to the extreme, you end up with Windows (at least the older ones), where c:\windows\system32 is full of junk that came from who knows where, and may or may not conflict with other software, etc. Using rpath and installing everything in one place seems like a great solution.
If the application is to be cleanly installed to a standard linux distribution, then you should either install the supporting shared libraries into a standard location (/usr/lib), or you should add the libraries location to the ld.so config, by create an /etc/ld.so.conf.d/myprogram.conf file containing the name of the directory the libraries are in.
If the installation is temporary or more ad-hoc, then a script to set the LD_LIBRARY_PATH is suitable.
The libraries are searched in the predefined locations which includes standard library paths configured with ld.so.conf and LD_LIBRARY_PATH. You can also try to compile your app with -rpath, but it is not recommended by some developers. I suggest you to create a wrapper script which will set LD_LIBRARY_PATH and run the real application like that:
"theapp" script:
#!/bin/sh
dir="`dirname \"$0\"`"
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}"$dir"
exec "$dir/theapp.real" # your real application
The application, script and libraries should be in the same location (under bin/).
I'm wondering how to "package" a C++ project for release. It uses various libraries, and I don't want a user to have to go through the same setup I did, with putting the right files in the right place and such. I had difficulty researching this, because I'm not sure the technical term for this issue. If I'm using command line compiling on Linux, is there an easy way to do this?
Your approach to this will differ on Windows and Linux because each OS handles this a different way. I'm more familiar with Linux so I'll restrict my answer to just the Linux side of things.
When you link your executable with a library using -l flag the linker defaults to looking in the normal system library directories so there are four approaches here.
Require the user to properly install the libraries themselves. However, it sounds like you don't want to do that.
Have the user add the library location to LD_LIBRARY_PATH variable.
Your third option is force the linker to look in a certain path for the libraries using the -rpath flag. For example, to have the application look in its working directory for a shared library you can compile with: g++ -rpath ./ -l SomeLib -o MyApp myapp.cpp
One other option is to static link your code with their library that way you only have to distribute one executable. If a static library exists you can use g++ -static -l SomeLib -o MyApp myapp.cpp to tell gcc to link statically.
On windows I would recommand wix http://wix.sourceforge.net/ to create the .msi installer
I would like to point out, the lookup path for .dlls I recommand putting all .dll in the same folder as your .exe since this has the highest priority
However, the vc crt (the c/c++ runtime library) should be installed using the redistributional package from microsoft -> updates automatically http://www.microsoft.com/de-de/download/details.aspx?id=5555
Wix can include the redistributional package into the same .msi therefore you have only to deploy a single installer file.
You mean an installer?
On Windows the program that you run to install a new app which outs everything in the correct directory, creates the start menu and lets you un-install it?
There is an installer builder in Visual Studio (might not be in the free express version) which makes .msi installer files. It's fairly easy to use for simple tasks but becomes complicated to do anything more.
Alternatively, to create traditional setup.exe type installs I use the excellent free Innosetup
On linux you would generally create a package using whatever format your distribution uses (.deb / .rpm ). There are lots of instructions on the specifics of each one and the tools to do so will probably already be installed in your Linux system