End to End GUI Development with Qt5
上QQ阅读APP看书,第一时间看更新

Linux

Linux packaging and deployment is broadly similar to OS X, and we won’t cover it in the same level of detail, so at least skim the OS X section first if you haven’t already. As with all platforms, the first thing to do is build the solution using the kit of your choice in the Release mode in order to generate the binaries.

When building in Release mode for the first time, I received the “cannot find -lGL” error. This was because the dev libraries for OpenGL were not installed on my system. One way of obtaining these libraries is to install FreeGlut:
$ sudo apt-get update
$ sudo apt-get install build-essential
$ sudo apt-get install freeglut3-dev

Once compiled, copy the cm-ui binary to a new cm/installer/linux directory.

Next, we can take a look at what dependencies our application has. In a command terminal, change to the cm/installer/linux folder and run ldd:

$ ldd <Qt Projects>/cm/binaries/linux/gcc/x64/release/cm-ui

You will see an output similar to the following:

linux-vdso.so.1 => (0x00007ffdeb1c2000)
libcm-lib.so.1 => /usr/lib/libcm-lib.so.1 (0x00007f624243d000)
libQt5Gui.so.5 => /home/nick/Qt/5.9.1/gcc_64/lib/libQt5Gui.so.5 (0x00007f6241c8f000)
libQt5Qml.so.5 => /home/nick/Qt/5.9.1/gcc_64/lib/libQt5Qml.so.5 (0x00007f6241698000)
libQt5Xml.so.5 => /home/nick/Qt/5.9.1/gcc_64/lib/libQt5Xml.so.5 (0x00007f624145e000)
libQt5Core.so.5 => /home/nick/Qt/5.9.1/gcc_64/lib/libQt5Core.so.5 (0x00007f6240d24000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f62409a1000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f624078b000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f62403c1000)
libQt5Sql.so.5 => /home/nick/Qt/5.9.1/gcc_64/lib/libQt5Sql.so.5 (0x00007f6240179000)
libQt5Network.so.5 => /home/nick/Qt/5.9.1/gcc_64/lib/libQt5Network.so.5 (0x00007f623fde8000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f623fbcb000)
libGL.so.1 => /usr/lib/x86_64-linux-gnu/mesa/libGL.so.1 (0x00007f623f958000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f623f73e000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f623f435000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f623f22c000)
libicui18n.so.56 => /home/nick/Qt/5.9.1/gcc_64/lib/libicui18n.so.56 (0x00007f623ed93000)
libicuuc.so.56 => /home/nick/Qt/5.9.1/gcc_64/lib/libicuuc.so.56 (0x00007f623e9db000)
libicudata.so.56 => /home/nick/Qt/5.9.1/gcc_64/lib/libicudata.so.56 (0x00007f623cff7000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f623cdf3000)
libgthread-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgthread-2.0.so.0 (0x00007f623cbf1000)
libglib-2.0.so.0 => /lib/x86_64-linux-gnu/libglib-2.0.so.0 (0x00007f623c8df000)
/lib64/ld-linux-x86-64.so.2 (0x0000562f21a5c000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f623c6b6000)
libxcb-dri3.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-dri3.so.0 (0x00007f623c4b2000)
libxcb-present.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-present.so.0 (0x00007f623c2af000)
libxcb-sync.so.1 => /usr/lib/x86_64-linux-gnu/libxcb-sync.so.1 (0x00007f623c0a8000)
libxshmfence.so.1 => /usr/lib/x86_64-linux-gnu/libxshmfence.so.1 (0x00007f623bea4000)
libglapi.so.0 => /usr/lib/x86_64-linux-gnu/libglapi.so.0 (0x00007f623bc75000)
libXext.so.6 => /usr/lib/x86_64-linux-gnu/libXext.so.6 (0x00007f623ba63000)
libXdamage.so.1 => /usr/lib/x86_64-linux-gnu/libXdamage.so.1 (0x00007f623b85f000)
libXfixes.so.3 => /usr/lib/x86_64-linux-gnu/libXfixes.so.3 (0x00007f623b659000)
libX11-xcb.so.1 => /usr/lib/x86_64-linux-gnu/libX11-xcb.so.1 (0x00007f623b457000)
libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f623b11c000)
libxcb-glx.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-glx.so.0 (0x00007f623af03000)
libxcb-dri2.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-dri2.so.0 (0x00007f623acfe000)
libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f623aadb000)
libXxf86vm.so.1 => /usr/lib/x86_64-linux-gnu/libXxf86vm.so.1 (0x00007f623a8d5000)
libdrm.so.2 => /usr/lib/x86_64-linux-gnu/libdrm.so.2 (0x00007f623a6c4000)
libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f623a453000)
libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007f623a24e000)
libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f623a048000)

