Runtime errors in trivial static build of Qt hello world application in MSYS2/MinGW

Viewed 626

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.

3 Answers

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.

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

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.

Related