Setting Up Your First Static Build in Qt (Ubuntu 16.04)
Overview
If you’ve already made some dynamic builds in Qt, you’ve probably ran into dependancy hell when you tried to distribute the app you made. Apart from running dependancy walkers and hoping that solves your issues, a better solution is to statically link these dependancies. When you statically link, all the Qt dependancies (this does not include thrid party dependancies) will be bundled in your app. Unsurprisingly, the trade-off for this ease-of-distribution is much larger binary files.
Depending on who you google, statically compiling Qt apps is either not as hard as it sounds or a fucking nightmare. My experience falls into the latter case. I finally managed to build Qt from source (version 5.11.0) after five days of trial and error. While there are brief tutorials out there showing the few lines of code required to run the build, what they tend not to cover is the basic problem solving steps when you hit a bump in the road. Here, I’ll go over the steps I ran to get the build working in addition to the issues I ran into along the road and how I solved them.
Before we start, these steps worked for me on Elementary OS (Loki) which is based on Ubuntu 16.04.
Mise en Place: Qt Source and Dependencies
I used the normal Qt online installer to get the source code.
The resulting source code was found in the default install folder, in my case ~/Qt5/5.11.0/Src/
If you don’t already have Qt installed on your machine, you probably want to install all the components in this step. Static builds are great for deployments, but static debugging builds can take an enormus amount of space. It’s good practice to test your apps with dynamic builds then just statically build your release version. Now we have the source code, lets try to cover our dependances.
sudo apt install qtbase5-dev qtdeclaratives-dev
Additionally, Qt recommends you get the following packages:
sudo apt install libfontconfig1-dev libfreetype6-dev libx11-dev libxext-dev libxfixes-dev libxi-dev libxrender-dev libxcb1-dev libx11-xcb-dev libxcb-glx0-dev libxcb-keysyms1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync0-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0-dev
Hopefully thats all we need… lets move onto the build.
Building Qt
The five days of hell I went through was due to building Qt within the source directory.
This can result in some artefacts from previous failed builds that don’t get swept away by make clean
.
To avoid this, we want to do out-of-source builds.
The process is simple… just run configure
from your destination directory rather than the source.
If anything goes wrong, you can just delete the entire destination directory and start over worry free.
This is how I run the build config:
mkdir ~/Q5/5.11.0_Static;cd ~/Q5/5.11.0_Static;sudo ~/Qt5/5.11.0/Src/configure -v -static -prefix "/home/james/Qt/5.11.0_Static" -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -qt-freetype -qt-xcb -make libs -nomake tools -nomake examples -nomake tests -opensource -confirm-license -egl -opengl es2 -skip wayland
I added the commands mkdir ~/Q5/5.11.0_Static
and cd ~/Q5/5.11.0_Static
in the same line so that if a build fails I can quickly repeat the configure process by searching back in my terminal for a single line instead of three.
I won’t pretend to completely understand what all these options mean… but I’ll try to sum up what I think I know:
- It seems quite standard that you don’t compile
tools
,examples
, andtests
for static builds. - Options formatted with
-qt-[module]
are referring to third party modules where we’re specifying that we want to use the bundled Qt versions of these rather than our preinstalled system versions. My assumption is that choosing more Qt versions of modules reduces dependancies (as they are bundled in the binary during the static build). - If you’re using Ubuntu versions < 17.10, you probably want to incude
skip wayland
in the config like I did. With 17.10, ubuntu started using wayland as opposed to Xorg as its default display server. On my 16.04-based distro I didn’t have wayland and thus my builds were failing due to some sneaky dependancies that wern’t flagged as errors in the config step. Alternatively, you can install wayland on your system… however, this also needs to be built from source on 16.04, so lets just make life easier and skip it for now. -
-opensource
and-confirm-license
are just automatically saying yes the the appropriate promts during config. - The
-prefix
flag may be redundant here since we’re already running config from our destination directory. Regardless…-prefix
is used for shadow builds. This lets you output your build results into an external directory form where you are running make. While this sounds similar to an out-of-source build, its not! Both actions result in your compiled program being dropped to an external folder outside your source directory but a key difference is that shadow builds still do some work in your source directory during the build process while an out-of-source build does not. Here’s an example of an out-of-source build without the prefix flag.
If you run into errors during the config process, it’s likely due to missing dependancies.
After the necessary googling and apt-installing, try running ~/Qt5/5.11.0/Src/configure --recheck-all
to see if the issue has been resolved.
If you’ve installed some potentially missing dependancies and you’re still seeing the same error, it may be a good idea to just wipe the destiantion directory and start over.
I haven’t see any examples of this being necessary… but better to be over-cautious.
When everything finished properly, config should end with instructions to run make
followed by make install
.
Go ahead and try this when you’re ready:
sudo make
sudo make install
Just because configure
ran smooth, this doesn’t mean your out of the woods yet…
The make
step is where I ran into my wayland dependancy issues.
In my case, I forgot to add -skip wayland
in my configure
and this messed up my make
.
Even after rerunning configure
with the added option I was still getting the same dependancy errors during building.
The problem was finally resolved when I wiped my build directory, redownloaded the source code and tried again.
I could have saved myself a lot of hassle if I had just used out-of-source builds from the start and wiped my destination directory each time I had a make error.
Wiping the destination directory is exactly what is sounds like and in this example just consists of:
sudo rm -R ~/Qt5/5.11.0_Static/
Finally… after a few hours and hopefully no errors, you’ve got a new version of Qt which allows you to run static builds.
Adding the Static Qt Compiler to Qt Creator
Now that you have a new version of Qt, you need to register it in Qt Creator. This process involves two simple steps:
- Add the new static version of
qmake
to Qt Creator. - Create a new build kit which uses this new compiler.
-
Go to Tools > Options > Build & Run > Qt Versions.
-
Press Add and select the
qmake
binary we just built. In the case of this example, its located at: /home/james/Qt/5.11.0_Static/bin/qmake
-
To keep thing organized, modify the version name so you remember that this is the static version.
-
Now, under the Kits tab, again press Add. Now you can make a new build kit which uses the static version of
qmake
.
Running a Static Build
Now you’ve got everything setup, its time to build!
When building, just select that new static build kit we created and let qmake
do the rest.
If all is well, your new compiled binary should be much larger that your previous dynamic builds. My 1.9MB binaries now turn into 20MB after using the static build kit. More importantly, now I can distribute apps without having to fully install Qt creater or spend days searching for missing dependancies.
Concluding Thoughts
- I previously thought, due to seeing many examples including it, that you had to add the flag
CONFIG += -static
in your.pro
file in addition to selecting a qmake binary build with the static flag… but apparently this isn’t the case. - If you are running into issues, I strongly reccomend posting on the Qt forums rather than other Q&A sites like stackoverflow. Responses were lightning fast and on point in my experience.