Compile Static Qt Build in Ubuntu Optimized for Small Size With AppImage Support!

Compile Static Qt Build in Ubuntu Optimized for Small Size With AppImage Support!

Qt is a static build-ready framework but it published as Shared Library due to license requirements. As you are reading this you should already know what is the requirement to build a static build and what is the benefits.

For me, it makes my life easy to distribute my final product with one single binary file for all Qt libraries and less dependency on system library and no need to worry about other system libs which could be missing in other computers and systems, as either, I also build my app against static system libs to get one absolute file or just package few systems shared libs.

For windows, there is a qt static build in Msys2 Repo but I could not find any ready static build for Linux with the last releases.

Looking around a with many trial and error I got the correct build configuration for my environment which may help you too.

My Build Env.

OSUbuntu 20.04 Lts
Device VendorLenovo x240
CPUIntel® Core™ i5-4300U CPU @ 1.90GHz × 4
RAM7.7 GiB
GraphicsIntel® HD Graphics 4400 (HSW GT2)
Qt Source Version5.14.2
Build ToolsGCC 9.3
Time Spent4 hours

Set-Up the build Env. in Ubuntu

  • Install build requiremnet in Ubuntu
    sudo apt-get build-dep qt5-default 
    sudo apt install build-essential libclang-dev libssl-dev python-is-python2  libfontconfig1-dev libfreetype6-dev
    
  • Download Qt Source from Qt Download Page
  • Set the Build Directory strcutre tree to be like this :
    /home/foxoman/Qt5static        // My Build Dir under the name Qt5static
    └── 5.14.2
      ├── build                    // Build Prefix
      ├── src                      // extract the Qt source here
      └── static                   // final install folder
    

Configure the build

Now open the terminal and apply this one command, if you apply same build structure then you do not need to change anything otherwise change accordingly

cd ~/Qt5static/5.14.2/build; ~/Qt5static/5.14.2/src/configure -v -static -release -ltcg -optimize-size -no-pch -prefix ~/Qt5static/5.14.2/ -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -qt-freetype -qt-xcb -qt-harfbuzz -make libs -nomake tools -nomake examples -nomake tests -opensource -confirm-license -skip qtwebengine -dbus-linked -no-rpath -openssl-linked -opengl desktop -sysconfdir "/etc/xdg" -no-qml-debug -feature-freetype -fontconfig -feature-relocatable -strip

To Understand what each setting do or to get more options

cd ~/Qt5static/5.14.2/build; ~/Qt5static/5.14.2/src/configure -h

Here are some the configuration options i used

-static -releaseBuild a static release no debug
-ltcg -optimize-sizeReduce the build size but will increase the compile time
-qt-*Use those Lib from Qt not from the system
-nomake tools, examples, testsDo not build the qt tools like QtCreator and the examples and the tests
-dbus-linked -openssl-linkedDynamic link to openssl and dbus Libs and to relink when needed
-feature-freetype -fontconfigEnable fontconfig to read system fonts otherwise you have to ship your app with the fonts

Build and Install

To Build and install the static final build in static folder run the bellow commands

make -j $(grep -c ^processor /proc/cpuinfo)

make install

Configure QtCreator to Use the Static Kit

Peek 2020-05-13 21-00.gif You Will have to Add the Qt Version from the static build and New Qt Kit to use!

2020-05-13_21-04.png Creating New Project you Can Activate the New Static Build

Optimize for smaller size

Due to our build configuration, the build size will be smaller than the normal static build size and we can make it smaller using:

  • Strip linux command
    strip -s /appDir/app
    
  • UPX compress tool to almost half of its size.
    ./upx -9 /appDir/app
    

Build An AppImage

AppImage format is the portable format in Linux and by building your app as a static app then it so easy to package it and distribute your app for Linux.

We will do it manually in an easy way.

  • Install appimagetool
sudo wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /usr/local/bin/appimagetool
sudo chmod +x /usr/local/bin/appimagetool
  • Build the AppDir Dir Structure to be a simple as bellow
