How to correctly deploy a modular Qt-Application on windows? (Contains: can not display svg-files in qml)
-
Hello everyone,
The following is a deployment problem, effectively a variation of the classic "Why doesn't my QML-application display my .svg images?"
This is a pure Windows issue, probably related to the way it resolves dependencies between executable units.Exposition
I have a somewhat tricky situation with properly deploying an application on Windows 7 (but I think the question holds for other versions too). My application consists of an executable and a bunch of "modules", implemented as low-level API plugins These modules get loaded by the application when (and only if) required, so static linking is not an option. Modules and the application share a common_lib.dll.
Further the whole thing should be portable and not require any installation at all.Here is what starts to make it complicated
I require my modules to be in a separate folder. So my deployment (before calling windeployqt) looks like
- MyApplicationFolder
- myApplication.exe
- common_lib.dll
- modules
- module_ui.dll
- ...
- qml (contains a huge bunch of .qml files)
- res (contains fonts, .svg files for the UI)
The qml and res part is required by the module_ui.dll which - you guessed it - obtains a
QQmlApplicationEngine
from the main executable and handles the loading of .qml files.
These .qml files contain references to .svg files which they display.And now things start to go wrong
Now I execute windeployqt and all seems fine. (Note: Qt5Svg.dll and all its dependencies get properly deployed too.)
Executing the application works well except: The UI-module fails to load these .svg files.- Only on windows,
- Only when run directly from the explorer (i.e. not run from the qtcreator)
Insights so far
- The problem could be reproduced by setting the qtcreator to use the system environment when running the executable
- Activating
QT_DEBUG_PLUGINS
reveals that Qt5Svg never gets loaded.
2.1 However, module_ui gets loaded just fine. - Executing windeployqt a second time in the modules sub-folder with the module_ui.dll as target resolves the issue
3.1 Consequence is that I now have fully deployed Qt two times in my project
Questions
- Does the module_ui.dll inherit the search path from the executable that loads it?
- Why does this problem only seem to occur with the svg plugin and not e.g. Qt5Core?
- Are there better options to teach my "module" where it has to look for its dependency? (I checked qt.conf and batch scripts but they don't seem to do the trick.)
Thanks for any help in advance.
- MyApplicationFolder
-
Hi, I've also run into problems with windeployqt when having extra custom built .dlls as part of my app:
- Your module_ui.dll inherits the search path from the .exe for .dlls like Qt5Core.dll and Qt5Svg.dll.
- The Qt plugins like qsvg.dll are however a different story. Normal .dlls like Qt5Core.dll are loaded by Windows just like kernel32.dll etc when your app launches. The plugins are loaded much later, when the QApplication (or QCoreApplication) is constructed in main.cpp.
- When loading for example that plugin qsvg.dll , Qt tries to load it from current directory\imageformats. And if the current directory has changed from where your .exe file is to where your module_ui.dll is, that could explain why the plugin fails to load.
You could check the list of directories from where Qt tries to load its plugins by calling QCoreApplication::libraryPaths()
Also a trick I've used, is to make a dummy call in my main app to plugins that my custom .dlls need, so that plugins like your qsvg.dll (and the Qt5Svg.dll it needs) gets loaded from within the scope of my main app.
-
@hskoglund said in How to correctly deploy a modular Qt-Application on windows? (Contains: can not display svg-files in qml):
You could check the list of directories from where Qt tries to load its plugins by calling QCoreApplication::libraryPaths()
That looks like a cunning plan :) <insert Blackadder reference here>
I played around with this information a bit and made the following observations:
- Dumping the library paths in the constructor of my module indeed lists only the module directory, but not the application directory.
- So I guess you mean the relative path when you say
Your module_ui.dll inherits the search path from the .exe for .dlls
- Adding the application folder to the library search path within the module constructor solves the issue without the need for double-deployment
Thanks a lot, you brought me on the right track.