# 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](https://www.qt.io/licensing/) 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](https://www.msys2.org/)  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.

OS | Ubuntu 20.04 Lts
------------ | -------------
Device Vendor | Lenovo x240
CPU |  Intel® Core™ i5-4300U CPU @ 1.90GHz × 4
RAM | 7.7 GiB
Graphics | Intel® HD Graphics 4400 (HSW GT2)
Qt Source Version | 5.14.2
Build Tools | GCC  9.3
Time Spent | 4 hours 

### Set-Up the build Env. in Ubuntu
- Install build [requiremnet](https://doc.qt.io/qt-5/linux-requirements.html)  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](https://download.qt.io/archive/qt/)  Page 
- Set the Build Directory strcutre  [tree](http://mama.indstate.edu/users/ice/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](https://doc.qt.io/qt-5/configure-options.html)  i used**

```-static -release``` | Build a static release no debug
------------ | -------------
```-ltcg -optimize-size``` |  [Reduce](https://www.qt.io/blog/2019/01/02/qt-applications-lto)  the build size but will increase the compile time
```-qt-*``` |  Use those Lib from Qt not from the system
```-nomake tools, examples, tests``` | Do not build the qt tools like QtCreator and the examples and the tests
```-dbus-linked  -openssl-linked``` | Dynamic link to openssl and dbus Libs and to relink when needed
```-feature-freetype -fontconfig``` | Enable 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](https://cdn.hashnode.com/res/hashnode/image/upload/v1589389301425/2sIL0f4qL.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](https://cdn.hashnode.com/res/hashnode/image/upload/v1589389584598/h5RQpCvqk.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](https://manpages.ubuntu.com/manpages/trusty/man1/strip.1.html)  linux command
```
strip -s /appDir/app
```
-   [UPX](https://upx.github.io/)  compress tool to almost half of its size.
```
./upx -9 /appDir/app
```

### Build An AppImage 
 [AppImage](https://github.com/AppImage/AppImageKit)  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](https://docs.appimage.org/reference/appdir.html)  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.](https://appimage-builder.readthedocs.io/en/latest/intro/tutorial.html) **

### Static link all System Libs at once!
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 Size | 38 mb
------------ | -------------
after strip size |  35.5 mb
after upx size | 11.6 mb
AppImage Size | 11.3 mb

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

![ezgif.com-optimize.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1589449621321/uNouzFLy7.gif)

 [Download](https://github.com/foxoman/strtobin/releases/download/1/StringtoBinary-x86_64.AppImage)  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](https://cdn.hashnode.com/res/hashnode/image/upload/v1587235304131/Je4ZlrqY6.png)](https://www.buymeacoffee.com/foxoman)
 ***Thank you for your support!***
