At the end of October 2018 on the Qt development mailing list it was announced
that CMake was chosen as the build system (generator) for building Qt6. That also meant that The Qt Company will gradually stop
investing in their in house Qbs build system.
I personally think is a good idea to have major C++ projects like Boost (July 2017 switch announcement! ),
LLVM/Clang, and now Qt to use CMake as their build system (generator). We C++ developers should work together in having a common build system.
There was a bit of email traffic on this topic. There was some skepticism of CMake being able to support specialized operating systems
like QNX, so I pointed to an October 2017 blog entry of Doug Schaefer named QNX CMake Toolchain File.
There Doug Schaefer presents us with a minimal CMake Toolchain File.
Since I am lucky() to have a QNX 7.0 license I tried to compile and run the recently released CMake 3.13.0 for the QNX 7.0 x86_64 target!
Basic CMake Compilation
The toolchain looks like this:
The build script looks like this:
Notice how I am using CMake 3.13.x’s -S and -B parameters! No more mkdir builddir && cd builddir commands anymore! Yeah!
The configuration step had some problems because it uses try_run and I was cross-compiling. Running the script a second time worked out fine.
The failed CMake configuration was due to:
The compilation fails at some point because libuv doesn’t have QNX support. The following patch
gets things working!
cmake, cpack, and ctest compiled and installed just fine! So… we’re done, right?
CMake-GUI Building
What happens if we want to build cmake-gui? CMake is shipping cmake-gui for Windows/Mac/Linux as a GUI application statically linked to Qt.
So I went and compiled Qt 5.11.2 statically for QNX x86_64 with this script:
The magic part above is the -xplatform qnx-x86-64-qcc. I don’t build icu, fontconfig, because the QNX 7.0 VMware image doesn’t provide them,
and I felt that it defeated my goal to deploy *.so files, hack LD_LIBRARY_PATH, and so on. I just wanted to run ./cmake-gui.
The toolchain does have libicu, which is quite a monster (31.4M!):
My CMake build script would change to:
Unfortunately CMake configure step stops with the following error:
The CMake package files that Qt provides require some C++ compiler features to be present.
So what did CMake detect using our QNX toolchain? Let’s just take a peak!
The above bug report has some workarounds for this problem, but what if we fixed this? QNX has QCC as a compiler wrapper around GCC, so what if I used GCC directly?
I came up with this small QNX toolchain:
Now I was able to compile, but not to link. Oh no!
CMake-GUI Linking and Deployment
I had a look at what CMake was doing for Windows and came up with similar approach for QNX.
I needed to apply the following patch:
Now the build script looks like this:
That looks pretty scary! That’s because Qt’s CMake files do not track dependencies when built in static mode.
Until Qt fixes their CMake files, we could just do the following:
Now the build script looks like this:
That’s more like it!
cmake-gui builds and links fine now. In order to run it on the VM, I need to have sftp / ssh access. This is done by running vi /etc/ssh/sshd_config
and change # PermitRootLogin no to PermitRootLogin yes.
After deployment and running /etc/graphics-startup.sh I was able to run /root/installdir/bin/cmake-gui, but then got these nice warnings:
This can be fixed in two ways, either set QT_QPA_FONTDIR environment variable to /usr/share/fonts, or create a symlink like:
And now I can present this beautiful screenshot:
Let me see you stripped!
CMake when it uses GCC/Clang it builds binaries unstripped, with debug information. Let’s see how big the above resulted binaries are:
CMake does have in the CMakeCache.txt an entry called CMAKE_STRIP, which is the case of the original QNX toolchain is set to /usr/bin/strip, because
CMake’s share/cmake-3.13/Modules/CMakeFindBinUtils.cmake has a bug for QNX, it can’t determine the ${_CMAKE_TOOLCHAIN_PREFIX} variable!
This is the reason why the original QNX toolchain had entries to ar and ranlib utilities.
My toolchain simply works, because the GNU GCC detection mechanism of ${_CMAKE_TOOLCHAIN_PREFIX} still applies!
But how can we use CMAKE_STRIP? Well, CMake has an undocumented target named install/strip!
Unfortunately QCC compiler wrapper doesn’t forward this flag to GCC , fortunately my toolchain file makes this possible, since we’re using directly the GCC compiler!
Let’s build a normal Debug build with this script:
The builddir and installdir sizes were:
Now let’s enable all the fancy debug build flags:
I searched after the presence of dwo files. This works starting with QNX 7.0!
The builddir and installdir sizes have become:
That’s like 50% size reduction for builddir, and 72% size reduction for installdir!
Need for speed
Remember how QCC is a wrapper for GCC, when coupled with ccache you should make sure that you have direct hits and not preprocessed ones!
This can lead to 30% speed degradation, depending on your QNX toolchain and ccache usage.
This version of the build script enables ccache, and since we use GCC directly we should mostly get direct hits:
The statistics were:
I don’t know why I had 4 preprocessed cache hits
Qt Creator Integration
Qt Creator has had some problems with the QNX / CMake integration. For example these bugs:
The good news is that with the GCC toolchain file these bugs are no longer reproduceable!
Devil is in the details
If we have a closer look at what CMake compiler detection cmake file (builddir/CMakeFiles/3.13.0/CMakeCXXCompiler.cmake) contains for the
CMAKE_CXX_IMPLICIT_LINK_LIBRARIES, we can see that there is a difference between the original QNX toolchain file and my own. It’s mainly about libgcc.a.
Luckily CMake can be configured to adjust to this, and my toolchain file is a bit more complicated
If you want an ARM 64 version, just change these two lines:
I hope you have enjoyed this C++ compilation ride in the world of the exotic operating system that is QNX!