Qt QCoreApplication addLibraryPath use - c++

I've been having troubles with the QCoreApplication::addLibraryPath(QString &Path) method on windows.
I've trying to use it to add directories where the application should be looking for dll that i'm loading dynamically with QLibrary.
I soon enough realized that it was not the right way to go. I now use a putenv approach to change directly my environement variables.
Plus, I still don't understand what exactly the addLibraryPath method is supposed to be used for?

I think qt documentation is not clear enough, regarding this topic.
There are (at least) 2 sorts of libs/dlls:
Essential Libs/Dlls das are already needed at program start (like Qt5core.dll).
"Functionality Libs" like the Qt Plugins and third party stuff, that can be loaded later.
It is not obvious (at least for me) which DLL is of sort 1 or sort 2. This leads to the problem that it may be nasty to find out which you can move into subfolders and point your application to it by addLibraryPath().
For me the following solution worked:
use windeploy to find out the bigger part of dependencies (my app's executable is in a "bin" folder below the project folder)
c:\Qt\Qt5.3.2\5.3\mingw482_32\bin\windeployqt.exe ..\bin\myapp.exe --release --force --compiler-runtime -libdir ..\bin -dir ..\bin\plugins
this puts the "sort 1" libs into the app folder
and the "sort 2" libs into a subfolder plugins
Additionally, it is needed to let the installer set an environment var "QT_PLUGIN_PATH" in registry to let the app find the plugins. I wasted hours just to find out that setting this path with addLibraryPath() at runtime is just not working. Also a qt.conf file seems not to work. The only alternative for me is setting a environment var in a .bat file, what is essentially the same like the registry setting.
Here's the registry key (in inno setup syntax):
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; ValueName: "QT_PLUGIN_PATH"; ValueData: "lib"
Another anoying thing is, that some libs are not identified by windeploy. These are mainly the compiler redistributables, that will vary with the compiler that you use. Others are more depending on the functions that you use, and somehow are not processed by windeploy. This fact is not documented obviously (at least I didn't see it) and is also not easy to understand. For my app, these are the following compiler redists and some database related libs:
libeay32.dll
libgcc_s_dw2-1.dll
libintl.dll
libpq.dll
libstdc++-6.dll
libwinpthread-1.dl
l
Dependency Walker is always said as a solution for finding this out. For me that didn't work either. Not all of the mentioned libs were listed, but the app isn't running without. Maybe it's because the libs are just loaded under special circumstances?

addLibraryPath adds a path to the ones that the application will search when dynamically loading libraries.
From the Qt documentation about QCoreApplication::​libraryPaths() :
This list will include the installation directory for plugins if it
exists (the default installation directory for plugins is
INSTALL/plugins, where INSTALL is the directory where Qt was
installed). The directory of the application executable (NOT the
working directory) is always added, as well as the colon separated
entries of the QT_PLUGIN_PATH environment variable.
Also it's stated in the Qt documentation that :
An application has an applicationDirPath() and an
applicationFilePath(). Library paths (see QLibrary) can be retrieved
with libraryPaths() and manipulated by setLibraryPaths(),
addLibraryPath(), and removeLibraryPath().
So it seems you can add the path for QLibrary with addLibraryPath.

Related

My project can't find its libraries when run manually from the terminal

I'm creating a library for the first time. So far it's working from the IDE (Qt Creator), but not from the terminal when I run its testing program manually.
There are two parts to my project, the library, and the sandbox for testing it. I've created a project in Qt Creator that includes two subprojects (one to build the lib, and one to build the tester) and both compile without errors. When I run the sandbox from the IDE the library is dynamically linked to the sandbox, the function greeting() is loaded in from it, then called, and prints "Welcome to the library!" to std::cout. However, if I open the build folder in the terminal and run the sandbox directly using ./sandbox I get:
./sandbox: error while loading shared libraries: libengine.so.1: cannot open shared object file: No such file or directory
I took this to mean that I needed to properly install my custom library, libengine.so.1. When I looked up how to do that I found that I just needed to copy the library files in to either, /usr/lib or /usr/local/lib, but neither of those worked and I'm still getting the above error. In the past, that simple solution did work for me when compiling a 3rd party library (SDL, I think) and I don't know what I'm missing that would mean it wouldn't work now. So far I haven't yet found any more detailed information and I don't know what I'm doing wrong or have missed.
How do I make my sandbox program see its companion library when I run it directly from the command line?
NOTE: I'm specifically asking about Linux/Ubuntu. If I later run into problems under Windows I'll be back. :-)
Short Answer
I ran in to multiple problems all at once.
First problem: Broken symbolic links (they're like shortcuts in Windows).
Second: My lib needed to be copied in to a different system directory than is generally recommended.
Third: Qt Creator and QMake made passing custom linker options difficult.
The Details
When Qt Creator compiles my library it automatically creates three symbolic links to it with different layouts of the version numbers.
> ll
lib-engine.so -> lib-engine.so.0.1.0
lib-engine.so.0 -> lib-engine.so.0.1.0
lib-engine.so.0.1 -> lib-engine.so.0.1.0
lib-engine.so.0.1.0 (original library file)
For some reason (I don't know why) each time I moved the links in to a system directory like usr/local/lib the links would break. I didn't notice this at first, or even think to check, because that's never happened to me before. Moving a link has always worked in the past. To get around this I just manually created the links within the directories they would reside in.
Broken links aside, putting the library in to usr/local/lib still didn't work, but usr/lib and /usr/lib/x86_64-linux-gnu (recommended in the blog linked below) did work!
Those fixes actually came after a different fix I looked in to after reading this blog and this article it linked to.
There it said to add -Wl,-rpath,'$ORIGIN/lib' to the gcc build options to embed a library search path in to the application itself. This set of options would allow me to put my library files where ever I wanted (specifically, in a directory called /lib in the application's working directory).
Unfortunately, that had two problems of its own. First, Qt Creator doesn't (from what I can tell) allow you to specify custom build options for individual subprojects through the GUI, so I had to figure out how to add linker options using the project file, assuming that was possible, which it was.
Second, QMake messed up the gcc options, embedding in to my application Library rpath: [RIGIN/lib] instead of Library rpath: [lib] like it's supposed to.
In the end, changing the proposed linker options of...
-Wl,-rpath,'$ORIGIN/lib'
... to the following QMake project file line...
QMAKE_LFLAGS += -Wl,-rpath,'lib'
... work out nicely. Using both fixes I can now either install my library on my system or put it in to a /lib folder and the program will run.

Set a predefined working directory when building a program in MacOSX

Recently I encountered this documentation about Apple and the loading of dynamic libraries.
Citing:
When the library name is a filename (that is, when it doesn’t include directory names), the dynamic loader searches for the library in several locations until it finds it, in the following order:
$LD_LIBRARY_PATH
$DYLD_LIBRARY_PATH
The process’s working directory
$DYLD_FALLBACK_LIBRARY_PATH
And my concern is about the third step "The process’s working directory".
Since I load libraries (and libraries that I load will load others), I would like to force the working directory to be some predefined path.
At the beginning of the main is already too late for me.
Do you know if there is some build option that I can set in pkgbuild, or in some .plist file?
Do you know a workaround for that?
EDIT:
I found these keys that could be set, in particular see LSEnvironment.
I was thinking maybe some 'hack' like
$DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$DYLD_FALLBACK_LIBRARY_PATH
(yes, I know that it is ugly...). But it would not work anyway, because citing the previous link:
These environment variables are set only for apps launched through Launch Services. If you run your executable directly from the command line, these environment variables are not set.
So, what can I do if someone calls my executable directly?
Are the .plist files considered at all in case the executable is called directly?

Is it possible to edit the hardcoded path in a Windows (custom built) installation of Qt 5?

We are building Qt 5.10 internally, and installing it to a given prefix on the build environments.
We would like to be able to relocate the installation (notably, but not only for, distribution). We are aware of qt.conf, as pointed out by this answer.
Yet, is there a maintained way to directly edit the values of those hardcoded paths in the installed files?
EDIT:
More rationale behind why we thing qt.conf is inferior to directly patching the binaries.
On development machines, it means that instead of simply patching the installed binaries once, we have to provide a configuration file in each folder containing an application depending on Qt.
Even worse than that, we discovered through failures (and the help of this post) that qtwebengineprocess.exe, in qtprefix/bin, expects its own qt.conf file, otherwise it will use the paths hardcoded in the libraries. This means that we have to touch the the library folder anyway, in otder to edit the configuration file to make it match the folder location on each development machine.

How to set library's path for q custom Qt application

I am running in situation where I have two different versions of Qt installed, the compiled with mingw one, and the other with visual studio.
Now, When I compile my program with Qt MinGW version and run it, I got a message have scrambled text, saying that one of essential Qt modules not loaded.
My question is, how I can set the path to Qt essential modules for my application with C++. I looked at documentation and found addLibraryPath method but it seems like for Qt plugins only.
Edit
It seems I misunderstood the question, as SIFE comment that he needs to load Qt modules (like QtGui4.dll), not plugins. The answer for plugins is left here, in case it might help someone.
Plugins
Qt loads plugins that are in the SDK/plugins by default. The problem is, it finds the wrong SDK first...
If I remember right, Qt first search in the directory .. So you can copy the 'plugins' directory near your *.exe : plugins for msvc copied near the msvc-compiled exe, and plugins for gcc near gcc-compiled exe.
If you do not want to copy the plugins directory, you can use setLibraryPaths (not tested, but might work)
Last but not least, you can also use the qt.conf approach.
Modules
Modules are not dynamically loaded, in the sense that they're part of the dependencies of the application, so they are loaded at exe startup, and not via LoadLibrary. So, the solution is simple: just copy the dlls in the same folder than the one containing the *.exe
Concerning compiler, the proper library/include settings should be done by QMake.
QMake creates your makefile/VS-Project using the libraries found in the same Version Qmake belongs to.
Try calling QMake using the complete path explicitely for each Qt-Version
e.g.
c:/myQtMinGwProject>c:/Qt4_mingw/bin/qmake
c:/myQtVSProject>c:/Qt4_VS2008/bin/qmake -t vcapp
Concerning run-time, make sure the dlls for corresponding version are in PATH
I hope it helps

How would I inform an isolated application of the location of dependent DLLs?

I have a couple of isolated applications that I am writing that all rely on dlls that are also written by myself and team. Things were fine when we only had a few dlls but not the build output directory is getting rather cluttered and hard to navigate. I would ultimately like to have the output build directory contain the following structure:
$(OutDir)
--(Application.exe)
--(Application.exe)
--Libs Folder
--(LibA.dll)
--(LibB.dll)
(etc)
Is there a way to have the applications look in the "Libs Folder" for these libraries at runtime using something like the manifest files?
Dynamic-Link Library Search Order describes what possibiites you have to modify the search path. It describes the search order and mentions manifests and the SetDllDirectory() function as possibilities of changing the search order.
While SetDllDirectory looks promising, it only will reliably work if you dynamically load your DLLs, which you don't do from what I understand.
Now, as to using manifests: Application Configuration Files talks about a privatePath attribute that can be used to [specify] the relative paths of subdirectories of the application's base directory that might contain assemblies. It sound to me as if it's only supposed to work for side-by-side assemblies but you may want to give it a try.
I will readily admit I have never bothered with manifests (except for what you need to know in VS 2005 to get anything running at all) and I would recommend to skip the idea of the library subdirectories for implicitly loaded DLLs and put them in the app directory and be done with it. For explicitly (dynamically) loaded DLLs, you can just deduce their full path from your executable path and supply that to LoadLibrary() and don't need to bother with the search path either.