[Solved]How can I properly force my Qt Application to loads shared libraries from Certain Directory when it loads?
-
I made my QtApplication (name: QtProjectWork ) in Qt5.2.1 and I compiled the binaries for 64 bit GCC running on LinuxMint.
In my application I have used number of features such as CommandLineParser that are only avaliable on Qt > 5.2.0In my programming environment I have installed the QtCreator and I have no problem in compiling and running the application and the required Qt shared libraries are directly loaded from the Qt5.2.1 installation path directory.
so running following command returns:
$ ldd QtProjectWork_libQt5Network.so.5 => /opt/Qt/5.2.1/gcc_64/lib/libQt5Network.so.5 (0x00007ff2a78f5000)_
libQt5Core.so.5 => /opt/Qt/5.2.1/gcc_64/lib/libQt5Core.so.5 (0x00007ff2a7227000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ff2a6fe7000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ff2a6ce4000)
....The problem that I have is since I am going to deploy the code on other LinuxSystem which has no QtCreator
installed and the user does not have enough privileges to update or install the libraries so once I hand out the code
to the user I have to include the shared libraries with the executables.So I made a "Qtlibs" directory inside the QtProjectWork binary directory and put all the required libraries inside Qtlibs directory with their respective symbolic links (using ln -s and relative path) , so the Qtlibs contents are as follow:
lrwxrwxrwx 1 btgarden btgarden 19 apr 1 10:43 libQt5Core.so -> libQt5Core.so.5.2.1
lrwxrwxrwx 1 btgarden btgarden 19 apr 1 10:55 libQt5Core.so.5 -> libQt5Core.so.5.2.1
-rwxr-xr-x 1 btgarden btgarden 5030256 mar 31 13:34 libQt5Core.so.5.2.1
lrwxrwxrwx 1 btgarden btgarden 19 apr 1 10:43 libQt5DBus.so -> libQt5DBus.so.5.2.1
lrwxrwxrwx 1 btgarden btgarden 19 apr 1 10:56 libQt5DBus.so.5 -> libQt5DBus.so.5.2.1
-rwxr-xr-x 1 btgarden btgarden 534744 feb 4 15:30 libQt5DBus.so.5.2.1
lrwxrwxrwx 1 btgarden btgarden 22 apr 1 10:43 libQt5Network.so -> libQt5Network.so.5.2.1
lrwxrwxrwx 1 btgarden btgarden 22 apr 1 10:56 libQt5Network.so.5 -> libQt5Network.so.5.2.1
-rwxr-xr-x 1 btgarden btgarden 1391448 feb 4 15:30 libQt5Network.so.5.2.1In order to force the application to firstly load the shared libraries from the Qtlib directory I added following lines to very beginning of my application main.cpp:
[Note:some part of the code is taken from http://stackoverflow.com/questions/20398461/deployment-of-qt-apps-under-linux]@int main(int argc, char *argv[])
{setlocale(LC_ALL,"C"); QCoreApplication a(argc, argv); // Fixing LIBRARY PATH in LINUX QString appFilePath = QCoreApplication::applicationFilePath(); QStringList paths = QCoreApplication::libraryPaths(); QCoreApplication::addLibraryPath(QString("%1/%2").arg(appFilePath).arg("Qtlibs")); paths = QCoreApplication::libraryPaths(); // Ensures first path to search is in $APP_PATH/Qtlibs QCoreApplication::setLibraryPaths(paths);// refreshing library paths if needed ! @
But this approach does not work and when I execute the $ ldd QtProjectWork I get same result as before.
It does not load shared libraries from Qtlibs directory :-( .I have read different websites regarding shared libraries workarounds, and on has suggested to use a shell script (in linux) and "export LD_CONFIG_PATH=. " which I rather not to use it (due to my multi-platform approach).
I do not know if I have to use a.setLibraryPaths(paths) instead of (static method) QCoreApplication::setLibraryPaths(paths) !? or how can I solve the problem.
Thanks in Advance -
setLibraryPaths() will not solve your problem. That method changes default lib paths for libraries loaded after your application starts (plugins, or stuff loaded with QLibrary).
But Qt libraries (and all other DLLs) are required before the application starts, and are being loaded by your OS. So, that part is handled by the operating system and you have no control over it in your application.
The solution is indeed to use a shell script with LD_LIBRARY_PATH or similar approaches. I know you would rather not do that, but your other possibility in this case is not to distribute your application at all ;)
-
I even tried following shell script and I took out those lines of code
which sets the library path.Then I made following shell script and I checked it that in fact it did not made any changes.
@#!/bin/bash
export LD_LIBRARY_PATH="pwd
/Qtlibs"
echo ${LD_LIBRARY_PATH}
ldd ./QtProjectWork $*
@
So still the libraries are downloaded from the opt/Qt/.... directory.
I am wondering if I can set any variable in .pro file to solve the problem.Otherwise I have to compile the code and use it as static library (that I do not know how?).
In fact in Linux Mint/Ubunutu LD_LIBRARY_PATH is not defined !?.
I checked /etc/ld.so.conf.d contents which stores the library paths and I could not find and PATH which points /opt/Qt/5.2.1/..... libraries path that was strange (where the Qt libraries paths are defined ?) and how the system looks for it.
If none of the solution works I have no other alternatives to compile it as static that I have to figure out how :-( -
LD_LIBRARY_PATH is always empty: this is exactly so that you can set it yourself in your scripts :) I definitely use it on Kubuntu and it works. You can also check the bin dir of Qt Creator: they are using the same trick.
If you want to be sure, rename your Qt folder to /opt/Qt-blahblabhblah and then try to run your application with and without the script.
-
"Here":http://www.tripleboot.org/?p=138 you can find great blog about solving this issue from "hskoglund":https://qt-project.org/member/131157 .
-
Thanks qxoz,
I think the chrpath command that I have to use does not need to be installed on the user's machine (please note that user can not install anything) but I can apply on the binaries in advance [I guess the chrpath changed the binary contents and I do not need to change LD_LIBRARY_PATH in script file?] but I can not figure out how can I change the $ORIGIN to something like ./Qtlibs since I want the libraries reside in one directory after the executable not the same directory that the executable is. -
Unfortunately i am more windows user and i am afraid can't give you useful advice :( .
By the way "Qt SDK":https://qt.gitorious.org/qtsdk installer also do something like that. -
Thanks to qxoz and sierdzio I have followed the [tripleboot.com] guidelines
it seems all the problems are solved by using chrpath since it modifies the binaries and change the runtime library path.In fact I have used following command to make it work in linux :
$chrpath -r ./Qtlibs QtProjectWork
it seems that it has modified the binary (checked with md5sum) and the
ldd QtProjectWork could be used as single binary with all the Qt5 libraries installed in [EXEC_PATH]/Qtlibs ---> I got no issues with ldd on missing libraries and the issue is solved. :-) -
Thanks for sharing the solution with us, I have learned something too :)
-
Hi, just saw this thread, great that my blog is helping! I am lazy but I promise more blog posts, like, more on deployment, how to fix Qt's ODBC for Linux/Mac and how to write a QtCreator plugin.
EDIT: forgot, $chrpath -r ./Qtlibs QtProjectWork is a pretty clever idea, makes for less clutter in the app's main directory. And I should mention in the blog, you can indeed do chrpath in advance on your dev. machine.
-
Thanks hskoglund for your great blog.
I would rather to use relative paths instead of absolute due to following reasons:
1 - Different versions of an application on a single machine does not crash when there is a version mismatch between their shared libraries (which only happens if their rpath is not relative path).
2- Access privileges issues for different machines and type of users, user might not get enough privileges to copy and install shared libraries in certain path on the system.
3- Ease and comfort in replacing or upgrading libraries without disturbing other applications that are using the very same shared library, one might imagine the huge differences between libQtCore5.so symbol link if it points to different versions of actual shared libraries such as libQtCore.so.5.0.2 or libQtCore.so.5.2.1 .