Cristian Adam

WSLg and Qt Creator

For the CMake presets feature presentation in Qt Creator 9 I needed a cross platform Windows and Linux screencast.

My Windows Arm64 laptop was the perfect platform for the use case of registering a CMake preset with a self built Qt.

Quickly I found out that I only had one option to run Qt Creator as a Linux application, and that’s via Ubuntu 22.04 running under Windows Subsystem For Linux GUI (WSLg).

That’s because there is no Virtual Box or VMware Player running on Windows Arm64.

Also I’ve tried using Hyper-V, which WSLg under the hood uses, but the Ubuntu 22.04 image wouldn’t boot.

WSL2 and WSLg was the way to go! I’ve installed Qt Creator via sudo apt install qtcreator and then started Qt Creator via the Windows shortcut named Qt Creator (Ubuntu-22.04)! This is a short cut for C:\Windows\System32\wslg.exe ~ -d Ubuntu-22.04 qtcreator

Qt Creator would look like this:

It’s very hard not to notice that the windows title bar looks a bit weird. The generic window icon, the mouse cursor that does strange theme changes, and the bit fat window borders!

My goal was to have Qt Creator 9 look similar on Windows 11 as a native Windows Arm64 application and as native Ubuntu 22.04 Linux application running with WSLg.

Windows Arm64 - Samsung Galaxy Book Go 5G

We all know the Arm CPU architecture from smartphones, which have a long battery life and passive cooling.

Apple has shown with the M1/2 laptops that you can have a laptop that kicks ass with an Arm CPU.

In November 2021 I had a look to see if there was something like that for Windows.

I found a handful of models. Microsoft Surface Pro X, Lenovo Flex 5G, Acer Spin 7 at prices between 1000 - 1500$, and lastly Samsung Galaxy Book Go 5G at 800$ (400$ on eBay).

Samsung Galaxy Book Go

In Germany I could only buy the Samsung Galaxy Book Go “European” LTE version. Which came with a Qualcomm Snapdragon (TM) 7c Gen 2 CPU, 4GB of RAM and 128GB SSD.

I bought a refurbished model for 300€.

I took 7zip and run 7z -b to benchmark for arm64, x86_64 and x86. The results are here, below you have the arm64 results:

C:\Program Files (Arm)\7-Zip>7z b

7-Zip 21.04 beta (arm64) : Copyright (c) 1999-2021 Igor Pavlov : 2021-11-02

Windows 10.0 22000
ARM64 0 805.D0E cpus:8 128T f:804EB8C1004
LE

1T CPU Freq (MHz):  1931  2549  2550  2493  2488  2549  2545
4T CPU Freq (MHz): 346% 1903   354% 1952

RAM size:    3659 MB,  # CPU hardware threads:   8
RAM usage:   1779 MB,  # Benchmark threads:      8

                       Compressing  |                  Decompressing
Dict     Speed Usage    R/U Rating  |      Speed Usage    R/U Rating
         KiB/s     %   MIPS   MIPS  |      KiB/s     %   MIPS   MIPS

22:      12741   678   1828  12395  |     194291   705   2349  16568
23:      12388   722   1749  12622  |     185160   687   2333  16017
24:      11760   729   1735  12645  |     187951   720   2290  16491
25:      11119   753   1686  12696  |     185261   739   2232  16484
----------------------------------  | ------------------------------
Avr:     12002   720   1750  12590  |     188166   713   2301  16390
Tot:             716   2025  14490

The numbers by themselves do not mean much, but let’s compare them with the Apple M1 results from 7-cpu.com:

CPU Compressing MIPS Decompressing MIPS
Qualcomm 7c Gen 2 12590 16390
Apple M1 48841 45484

That’s not that good, isn’t it? Also 4GB of RAM, and 128GB SSD with no means to upgrade, made the offering a bit uncool.

Another thing that I’ve noticed was the screen quality. It wasn’t at the same level as my previous Lenovo laptops. The colors would change depending how I moved my head.

Notebookcheck.net has an article named Samsung Galaxy Book Go in review: Silent office notebook (archive.org copy), and their conclusion:

A better display could have made the Samsung Galaxy Book Go a good and inexpensive notebook.

Speeding up C++ GitHub Actions using ccache

In my previous post Using GitHub Actions with C++ and CMake I have provided a GitHub Actions yaml configuration file for C++ projects using CMake.

Building a project on GitHub Actions means always a build from scratch, for any given change, big or small. This takes time and wastes resources unnecessarily.

GitHub provides a way of caching dependencies to speed up workflows. The total size of cached files per repository is 2 GiB.

By having a look at the examples of various programming languages we can see that this is meant to cache package manager dependencies e.g. pip for python, npn for node, or gradle for java.

But, as it turns out, the caching mechanism can be used to cache compilation artifacts.

Using GitHub Actions with C++ and CMake

In this post I am going to provide a GitHub Actions configuration yaml file for C++ projects using CMake.

GitHub Actions is a CI/CD infrastructure provided by GitHub. GitHub Actions currently offers the following virtual machines (runners):

Virtual environment YAML workflow label
Windows Server 2019 windows-latest
Ubuntu 18.04 ubuntu-latest or ubuntu-18.04
Ubuntu 16.04 ubuntu-16.04
macOS Catalina 10.15 macos-latest

Each virtual machine has the same hardware resources available:

  • 2-core CPU
  • 7 GB of RAM memory
  • 14 GB of SSD disk space

