2

I am trying to build a trivial Qt application, shown below, for Windows using MSYS2/MinGW.

hello.cpp:

#include <QApplication>
#include <QWidget>

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QWidget window;
    window.setWindowTitle("Hello world");
    window.show();
    return app.exec();
}

I can build this with the command below, and it builds and runs successfully:

g++ $(pkg-config Qt5Widgets Qt5Core --cflags) hello.cpp $(pkg-config Qt5Widgets --libs) -o hello

Now I would like to build the application statically so that I can deploy/run it as a standalone executable file. The mingw-w64-x86_64-qt5-static package appears to exist for exactly this purpose, so I've installed it (version 5.15.1-1) with pacman.

By default, the pkg-config files for the static Qt build are not in the PKG_CONFIG_PATH, so I've updated PKG_CONFIG_PATH to search the files in qt5-static first:

PKG_CONFIG_PATH=/mingw64/qt5-static/lib/pkgconfig:$PKG_CONFIG_PATH

I have also updated my build command accordingly to request the static dependencies for the libs. However, this results in a bunch of errors:

$ g++ $(pkg-config Qt5Widgets Qt5Core --cflags) hello.cpp $(pkg-config Qt5Widgets --static --libs) -o hello
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libQt5Gui.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtlibpng.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtharfbuzz.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libQt5Core.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtpcre2.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libQt5Core.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtpcre2.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtlibpng.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtharfbuzz.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtpcre2.a: No such file or directory

The offending file paths come directly from the Libs.private section of the .pc files from the package. It looks like maybe they're using the package maintainer's machine's paths?

Anyway, since I should have all of these libraries, I tried to work around the issue by piping the pkg-config output through sed to replace the absolute paths with their corresponding -l flags, as shown below (for example, this replaces D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtharfbuzz.a with -lqtharfbuzz, etc.). This results in a successful build, but when I attempt to run the resulting executable, I get the runtime failure shown:

$ g++ --static -static-libstdc++ $(pkg-config Qt5Widgets Qt5Core --cflags) hello.cpp $(pkg-config Qt5Widgets --static --libs | sed 's/D:\/\S\+\/lib\(\S\+\)\.a\b/-l\1/g') -o hello
$ ./hello
qt.qpa.plugin: Could not find the Qt platform plugin "windows" in ""
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

My question is, then, how do you build a static Qt executable using MSYS2/MinGW and mingw-w64-x86_64-qt5-static?

Edit: To provide a little more transparency in case it is useful for understanding/debugging the issue, I've run the same static build commands with set -x in bash so that you can see how the pkg-config commands get expanded.

Without the sed filter:

$ g++ --static -static-libstdc++ $(pkg-config Qt5Widgets Qt5Core --cflags) hello.cpp $(pkg-config Qt5Widgets --static --libs) -o hello
++ pkg-config Qt5Widgets Qt5Core --cflags
++ pkg-config Qt5Widgets --static --libs
+ g++ --static -static-libstdc++ -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -IC:/msys64/mingw64/qt5-static/include/QtWidgets -IC:/msys64/mingw64/qt5-static/include -IC:/msys64/mingw64/qt5-static/include/QtGui -IC:/msys64/mingw64/qt5-static/include -IC:/msys64/mingw64/qt5-static/include/QtCore -IC:/msys64/mingw64/qt5-static/include hello.cpp -LC:/msys64/mingw64/qt5-static/lib -lQt5Widgets D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libQt5Gui.a -ld3d11 -ldxgi -ldxguid D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtlibpng.a D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtharfbuzz.a -lcomdlg32 -loleaut32 -limm32 -lglu32 -lopengl32 -lgdi32 D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libQt5Core.a -lmpr -luserenv -lversion -lz D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtpcre2.a -lzstd -lnetapi32 -lws2_32 -ladvapi32 -lkernel32 -lole32 -lshell32 -luuid -luser32 -lwinmm -luxtheme -ldwmapi -lshell32 -lcomdlg32 -loleaut32 -limm32 -lwinmm -lws2_32 -lole32 -luuid -ladvapi32 -lglu32 -lopengl32 -lgdi32 -luser32 -lQt5Gui -ld3d11 -ldxgi -ldxguid D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libQt5Core.a -lmpr -luserenv -lversion -lz D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtpcre2.a -lzstd -lnetapi32 -lws2_32 -ladvapi32 -lkernel32 -lole32 -lshell32 -luuid -luser32 -lwinmm D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtlibpng.a D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtharfbuzz.a -lz -lcomdlg32 -loleaut32 -limm32 -lwinmm -lws2_32 -lole32 -luuid -ladvapi32 -lglu32 -lopengl32 -lgdi32 -luser32 -lQt5Core -lmpr -luserenv -lversion -lz D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtpcre2.a -lzstd -lnetapi32 -lws2_32 -ladvapi32 -lkernel32 -lole32 -lshell32 -luuid -luser32 -lwinmm -o hello
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libQt5Gui.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtlibpng.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtharfbuzz.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libQt5Core.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtpcre2.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libQt5Core.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtpcre2.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtlibpng.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtharfbuzz.a: No such file or directory
g++.exe: error: D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/libqtpcre2.a: No such file or directory

With the sed filter:

