Setting up QtCreator for cross-compilation with CMake took me 15-20 hours the first two or three times. The next half a dozen times took me 4 hours on average. The last two times took me 5 minutes – using the script presented in this post. I can cross-compile the Qt application for my embedded device and run the Qt application on the device with one button press in QtCreator.
Users of the commercial Qt for Device Creation license have been enjoying this fast and proper QtCreator setup for several years now. The script in this post is the first time that (L)GPLv3 users of Qt can enjoy the same convenience.
Prerequisites
You have built a Linux image and an SDK for an embedded device with Yocto. For this post, I built the SDK for the reference image tdx-reference-multimedia-image of the Verdin i.MX8M Mini board from Toradex. You can log into the board with SSH using a username and password.
You should use a QtCreator version not older than 4.11 and a CMake version not older than 3.14. Using the latest QtCreator and CMake versions has never caused me any problems. So, I suggest you do the same. In the unlikely event that you must use older versions, I explain a workaround in my post Deploying Qt Projects to Embedded Devices with CMake.
Download the script configure-qtcreator.sh
, install it in a directory from $PATH
and make it executable.
$ wget https://raw.githubusercontent.com/bstubert/embeddeduse/master/BlogPosts/qtcreator-setup/configure-qtcreator.sh
$ mv configure-qtcreator.sh $HOME/bin
$ chmod a+x $HOME/bin/configure-qtcreator.sh
The script generates the Qt Creator configuration files, which QtCreator displays in the dialog Tools | Options | Kits. The script works for any SDK built with Yocto.
Setting Up QtCreator in 5 Minutes
You choose a name for the QtCreator kit. My kit name is
NAME = Goldfinger
QtCreator uses this name to mark the compiler, Qt version, debugger, CMake version and device as belonging to this kit.
The Yocto SDK is installed in $SDK_DIR_PATH
and contains the environment setup file, which sets Linux environment variables like OECORE_*
, CXX
and CXXFLAGS
needed for cross-compilation against the SDK. My settings look as follows:
SDK_DIR_PATH = /private/Projects/Spectre/verdin-dunfell/sdk
ENV_SETUP_FILE_PATH = $SDK_DIR_PATH/environment-setup-aarch64-tdx-linux
The QtCreator version, for which you generate the configuration files, is located in $QT_CREATOR_DIR_PATH
, which contains the subdirectories bin
and libexec
. My settings are
QT_CREATOR_DIR_PATH = /home/burkhard/Qt/Qt5.15.2/Tools/QtCreator
$DEVICE
(verdin-imx8mm.local
for me) is the name or IP address of the device, on which the Qt application will be running. The call
$ ssh $DEVICE
should allow you to log in to the target device. Once set up, QtCreator will deploy the Qt application to $DEVICE
and run it on the $DEVICE
.
Close QtCreator and call the script configure-qtcreator.sh
:
$ configure-qtcreator.sh --name $NAME --env-setup $ENV_SETUP_FILE_PATH \
--creator-base $QT_CREATOR_DIR_PATH --device $DEVICE
The script generates two CMake toolchain files – Goldfinger.cmake
and OEQt5Toolchain.cmake
– in the directory
$SDK_DIR_PATH/sysroots/x86_64-tdxsdk-linux/usr/share/cmake/OEToolchainConfig.cmake.d
Goldfinger.cmake
is a normal CMake toolchain file and sets the variables for the C++ compiler, the linker and the system root among others. OEQt5Toolchain.cmake
fixes a long-standing bug in the CMake files of the Qt libraries.
The script also generates a couple of QtCreator configuration files – profiles.xml
, qtversion.xml
, toolchain.xml
, debuggers.xml
, cmaketools.xml
and devices.xml
– in the directory
$QT_CREATOR_DIR_PATH/share/qtcreator/QtProject/qtcreator
It is now time to restart QtCreator. When started, QtCreator merges these configuration files with their counterparts in $HOME/.config/QtProject/qtcreator
. When you open the dialog Tools | Options | Kits | Kits, you’ll see the new auto-detected kit Goldfinger.
QtCreator auto-detected the configurations for the Device Goldfinger, the sysroot, the C compiler GCC (Goldfinger), the C++ compiler (Goldfinger), the debugger GDB Goldfinger, the Qt version Goldfinger, the CMake tool CMake Goldfinger, the CMake generator and the CMake configuration. You can inspect these configurations by clicking through the tab pages. If you want to change the disabled configurations, you must clone them.
One manual post-processing step is required: creating and deploying a public key on the device. Go to Tools | Options | Devices, select the Device Goldfinger, press the Create | New for Private key file and press the Deploy Public Key button. You can test your setup by pressing the Test button. I have described the setup of a device in detail in my post Docker Builds from QtCreator.
You are now able to cross-build your Qt application against the Yocto SDK. To run the Qt application on the device, you adapt the deployment and run settings as described in my post Cross-Compiling Qt Embedded Applications with QtCreator and CMake.
CMake Toolchain Files
The Yocto SDK comes with a CMake toolchain file $ORIG_TOOLCHAIN_FILE
, where
TOOLCHAIN_DIR = $SDK_DIR_PATH/sysroots/x86_64-tdxsdk-linux/usr/share/cmake/
ORIG_TOOLCHAIN_FILE = $TOOLCHAIN_DIR/OEToolchainConfig.cmake
You could source the environment setup file $ENV_SETUP_FILE_PATH
of the Yocto SDK in a Linux terminal and start QtCreator from the same terminal. This approach has two problems.
- It will only work, if you explicitly set the variable
OE_QMAKE_PATH_EXTERNAL_HOST_BINS
in the CMake toolchain file. This is a long-standing bug Qt’s CMake files from Yocto 2.x, which unfortunately made it into Yocto 3.x. - You cannot switch kits in QtCreator without restarting QtCreator in another terminal. The original toolchain file reads the environment variables (e.g.,
$ENV{CFLAGS}
) set in the environment setup script.
The script configure-qtcreator.sh
solves these two problems by generating a CMake toolchain file for each problem. It generates $QT5_TOOLCHAIN_FILE
for the first problem and $KIT_TOOLCHAIN_FILE
for the second problem, where
QT5_TOOLCHAIN_FILE = $TOOLCHAIN_DIR/OEToolchainConfig.cmake.d/OEQt5Toolchain.cmake
KIT_TOOLCHAIN_FILE = $TOOLCHAIN_DIR/OEToolchainConfig.cmake.d/Goldfinger.cmake
$ORIG_TOOLCHAIN_FILE
includes all the *.cmake
files from the subdirectory OEToolchainConfig.cmake.d
at the end.
file( GLOB toolchain_config_files "${CMAKE_TOOLCHAIN_FILE}.d/*.cmake" )
foreach(config ${toolchain_config_files})
include(${config})
endforeach()
If you didn’t source the environment setup file, the command
set( CMAKE_C_FLAGS $ENV{CFLAGS} CACHE STRING "" FORCE )
from $ORIG_TOOLCHAIN_FILE
will assign the empty string to CMAKE_C_FLAGS
. The $KIT_TOOLCHAIN_FILE
overwrites CMAKE_C_FLAGS
with the command
set( CMAKE_C_FLAGS " -O2 -pipe -g -feliminate-unused-debug-types "
CACHE STRING "" FORCE )
$KIT_TOOLCHAIN_FILE
replaces all the environment variables from $ORIG_TOOLCHAIN_FILE
with the values of these environment variables. Otherwise, the toolchain files are the same.
$QT5_TOOLCHAIN_FILE
sets the CMake variable OE_QMAKE_PATH_EXTERNAL_HOST_BINS
to its correct value. If this variable is not set, the CMake files for the Qt modules will be skipped with the message “WARNING Skipping because OE_QMAKE_PATH_EXTERNAL_HOST_BINS is not defined”.
QtCreator Configuration Files
The options --name
, --env-setup
and --creator-base
of the script configure-qtcreator.sh
are mandatory. The example call included the option --device $DEVICE
to generate a device configuration. If you already have a device configuration, you leave out the option.
The default ABI flavour is arm-linux-poky-elf-64bit
. If you had a 32-bit device, you’d pass the option --device arm-linux-poky-elf-32bit
. The ABI flavour is shown in QtCreator’s compiler settings Tools | Options | Kits | Compilers.
The script configure-qtcreator.sh
first removes the configurations from the QtCreator configuration files and then adds the new configurations. If you pass the option --remove
, the script will only remove configurations.
The script configure-qtcreator.sh
uses the QtCreator utility sdktool
to remove and add configurations. The utility is located in
SDKTOOL = $QT_CREATOR_DIR_PATH/libexec/qtcreator/sdktool
It reads the XML configuration files (e.g., toolchains.xml
, profiles.xml
) from the directory $QT_CREATOR_DIR_PATH/share/qtcreator/QtProject/qtcreator
, removes or adds sections and writes the modified XML files. When restarted, QtCreator reads these XML files, adds a unique ID and merges the configurations with those from $HOME/.config/QtProject/qtcreator
.
The command $SDKTOOL --help
lists all the available add and remove operations. The command $SDKTOOL --help <operation>
shows help for a specific operation like addTc
and rmTC
. You will not find sdktool
mentioned even once in the Qt documentation. The source code provides the only other source of information. The rest is trial and error.
The script configure-qtcreator.sh
needs two sdktool
calls to remove any configuration.
# BASEID = byos.Goldfinger.5.14.2
# CREATOR_CONFIG_DIR = $HOME/.config/QtProject/qtcreator
${SDKTOOL} rmQt --id ${BASEID}.qt 2>/dev/null || true
${SDKTOOL} --sdkpath=${CREATOR_CONFIG_DIR} rmQt --id ${BASEID}.qt 2>/dev/null || true
The first call removes the Qt version from
$QT_CREATOR_DIR_PATH/share/qtcreator/QtProject/qtcreator/qtversion.xml
The second call removes the Qt version from
$HOME/.config/QtProject/qtcreator/qtversion.xml
Note that the option --sdkpath=<path>
cannot be rewritten as --sdkpath <path>
like all the other options. sdktool
would fail with a meaningless message. All the other options must have the format --name <value>
.
Adding a configuration requires only one sdktool
call. For example, a new Qt version is added with this sdktool
command:
# BASEID = byos.Goldfinger.5.14.2
# NAME = Goldfinger
${SDKTOOL} addQt --id "${BASEID}.qt" --name "${NAME}" \
--type "Qdb.EmbeddedLinuxQt" --qmake "$(type -p qmake)"
This command adds the Qt version to the file
$QT_CREATOR_DIR_PATH/share/qtcreator/QtProject/qtcreator/qtversion.xml
When restarted, QtCreator adds an ID to the Qt version and merges it into the file
$HOME/.config/QtProject/qtcreator/qtversion.xml
I figured out the type Qdb.EmbeddedLinuxQt
by looking up the Qt version of a manually created configuration.
All the configurations show up as auto-detected in the QtCreator dialog Tools | Options | Kits. You would have to change the source code of sdktool
, which hard-wires auto-detect to true. It is not enough to change the auto-detect property to false in the XML configuration files. QtCreator changes the value back to true on the next restart.
Conclusion
When you install a commercial Boot2Qt edition, the Qt installer creates the CMake toolchain files missing from the Yocto SDK, guides you through setting up a device and generates the QtCreator configuration files. When you start QtCreator after the installation, you are ready to cross-build your Qt application. You don’t have to setup the kit and its parts manually in QtCreator.
Most of the magic comes from the original configure-qtcreator.sh script. I added the generation of the CMake toolchain files and made sure that all parts of a generated kit get removed. My modified configure-qtcreator.sh script provides you with the same convenience as the installer of the commercial Boot2Qt versions. It enables you to cross-build your Qt application for your device and run them on the device within 5 minutes!