Each job in a workflow can run for up to 6 hours of execution time.

Unfortunately when I enabled GitHub Actions on a C++ project I was presented with this workflow:

./configure
make
make check
make distcheck

This is not something you can use with CMake though smile

Hello World

I am going to build the following C++ hello world program:

#include <iostream>

int main()
{
  std::cout << "Hello world\n";
}

With the following CMake project:

cmake_minimum_required(VERSION 3.16)

project(main)

add_executable(main main.cpp)

install(TARGETS main)

enable_testing()
add_test(NAME main COMMAND main)

TL;DR see the project on GitHub.

Building multiple configurations with CMake in one go!

Coming from other build systems to CMake one will quickly learn that CMake can build only one configuration at a time. In practice you need to set up multiple build directories and configure/build with CMake for each and every one.

Autotools can do static and shared builds of libraries. For CMake most of the project would do a static build, then a shared build by setting the CMake variable BUILD_SHARED_LIBS to ON.

QMake can do debug and release builds at the same time, and as we can read at Qt for Android better than ever before, it can configure multiple Android architecture configurations at the same time.

What can we do to get the same level of convenience with CMake?

Bundling together static libraries with CMake

In this article I’m going to talk about building a C++ library with CMake, but it won’t be a CMake tutorial.

Let’s say you have a C++ library which depends upon a few open source libraries, which have a CMake project structure, but not necessarily done by the book (which means that they get only get built, and not deployed / installed)

Your library will include tests (unit-tests / integration tests), and the deployment can be just packing the headers and the binaries together in a tar.gz file.

This is not necessarily by the book, but it will do the job, and it could fit into any build system that the client has.

A book that one can use to do CMake right is Profesional CMake. Awesome CMake also has a great list of resources regarding CMake.

Coming back to the C++ library, which decisions do we take to build it? Shared library, static library, both?

Speeding up libclang on Windows

In this article I am revisting an article from three years ago: “Speeding up libclang on Windows”, in which I was having a look at how the experimental Clang Code Model was handling a particular source code file.

With the help of Profile Guided Optimization I was able to go down from 10 seconds to 6 seconds.

In the meantime the Clang Code Model has been enabled by default in Qt Creator 4.7.

Three years ago I tested Qt Creator 3.6.0, Qt 5.5.1, LLVM/Clang 3.6.2, MinGW GCC 5.3.0, Visual C++ 2013/5. I tested on a Lenovo W510 Thinkpad with an “Intel(R) Core (TM) i7 CPU M 620 @ 2.67 GHz” CPU.

Now I am going to test Qt Creator 4.8.2, Qt 5.12.2, LLVM/Clang 7.0.1, MinGW GCC 7.3.0, and Visual C++ 2017. I upgraded my laptop to a Lenovo A485 Thinkpad with an “AMD Ryzen 7 Pro 2700U w/ Radeon Vega Mobile Gfx 2.20 GHz” CPU.

How many seconds would it take libclang to parse the file? TL;DR? 3 seconds!

Modifying the default CMake build types

CMake has for single configuration configurators the following build types (configuration):

  • Empty (Qt Creator wrongly refers to this as “Default”)
  • Debug
  • Release
  • RelWithDebInfo – Release with debug information, needed for profiling / post mortem debugging
  • MinSizeRel – Release optimized for size, and not for speed.

If we have a look at CMake’s Modules/Compiler/GNU.cmake we can see:

  # Initial configuration flags.
  string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
  string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g")
  string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Os -DNDEBUG")
  string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3 -DNDEBUG")
  string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG")

The empty build type usually contains the common build flags for all build types. It is generated from the CMAKE_C_FLAGS_INIT / CMAKE_CXX_FLAGS_INIT variables, and the CFLAGS / CXXFLAGS system environment variables.

But in the case of an IDE like Qt Creator makes no sense to have, you will end up for GCC with a -O0 (Debug) build. I’ve opened QTCREATORBUG-22013 in this regard.

CMake uses the CMAKE_<LANG>_FLAGS_<CONFIG>_INIT variables which will be used to populate the CMAKE_CMAKE_<LANG>_FLAGS_<CONFIG> variables.

There are cases when you might want to change the default build types:

  • Want to have -g1 for RelWithDebInfo, because your binaries are becoming too big
  • Want to improve build times in Debug mode with -gsplit-dwarf
  • Want to link to a different version of the CRT
  • Want to enable all possible warnings from the compiler

Lastly, we want to do all this without putting if clauses in the code, and manually changing the CMAKE_<LANG>_FLAGS variables. The rule of thumb is: if you have to change compiler flags, you should do it in a toolchain file!

A Better QNX CMake Toolchain File

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(sweat_smile) 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!

Speeding up CMake

At the beginning of this year Bits’n’Bites wrote an article named Faster C++ builds, in which it’s being described how you can accelerate building LLVM using ninja, using a cache etc.

The following excerpt caught my eye:

For most developers, the time it takes to run CMake is not really an issue since you do it very seldom. However, you should be aware that for CI build slaves in particular, CMake can be a real bottleneck.

For instance, when doing a clean re-build of LLVM with a warm CCache, CMake takes roughly 50% of the total build time!

So I decided to build LLVM 4.0.0 (and clang) on my 2011 Core i7 Lenovo W510 laptop and see if I can reproduce his findings.