/home/foxoman/app.AppDir
├── app.desktop
├── app.png
├── AppRun
└── usr
    ├── bin
    │   └── app
    └── share
        ├── applications
        │   └── app.desktop
        └── icons
            └── hicolor
                └── 256x256
                    └── apps
                        └── app.png

8 directories, 6 files

In Case you wanted to add few System Libs or Qt Plug-In which you can not build statically needed to be shipped with your app add it in /usr/lib/ folder and activate the export to the lib folder in AppRun file as explained later!

  • Make a folder Called app.AppDir and create the sub dir as per the above structure

  • You Will only need 4 files to care about, your App Binary should be in /bin/ folder and the app icon in two places and the desktop file also in two places plus the AppRun bash file to run the app, And /lib/ Folder for shared system libs.

#!/bin/sh
HERE="$(dirname "$(readlink -f "${0}")")"

## If you gonna add more libs inside the appimage uncomment this line and change the url as needed
#export LD_LIBRARY_PATH=${HERE}/usr/lib/foobar:$LD_LIBRARY_PATH

# uncomment for GUI App
#exec "${HERE}/usr/bin/app" "$@"

# uncomment for console app
x-terminal-emulator -e "${HERE}/usr/bin/app" "$@"
  • now run this command to build the appimage
 appimagetool '/home/foxoman/app.AppDir'

Finding the missing Libs

Few System Libs still needed if it's not linked statically to your bin like the GCC libs and so on. To find out what libs is needed: objdump -p /bin/app It will tell you something like this:

Dynamic Section:
  NEEDED               libc.so.6
  NEEDED               libdouble-conversion.so.3
  NEEDED               libicui18n.so.66
  NEEDED               libicuuc.so.66
  NEEDED               libglib-2.0.so.0
  NEEDED               libpthread.so.0
  NEEDED               libstdc++.so.6
  NEEDED               libm.so.6
  NEEDED               libgcc_s.so.1
  NEEDED               ld-linux-x86-64.so.2

And you could use this command to find where those required libs is located:

ldd -v /bin/app

Result like this:

    linux-vdso.so.1 (0x00007ffed2df0000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fedae872000)
    libdouble-conversion.so.3 => /lib/x86_64-linux-gnu/libdouble-conversion.so.3 (0x00007fedae85c000)
    libicui18n.so.66 => /lib/x86_64-linux-gnu/libicui18n.so.66 (0x00007fedae55d000)
    libicuuc.so.66 => /lib/x86_64-linux-gnu/libicuuc.so.66 (0x00007fedae377000)
    libglib-2.0.so.0 => /lib/x86_64-linux-gnu/libglib-2.0.so.0 (0x00007fedae24e000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fedae22b000)
    libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fedae048000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fedadef9000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fedadede000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fedaec54000)
    libicudata.so.66 => /lib/x86_64-linux-gnu/libicudata.so.66 (0x00007fedac41d000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fedac417000)
    libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007fedac3a4000)

You will need to ship them with your app image then you finally able to complete all requirements or just build and link it statically with your app as bellow if you have static system libs available or you build it your self statically.

To Make Automatic AppImage Build you could use AppImage Builder.

To make life easier for you, you may need to compile your app statically with all required system static libraries, to do that add this Line to your app qmake file in QtCreator or to the command line.

QMAKE_LFLAGS += -static -s -Os

This will also strip out your binary file and you will not need to use strip command!

Final Result

Using Static Qt Build and strip with UPX tool and package it as AppImage I am able to get a completely High Performance, Small Size portable format solution to publish my apps in all Linux distros. While the size looks high for console app but for a full GUI app with an approximate of 10 - 20 MB only is a big success.

I have created a small console app as an example.

Optimized Static App Size38 mb
after strip size35.5 mb
after upx size11.6 mb
AppImage Size11.3 mb

The test app is a full console app String to Binary Converter!

ezgif.com-optimize.gif

Download and test it and let me know!

Please let me know how it works and your comment and share for this article down in comment section.


bymecoffe.png Thank you for your support!