How to deploy QWindowsIntegrationPlugin with CMake - c++

I'm using CMake to build a Qt application. My project compiles, and thanks to 'fixup_bundle()', make install copies the required libraries next to my executable. Great!
Only problem is, when I execute it, I get the dreaded 'This application failed to start because it could not find or load the Qt platform plugin "windows".' error.
Indeed, manually copying qwindows.dll into a 'platforms' directory next to the executable fixes the issue. Now, how can I tell CMake to do that automatically?
Not much info from Qt :
Plugins are also available as IMPORTED targets in CMake. The Qt Network, Qt SQL, Qt GUI, and Qt Widgets modules have plugins associated. They provide a list of plugins in the Qt5_PLUGINS variable.
All right, I guess I have to play with Qt5::QWindowsIntegrationPlugin, which should be an imported target. That's where I'm lost.
I know (well, I think I know at least) that fixup_bundle() looks into the executable to find its dependencies. But despite the fact that I link my executable against QWindowsIntegrationPlugin, there is no trace of it. Therefore, no qwindows.dll copied into my output path by fixup_bundle().
Except the manual copy of the file, I couldn't find a nice CMake-friendly answer to this issue.
Thanks for your help.

Just ran into the same issue. Here is how I resolved it in my CMake install script:
# QWindowsIntegrationPlugin is part of the Gui component
find_package(Qt5 COMPONENTS Gui REQUIRED)
install(
FILES "$<TARGET_FILE:Qt5::QWindowsIntegrationPlugin>"
DESTINATION bin/platforms
)

Related

How to apply the libraries and plugins configuration loaded in QLibraryInfo in a QApplication?

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.

How can I use CMake to both build wxwidgets on-demand and link with it