That’s some list of dependencies! Crucially, note the dependency on our cm-lib library:

libcm-lib.so.1 => /usr/lib/libcm-lib.so.1

This shows that the executable will look for our library in the /usr/lib folder, so let’s ensure that it’s available there before we move on by copying libcm-lib.so.1 to /usr/lib:

$ sudo cp <Qt Projects>/cm/binaries/linux/gcc/x64/release/libcm-lib.so.1 /usr/lib

We can already guess what a nightmare managing all these dependencies manually will be, having discussed the OS X process and seen how many dependencies there are, so there must be a tool in our Kit’s bin folder that does it all for us, right? Well, yes and no. There is no official Qt tool we get out of the box to do this for us like there is for OS X and Windows. Fortunately, a fantastic member of the Qt community probonopd has come to the rescue and plugged the gap with linuxdeployqt.

You can get a linuxdeployqt app image from the releases page of the GitHub project at https://github.com/probonopd/linuxdeployqt. Download the file (linuxdeployqt-continuous-x86_64.AppImage) and then make it executable:

$ chmod a+x <Path to downloaded file>/linuxdeployqt-continuous-x86_64.AppImage

We can then execute it and have it work its dependency-based magic for us. Change the directory to cm/installer/linux first:

$ <Path to downloaded file>/linuxdeployqt-continuous-x86_64.AppImage cm-ui -qmldir=<Qt Projects>/cm/cm-ui -appimage

The qmldir flag tells the tool where to scan for QML imports and is set to our UI project folder. The appimage flag is used to get the tool to create an application image file for us, which is a single file with everything bundled inside.

Things may not work perfectly the first time. Your output may look as follows:

ERROR: Desktop file missing, creating a default one (you will probably want to edit it)
ERROR: Icon file missing, creating a default one (you will probably want to edit it)
ERROR: "/usr/bin/qmake -query" exited with 1 : "qmake: could not exec '/usr/lib/x86_64-linux-gnu/qt4/bin/qmake': No such file or directoryn"
ERROR: Qt path could not be determined from qmake on the $PATH
ERROR: Make sure you have the correct Qt on your $PATH
ERROR: You can check this with qmake -v

The first two errors are just because we haven’t provided a desktop file or icon and defaults have been generated for us; we can ignore those. The rest are because linuxdeployqt doesn't know where qmake is. We can either provide the path as an extra parameter (-qmake=<PATH>), or to save us having to do it every time, we can add it to our PATH environment variable:

$ export PATH=<Qt Path>/5.9.1/gcc_64/bin/:$PATH

We can then check whether qmake can be found by trying to retrieve the version information:

$ qmake -v

If it is happy, you will see the version information:

QMake version 3.1
Using Qt version 5.9.1 in /home/nick/Qt/5.9.1/gcc_64/lib

With that fixed, we can now try running the linuxdeployqt command again. However, we’ve fixed one problem, but now experience another:

ERROR: Desktop file missing, creating a default one (you will probably want to edit it)
ERROR: Icon file missing, creating a default one (you will probably want to edit it)
ERROR: ldd outputLine: "libmysqlclient.so.18 => not found"
ERROR: for binary: "/home/nick/Qt/5.9.1/gcc_64/plugins/sqldrivers/libqsqlmysql.so"
ERROR: Please ensure that all libraries can be found by ldd. Aborting.

Ignore the first two errors again. Now it can't find MySQL drivers, which is annoying, because we aren’t even MySQL and it is the same Qt SQL quirk we saw on OS X. As a workaround, let's effectively "hide" the SQL drivers we don't want from the tool by temporarily renaming them:

$ cd <Qt Path>/5.9.1/gcc_64/plugins/sqldrivers
$ mv libqsqlmysql.so libqsqlmysql.so_ignore
$ mv libqsqlpsql.so libqsqlpsql.so_ignore

Run the linuxdeployqt command again. You will get lots of output this time, culminating in a success message, including the following:

App name for filename: Application
dest_path: Application-x86_64.AppImage

This is telling us that our app image has been named as Application-x86_64.AppImage, which it saves to the Downloads folder.

Take a look in file manager, and you will see that it has added various files and directories alongside our executable:

It has also deposited the Application-x86_64.AppImage file in the Downloads folder that is a single self-contained executable package with all dependencies. However, if you head over to Downloads and try and launch the AppImage, you may get an error (execute it via a Terminal command to see the error message):

QXcbIntegration: Cannot create platform OpenGL context, neither GLX nor EGL are enabled

This appears to be an issue with linuxdeployqt missing some dependencies, but for some reason, running the tool a second time magically picks them up. Execute the linuxdeployqt command again, and hey presto, the AppImage now works correctly.