QT static build woes
Update (Feb 9th, 2022): Right now, I'm using QT 5.15.2, which could be the last QT 5 release. For now I'm not upgrading to QT 6 as I don't need the new features. The static build process is somewhat easier with 5.15.2:
- Make sure Python (currently version 3.10) is installed, and the Python path contains no spaces.
- Download the sources from https://download.qt.io/official_releases/qt/5.15/5.15.2/single/
- Extract
- Download jom from http://download.qt.io/official_releases/jom/jom.zip
- Extract jom.exe to the qt-everywhere-src-5.15.2 directory
- Open extracted folder in x64 Native Tools Command Prompt for VS 2019 (included in Visual Studio 2019 Community)
configure.bat -prefix ../5.15.2-MSVC -opensource -confirm-license -mp -release -static -static-runtime -nomake tools -nomake examples -nomake tests -no-direct2d -opengl desktop -skip qtwebengine -skip qt3d- make sure you are still in the qt-everywhere-src-5.15.2 directory, and not the qtbase subdirectory
jomjom install
Use jom instead of nmake to utilize multi-core processors during build!
Original blog post below.
QT is a very popular UI toolkit for C++. I'm currently using it to develop a multimedia app for an artist. He uses it to compose music, but that's a different story.
One of the major headaches when working with QT is the deployment of the program to the end-user. Ideally, I want to have a single .exe file with no additional dependencies. I send that to the user, he double-clicks and the program starts.
If you try to do that with a QT app, your user won't be very happy. The program will not run and instead complain about a missing DLL. If you want to avoid that kind of situation you have to distribute QT with your program in form of DLL files. Depending on the QT version you are using, it might be around 70 DLL files totaling more than 60 Megabytes. If you don't believe me, download the Windows version of Calibre, a very popular e-book management app made using QT and count the DLL files.
That's the default way, and open source devs are super happy with it because that way, one avoids legal issues coming with the LGPLv3. Dynamic linking is necessary here if you are not including the source code with our app. I'm quoting the relevant text below.
- Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version.
Why someone would release a work under that license is beyond me, but that's the way it works. For the same reason, a statically linked version of the QT libraries is not really available for download anywhere. If you want to compile your app in a way so it does not need a shitload of DLL files to operate, you do need a statically linked version, though. This is where the troubles begin.
I know I shouldn't bother, but I find it very elegant to distribute an app as a single executable with no external dependencies, and I hate cluttering the app folder with countless extra files that have no meaning whatsoever to the user.
For that reason I have attempted many times to make a static build of the QT libraries, with varied success. There also is an entry on the QT bug tracker now, demanding pre-built static libraries.
Building QT 5.12.1 statically
I'm using the Visual C++ compiler here. This enables QT to use the Windows multimedia subsystem. If you use the MinGW compiler instead, your app cannot decode MP3 files.
So, you need Visual Studio 2017.
You also need the QT sources.
Unpack the QT sources to a folder somewhere - but don't nest it too deep because Windows by default does not allow very long pathnames.
Now, edit the file qtbase\mkspecs\common\msvc-desktop.conf and replace -MD with -MT. This will link the CRT statically, eliminiating yet another DLL dependency.
Specifically, there are two lines that should now look like this:
QMAKE_CFLAGS_RELEASE = $$QMAKE_CFLAGS_OPTIMIZE -MT
QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_OPTIMIZE -Zi -MT
Open a Visual Studio 2017 shell prompt, it's called "x64 Native Tools Command Prompt for VS 2017".
Navigate to the folder where you unpacked the source code.
Run the configure script with the necessary parameters:
configure.bat -prefix ../5.12.1-MSVC -opensource -confirm-license -mp -release -static -static-runtime -nomake tools -nomake examples -nomake tests -no-direct2d -opengl desktop -skip qtwebengine -skip qt3d -no-feature-d3d12
It used to be even more complicated than that, but they have improved it over the last couple of years. I don't want to compile tools/examples/tests and I also don't need debug information for the static build.
It's a good idea to skip qtwebengine if you don't need it because that's A LOT of code. The -no-feature-d3d12 is also recommended. Direct3D 12 support is a recent addition, not even enabled by default and only works on Windows 10. In a static build however, it will be compiled into your EXE file, so your whole program is incompatible with Windows below version 10. I need my app to run on Windows 8.1 too, so I had to disable it.
When everything is configured, you can start the build process by running nmake in the same console window. nmake install will then install the compiled libraries to the directory specified by -prefix. It's best to let this run over night. Even without the webengine, QT is huge.
Using the static QT
Simply add the newly built libraries to QT creator by selecting Tools->Options->Kits->QT Versions->Add. Then add a new kit that uses the version you just added.
When you build a project using the static version, make sure you select the "Release" configuration if you haven't built the debug libraries.