I have the following situation:
I'm working on an application that depends on a number of third party libs, among them wxwidgets
I build the application for multiple target configurations (x86, arm, Linux, Windows) using Linux as my build host system
Due to the above mentioned multiple target configurations, I have chosen to build those third-party libs from source, using CMake's ExternalProject_Add function.
The third-party libs are built 'on-demand' at a location separate from my application's CMAKE_BINARY_DIR so that I can wipe the build tree for my application without having to rebuild the third-party libs (takes a looooong time).
The location of the third-party libs is different depending on what target configuration I build them for (obviously).
I'm quite new to CMake and the problem I currently face is this:
The source files in my application can't find the wx include files and I need to set the correct linker flags to be able to link my application against wxwidgets.
This seems to be handled by a utility 'wx-config' that provides exactly that info as output when run with either the --cppflags or --libs flag. I can not however, figure out how to catch that output and append it to the include dirs and linked libraries I setup from my CMakeLists.txt files.
So basically what I want is.
Build wxwidgets (if it doesn't exist) for the current target configuration
Run wx-config --cppflags and --libs to find out the correct include dirs and linker flags for the current target configuration
Use the info from step 2 when building targets that are my own application
So far I've tried something like this:
# Set a target-configuration-specific location
set(wxwidgetsTop ${MYPROJECT_EXTERNAL_DIR}/wxwidgets/wxwidgets_${MYPROJECT_CURRENT_TARGET_CFG})
# Build the project
ExternalProject_Add( wxWidgetsExternal
PREFIX ${wxwidgetsTop}
URL ${MYPROJECT_EXTERNAL_DIR}/tarballs/wxWidgets-3.0.2.tar.bz2
SOURCE_DIR ${wxwidgetsTop}/src/wxwidgets
CONFIGURE_COMMAND ${configure_cmdline}
BUILD_COMMAND make -j${MYPROJECT_NCPU}
INSTALL_COMMAND make install
)
# Create a wxwidgets target to be used as a dependency from other code
add_library(wxWidgets IMPORTED STATIC GLOBAL)
add_dependencies(wxWidgets wxWidgetsExternal)
# (non-working) attempt to get the correct include dirs and linker
# flags for wxwidgets
add_custom_command(TARGET wxWidgetsExternal
POST_BUILD
COMMAND ${INSTALL_DIR}/bin/wx-config ARGS --cppflags
COMMENT "Running wx-config"
)
but the above does not provide a way to actually use the result from the custom command to append the cppflags and linker options when building the targets that make up my application.
What is a good way to achieve what I want?
I see three different ways of doing this:
Method 1: use find_package
Use wxWidgets as a standalone requirement for your project, and expect the devs to install it before building your project. In your CMakeLists.txt you will need to call find_package(wxWidgets), like this:
find_package(wxWidgets COMPONENTS net gl core base)
if(wxWidgets_FOUND)
include(${wxWidgets_USE_FILE})
# and for each of your dependent executable/library targets:
target_link_libraries(<YourTarget> ${wxWidgets_LIBRARIES})
endif()
This has the advantage of not rebuilding the lib if you rebuild your project, however it requires some work for your user (they need to handle the installation of wxWidgets by hand) and for you (you need to setup include paths / compile definitions / ... by hand).
Method 2: embed wxWidgets
The second option is to bundle wxWidgets in your repo (svn external or git submodule) and usually (re)write the CMakeLists.txt of this lib to be target-oriented. Then, in your top-most CMakeLists.txt, you can do the following:
# for example, if you just need core and net:
target_link_librairies(my_app PUBLIC wxWidgetsCore wxWidgetsNet)
# No need to manually setup include dirs, etc...
To make a CMakeLists.txt target-oriented, you define include directories and other compilation properties for a target, not a directory. Example:
# When defining wxWidgetsCore, for example
add_library(wxWidgetsCore ...)
target_include_directories(wxWidgetsCore PUBLIC someDir)
target_compile_definitions(wxWidgetsCore PUBLIC -pedantic)
target_link_libraries(wxWidgetsCore PUBLIC someLib)
The drawback of this approach is that rebuilding your project will trigger a rebuild of wxWidgets. However, it is possible to trick this by not using "rebuild" but "clean just my app, then build". Here is some insight on how to achieve this.
Method 3: some sort of hybrid
The big drawback of method 2 leads to the third approach: don't put wxWidgets in your project, but create a CMakeLists.txt that will "import" the lib. The idea: you ask your user for the directory where wxWidgets is installed, then this script will setup everything for your project. First, put the CMakeLists.txt here:
/your-project-root
/thirdparty
/wxWidgets
CMakeLists.txt
/dir-where-wxwidgets-is-installed
...
Now, you define an imported target:
# When defining wxWidgetsCore, for example
set(WX_INCLUDE_DIR ${USER_SPECIFIED_WX_ROOT}/include)
add_library(wxWidgetsCore IMPORTED GLOBAL)
set_property(TARGET wxWidgetsCore APPEND PROPERTY
INTERFACE_INCLUDE_DIRECTORIES ${WX_INCLUDE_DIR})
See INTERFACE_INCLUDE_DIRECTORIES and INTERFACE_LINK_LIBRARIES. You need your user to have build wxWidgets somewhere in his system, but from your point of view you just do target_link_libraries(your_app PUBLIC wxWidgets...), as in method 2. The advantage is that this approach is interchangeable with method 2 transparently, and you don't put the whole dependency in your project.
Setting cppflags and linker flags has to be done at CMake time, but you are trying to run wx-config at build time and you are not capturing its output anyway, so your add_custom_command() isn't doing anything useful other than printing things to the build tool's output.
Ideally, you would use the FindwxWidgets module CMake already provides. It requires wxWidgets to already be built (but see further below). Have a look at the CMake documentation for it and see if that at least sounds like what you are trying to achieve manually by using wx-config. If you can get FindwxWidgets to do the job for you, that would be a much cleaner approach.
Getting something to build at configure time so you can use it later on in your CMakeLists.txt file is a bit more tricky. ExternalProject_Add() downloads and builds things at build time, but you need wxWidgets to be built earlier at configure time. I wrote an article recently for how to do at least the downloading part at configure time and you should be able to adapt it to do the whole build at configure time instead. The article uses Google Test as its example and can be found here:
https://crascit.com/2015/07/25/cmake-gtest/
It would be trivial to make it put the wxWidgets build wherever you like, not just in the CMAKE_BINARY_DIR area. That would allow you to have different wxWidgets builds for each build configuration and to be able to wipe out your application's build tree independently of the wxWidgets builds.
Hope that points you in the right direction.
The solution I use checks for wxWidgets installation in the system using find_package, if it's not found, then the script downloads wxWidgets from github and links the program against downloaded library. The lib is installed in the build directory, so only the first build is slow - subsequent builds do not even check wxWidgets sources timestamps, so the process is as fast as building using preinstalled wxWidgets library.
Here's how my script does it:
It quietly checks for wxWidgets installation using find_package(wxWidgets QUIET),
If it's found, the script adds a dummy library wxWidgets_external,
If it's not, then it creates an ExternalProject named wxWidgets_external which downloads, builds and installs the library in the build dir, setting wxWidgets_ROOT_DIR to point to the wxWidgets installation dir,
Then we add another ExternalProject pointing to a folder with the main program's source files and CMakeLists.txt build script. This external projects depends on wxWidgets_external which is either a dummy library in case wxWidgets is preinstalled in the system, or an external project set up to download the library from github,
In the aforementioned CMakeLists.txt we again call find_package, this time with REQUIRED parameter and use the library the standard way (https://docs.wxwidgets.org/trunk/overview_cmake.html). Because we set up the dependencies and variables correctly, this call will use either preinstalled wxWidgets (if it's available) or the one downloaded from github.
There are more quirks to it, but that's the gist of it. The full sample code (tested on Linux, Windows and Mac) is available on github (https://github.com/lszl84/wx_cmake_template).
Also see full blog post which explains this in more detail: https://justdevtutorials.medium.com/wxwidgets-cmake-multiplatform-superbuild-4ea86c4e6eda

Create standalone executable with CMake

I need to build a standalone executable. The main problem is that this project relies on dll which I previously built on my system.
When I create the executable there should not be a dependence from these dll so I need to know if I can include them somehow in the program. To compile I'm currently using CMake which I believe is the best solution, but I haven't figured a way to accomplish this task yet.
Right now in my CMakeLists.txt file I do the following:
find_package(ITK REQUIRED)
include(${ITK_USE_FILE})
add_executable(myexe myexe.cxx)
target_link_libraries(myexe
${ITK_LIBRARIES} )
I omitted some instructions to focus on what's most important. When I compile it, it correctly works but it is not standalone as it still keeps using the dll (also tried with .a) installed on my system.
Thanks
A DLL is by nature dynamically linked to at runtime. Your only option is to use a static library (.lib on windows .

QT missing dll after deploy

I've copied all of the dlls from QT that were required, and my application works fine on my Windows server machine.
However when trying to run it on a Windows 7 box i get the following message:
This application failed to start because it could not find or load he
Qt platform plugin "windows".
Reinstallning the application may fix this problem.
Any ideas what I'm missing here?
I'd scratched my head over this some time ago. It turned out that this was caused not by missing qwindows.dll, but rather one of libEGL.dll or libGLESv2.dll. This was tricky, because dependency walker does not show those libs as direct dependencies.
If you want to test on your dev machine, whether your app has all required libs, fire up console issue SET PATH=, cd to your app directory and run it.
This is complete list of dlls that my app is using (Qt 5.2 / QtQuick app only, rest is C++). QtQuick is nice but the size of Qt dependencies is a bit scary:
icu*.dll - depending on whether you've compiled with ICU
libEGL.dll
libGLESv2.dll
Qt5Core.dll
Qt5Gui.dll
Qt5Network.dll
Qt5Qml.dll
Qt5Quick.dll
Qt5Widgets.dll
Widely used solution is put all necessary libraris in the folder of application.
What are libraries application need?
Run application and see error message:
The program can't start because <Library name> is missing from your computer.
Try reinstalling the program to fix this problem
Library set is depended from Qt version. Run several times application and each time copy required lib you found what is neeeded for application.
In my case (Qt 5.2.1) there are
icudt51.dll,
icuin51.dll,
icuuc51.dll,
libgcc_s_dw2-1.dll,
libstdc++-6.dll,
libwinpthread-1.dll,
Qt5Core.dll,
Qt5Gui.dll,
Qt5Widgets.dll.
All libs you can found in your Qt install folder. But don't use libraries from Tools\QtCreator folder, because QtCreator has another version of these libraries!
In case of error:
This application failed to start because it could not find or load he Qt platform plugin windows. Reinstallning the application may fix this problem.
You should create folder platforms and copy qwindows.dll into it.
If you still got error you should create qt.conf file in application's folder with content:
[Paths]
Plugins=plugins
This solution is described in https://qt-project.org/forums/viewthread/37265
More information about qt.conf you can find at http://qt-project.org/doc/qt-5/qt-conf.html
In latest versions of Qt you can find deploy tool (since 5.2). This tool find necessary libraries for application and copy into application folder. You can run it something like this:
call c:\Qt\QtX.Y.Z\X.Y.Z\mingw48_32\bin\qtenv2.bat
cd /d "c:\path\to\your\application\folder"
windeployqt.exe your_application.exe
Generally it works well. But I notice that some libraries are not copied, but you can found by method is descibed at beggining of post. More useful information you can find at
http://qt-project.org/doc/qt-5/windows-deployment.html
In rare cases yo can got this error if some library is missing but not appear in error message above. Example: Qt 5.1.1: Application failed to start because platform plugin "windows" is missing
I wasn't in this situation, so I can't tell more.

SVG icons not showing up in Qt4 release build in windows

I have a Qt4 application with SVG icons, compiled with mingw (in windows), linked to Qt shared libraries.
When application is run, SVG icons show up in debug and release builds in linux, however in windows SVG icons show up only in debug build but not in release build.
All SVG icons are listed in project.qrc, and project.pro has RESOURCES = project.qrc. Application uses QtSvg4.dll (version 4.7.0).
Qt 4.7.0, Qt Creator 2.0.1, mingw/g++ 4.4.0.
Solution update: In application directory, create /imageformats/ directory and put qsvg4.dll there instead of application directory itself, or create a qt.conf file with appropriate path. More information in deploying plugins.
Most likely you will have to include the plugins from your qt dir. This involves making a qt.conf file that is local to your app (see here: http://doc.qt.io/qt-4.8/qt-conf.html , more specifically the [Paths] section), and copy c:\Qt\4.x.x\plugins\imageformats*.dll to your distributable's directory.
for Qt 5.14
add a line to the .pro file
QT += svg
For Qt5
Since Qt5 the framework has been heavily modularized (List of Modules).
Most likely you are missing the svg module. The application will still compile without complaining. Make sure the SVG module is installed on your system and linked (with qmake (Howto), cmake (Howto) or plain make). If it was linked successfully QImageReader::supportedImageFormats() will list SVG.
For my (Qt 4.6.3) application, I solved this by putting the plug-in dll (qsvgicon4.dll) in a directory called iconengines within the application directory.
Tried other solutions - such as deploying plugin to directory (within app directory) named imageformats with and without an appropriate qt.conf, but no joy.
Note: I previously ran the application with Qt 4.7.0 dlls and had no problems on the same Win7 target machine.
You guessed it: here's yet another way to avoid reading the docs, but instead to rely on cheap advice from the internet.
Just add this line to your app.pro!
QTPLUGINS += qsvg
In my case, Qt is static linked from MSYS2, so plugin DLLs don't even exist. But the app still has to link in that imageformats/qsvg plugin code. The qmake line above is about the easiest way to do it; it translates to the g++ link line segment like this:
g++ [...] -LC:/msys64/mingw64/qt5-static/share/qt5/plugins/imageformats \
C:/msys64/mingw64/qt5-static/share/qt5/plugins/imageformats/libqsvg.a [...]
Based on what you've said, you're doing all that's needed for it to work, so a proper answer is likely to require some more information. See if these links are of any use to you:
http://lists.trolltech.com/qt-interest/2008-10/msg00655.html
http://www.qtcentre.org/archive/index.php/t-9036.html
In particular, make sure that the SVG plugin is getting loaded with:
QImageReader::supportedImageFromats()
It still seem to be a problem with Qt5.1 in Windows, here how I solved it for cmake users:
Find_File(qtsvg NAMES "Qt5Svg.dll" PATHS ${QTBinBase}/.. PATH_SUFFIXES "bin" )
Find_File(qtxml NAMES Qt5Xml.dll PATHS ${QTBinBase}/.. PATH_SUFFIXES "bin" )
Find_File(qsvg NAMES "qsvg.dll" PATHS ${QTBinBase}/.. PATH_SUFFIXES "plugins/imageformats" )
Find_File(qsvgicon NAMES "qsvgicon.dll" PATHS ${QTBinBase}/.. PATH_SUFFIXES "plugins/iconengines" )
install(FILES ${qtsvg} ${qtxml} DESTINATION bin)
install(FILES ${qsvg} DESTINATION bin/plugins/imageformats)
install(FILES ${qsvgicon} DESTINATION bin/plugins/iconengines)
Its the manual way, not beautiful but works. QTBinBase I got with another dirty trick:
get_target_property(QtCore_location Qt5::Core LOCATION)
get_filename_component(QtBinBase ${QtCore_location} PATH)
If adding the Qt4Svg.dll and the imageformats/qsvg4.dll doesn't work, make sure the Qt4Xml.dll is also included along the standard core, gui and svg DLLs.
This is how I solved this for me.
Short: to render svg images you need to include the xml DLL aswell