$ g++ --static -static-libstdc++ $(pkg-config Qt5Widgets Qt5Core --cflags) hello.cpp $(pkg-config Qt5Widgets --static --libs | sed 's/D:\/\S\+\/lib\(\S\+\)\.a\b/-l\1/g') -o hello
++ pkg-config Qt5Widgets Qt5Core --cflags
++ pkg-config Qt5Widgets --static --libs
++ sed 's/D:\/\S\+\/lib\(\S\+\)\.a\b/-l\1/g'
+ g++ --static -static-libstdc++ -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -IC:/msys64/mingw64/qt5-static/include/QtWidgets -IC:/msys64/mingw64/qt5-static/include -IC:/msys64/mingw64/qt5-static/include/QtGui -IC:/msys64/mingw64/qt5-static/include -IC:/msys64/mingw64/qt5-static/include/QtCore -IC:/msys64/mingw64/qt5-static/include hello.cpp -LC:/msys64/mingw64/qt5-static/lib -lQt5Widgets -lQt5Gui -ld3d11 -ldxgi -ldxguid -lqtlibpng -lqtharfbuzz -lcomdlg32 -loleaut32 -limm32 -lglu32 -lopengl32 -lgdi32 -lQt5Core -lmpr -luserenv -lversion -lz -lqtpcre2 -lzstd -lnetapi32 -lws2_32 -ladvapi32 -lkernel32 -lole32 -lshell32 -luuid -luser32 -lwinmm -luxtheme -ldwmapi -lshell32 -lcomdlg32 -loleaut32 -limm32 -lwinmm -lws2_32 -lole32 -luuid -ladvapi32 -lglu32 -lopengl32 -lgdi32 -luser32 -lQt5Gui -ld3d11 -ldxgi -ldxguid -lQt5Core -lmpr -luserenv -lversion -lz -lqtpcre2 -lzstd -lnetapi32 -lws2_32 -ladvapi32 -lkernel32 -lole32 -lshell32 -luuid -luser32 -lwinmm -lqtlibpng -lqtharfbuzz -lz -lcomdlg32 -loleaut32 -limm32 -lwinmm -lws2_32 -lole32 -luuid -ladvapi32 -lglu32 -lopengl32 -lgdi32 -luser32 -lQt5Core -lmpr -luserenv -lversion -lz -lqtpcre2 -lzstd -lnetapi32 -lws2_32 -ladvapi32 -lkernel32 -lole32 -lshell32 -luuid -luser32 -lwinmm -o hello

Also, at the moment I'm merely interested in understanding how to get this trivial example building from the command line in MSYS2/Mingw using the existing package MSYS2 package. I'm not yet interested in using Qt Creator/QMake/etc. to manage the build.

Frank
  • 23
  • 3

3 Answers3

0

You'll have to build a static version of the Qt libraries (they only distribute dynamic libraries).

This page:

static Qt

isn't entirely accurate (I've edited it a couple of times), but it's a good start.

mzimmers
  • 857
  • 7
  • 17
  • I was hoping to stay in the MSYS2/MinGW64 shell and to use the existing `mingw-w64-x86_64-qt5-static` package, but as that approach doesn't seem to be working, perhaps I will have to resort to generating my own static libs and building my applications using Qt Creator as you point out. I would still be interested to understand what the issue is with my approach, though. – Frank Nov 25 '20 at 12:44
  • I'm really not familiar with mingw-w64-x86_64-qt5-static. I wonder if it's an incomplete build that happens to be missing some of the libraries you need. Anyway, I still recommend you look into building your own library. It's only a few steps, and I can provide you details if you like. – mzimmers Nov 26 '20 at 03:32
0

Looks like like it's looking for the libraries in the absolute location D:/mingwbuild/mingw-w64-qt5-static/src/x86_64/qtbase/lib/. Is it correct that that is not where you have the library files?

A dirty workaround would be to copy them in this exact location.

You could also try adding pkg-config option --define-prefix to see if that fixes the reported path of the library files.

For building a static Qt yourself see my earlier instructions here: how to statically compile Qt using MinGW compiler and SSL support

Brecht Sanders
  • 6,215
  • 1
  • 16
  • 40
  • Correct - that is not the location of the library files on my machine. I tried your `--define-prefix` suggestion, but it doesn't resolve the issue. The `prefix` value in the .pc files already appears to be correct for my installation (`prefix=/mingw64/qt5-static`), but some (not all) of the `Libs.private` values in the .pc files use those absolute paths. I may have to resort to building a static Qt myself, as you suggest, though I was originally hoping to utilize the existing MSYS2 package. – Frank Nov 25 '20 at 12:38
0

In order to avoid qt.qpa.plugin: Could not find the Qt platform plugin "windows" in "" you'll need to link statically against the Windows platform plugin. Most likely you also want to link statically against other plugins, e.g. for Qt Widgets styles or SVG icon support.

I suggest reading the official documentation: https://doc.qt.io/qt-5/plugins-howto.html#static-plugins

The steps under "Creating Static Plugins" are important. Since you're likely only using plugins provided by Qt you can skip the first step of course. Since you're not using QMake you can not follow the last step but instead need to add the corresponding static library for the plugin manually to your linker invocation (and libraries it depends on). Use pacman -Ql mingw-w64-x86_64-qt5-static to find the paths of plugins in your installation.

Martchus
  • 101
  • 5
  • The static plugins seemed to be the missing piece! There were a lot of hoops to jump through, but I eventually arrived at a standalone static executable. Specifically, I had to define the preprocessor macro `QT_STATICPLUGIN`, add `Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)` macros in my source file, and then play dependency hunting with `nm` to track down all the libraries I needed to resolve the missing references. I was a bit surprised how many additional libs I needed to bring in for this. I guess this is why people use qmake. – Frank Nov 28 '20 at 00:17
  • Don't expect a smooth experience when using qmake. I suppose making a static build using GCC/mingw-w64 is not supported by upstream, e.g. I had to patch a lot (https://github.com/Martchus/PKGBUILDs/tree/master/qt5-base/mingw-w64-static). However, I've already tested making a statically linked executable with Qt 6 and CMake and that was way less hacky (https://github.com/Martchus/PKGBUILDs/tree/master/qt6-base/mingw-w64-static). – Martchus Nov 30 '20 at 11:23