Creating Simple Installers with CPack

In my recent post Benefits of a Relocatable Qt, I explained how to relocate Qt from a build server to a developer PC and from the PC to an embedded system. Qt is installed in three different locations. My solution has two small deficiencies. First, it sets the install rpath to an absolute path and restricts the installation to this absolute path. Second, it forces us to create a tarball of the installation directory on the PC manually. Let us fix these two deficiencies.

Relative Install Rpaths

The line

set(CMAKE_INSTALL_RPATH /home/user/kea/qt/lib)

in the file RelocatableQt/CMakeLists.txt sets the install rpath to the absolute path /home/user/kea/qt/lib. Hence, we can only install Qt in exactly this directory. If we install Qt somewhere else, the application will not find the Qt libraries.

This is often OK for an embedded system, because the installation location for applications and libraries is fixed. However, this is not OK, if we want to pass Qt applications to other developers or to selected users for early feedback.

If we want others to run our Qt application on their PCs, we cannot expect them to install the Qt application in the location of our choice. We want to allow them to install the Qt application in any location. The installation directory structure looks as follows.

/user/chosen/path
    bin
        SimpleApp
    qt
        lib
        ...

We achieve this location independence by defining CMAKE_INSTALL_RPATH relative to the directory of the application executable denoted by $ORIGIN.

set(CMAKE_INSTALL_RPATH $ORIGIN $ORIGIN/../qt/lib)

The runtime linker replaces $ORIGIN by the application directory /user/chosen/path/bin. It searches for shared libraries in the directories /user/chosen/path/bin and /user/chosen/path/bin/../qt/lib.

Let’s try out whether we can install the application and the Qt libraries whereever we want. We create a tarball of the subdirectory final of the build directory.

$ cd ~/Work/embeddeduse/BlogPosts/build-RelocatableQt-Desktop_Relocatable_Qt_5_14_1_64bit-Release/
$ tar czf ~/Work/simple-app.tgz final

We pass the tarball to Alice, who is a power user happy to alpha-test our application. Alice unpacks the tarball in the slightly unusual installation directory ~/Work/yoyo.

$ mkdir -p ~/Work/yoyo
$ cd ~/Work/yoyo
$ tar xf /path/to/simple-app.tgz --strip-components=1
$ ls *
bin:
SimpleApp

qt:
lib  phrasebooks  plugins  qml  translations

Alice can run our application from anywhere with the command

$ ~/Work/yoyo/bin/SimpleApp &

Alice could also execute all the above steps from the File browser.

Note that running the application from QtCreator will fail. By default, QtCreator runs the executable produced by the build step. This executable contains a sequence of colons instead of an rpath. The install step replaces the colons by the relative rpaths.

We can add a custom executableas a new Run configuration Final SimpleApp on Project > Build & Run > Run Settings > Run. We set Executable to

/home/burkhard/Work/embeddeduse/BlogPosts/build-RelocatableQt-Desktop_Relocatable_Qt_5_14_1_64bit-Release/final/bin/SimpleApp

and rename the configuration from Custom Executable to Final SimpleApp. Now, we can run the new configuration Final SimpleApp from QtCreator by pressing Ctrl+R.

Simple Installers

In the previous section, we still created the tarball manually. CPack, which comes with CMake, can do the packaging for us. We must add the following lines to RelocatableQt/CMakeLists.txt before calling add_executable.

set(CPACK_PACKAGE_NAME "SimpleApp")
set(CPACK_PACKAGE_VENDOR "MyComp")
set(CPACK_VERBATIM_VARIABLES true)
set(CPACK_PACKAGE_VERSION_MAJOR 0)
set(CPACK_PACKAGE_VERSION_MINOR 2)
set(CPACK_PACKAGE_VERSION_PATCH 0)
include(CPack)

We should set the package name and the versions as they appear in the names of the generated packages and as they help to distinguish different packages. Setting CPACK_VERBATIM_VARIABLES to true ensures that contents written to the CPack configuration files is escaped properly.

When we package for a product release, we should also set the variables

CPACK_PACKAGE_VENDOR
CPACK_PACKAGE_DESCRIPTION_SUMMARY
CPACK_PACKAGE_DESCRIPTION_FILE
CPACK_RESOURCE_FILE_WELCOME
CPACK_RESOURCE_FILE_LICENSE
CPACK_RESOURCE_FILE_README

These variables are not needed for our toy project.

Finally, RelocatableQt/CMakeLists.txt must include the CPack module with include(CPack). CMake uses the CPack module to generate the configuration files CPackConfig.cmake and CPackSourceConfig.cmake.

Based on these configuration files, CPack produces its output. We create a gzipped tarball and a self-extracting archive with the command.

$ cpack -C "Release" -G "STGZ;TGZ"

The command is executed in the build directory. It produces the two files SimpleApp-0.2.0-Linux.sh and SimpleApp-0.2.0-Linux.tar.gz. The tarball SimpleApp-0.2.0-Linux.tar.gz is nearly the same as simple-app.tgz we created manually before. The difference is that the auto-generated tarball suffixes each entry with SimpleApp-0.2.0-Linux, whereas the manually generated tarball uses final. Alice can install SimpleApp-0.2.0-Linux.tar.gz in the same way as she installed simple-app.tgz.

Alice receives the self-extracting archive SimpleApp-0.2.0-Linux.sh on a USB drive. She copies the installer from the USB drive to her ~/Downloads directory and makes it executable. She creates the directory ~/Work/yoyo, in which she wants to install the application, changes into this directory and runs the shell script. The shell script requires her to answer three questions.

$ ~/Downloads/SimpleApp-0.2.0-Linux.sh 
SimpleApp Installer Version: 0.2.0, Copyright (c) MyComp
This is a self-extracting archive.
The archive will be extracted to: /home/burkhard/Work/yoyo

If you want to stop extracting, please press <ctrl-C>.
LICENSE
=======

This is an installer created using CPack (https://cmake.org). No license provided.



Do you accept the license? [yN]: 
y
By default the SimpleApp will be installed in:
  "/home/burkhard/Work/yoyo/SimpleApp-0.2.0-Linux"
Do you want to include the subdirectory SimpleApp-0.2.0-Linux?
Saying no will install in: "/home/burkhard/Work/yoyo" [Yn]: 
n

Using target directory: /home/burkhard/Work/yoyo
Extracting, please wait...

Unpacking finished successfully

As of CMake version 3.10.2, installation with the self-extracting archive is more complicated than with the tarball. Version 3.10.2 is, however, over two years old. I don’t know whether the shell script of the self-extracting archive has improved or whether the script is customisable by now. If not, I would advise against using it.

The tarball generated by CPack is enough to implement an updater for Qt applications on embedded systems. But that’s a topic for another post.

Getting the Source Code

You can get the source code from Github with the command

$ git clone https://github.com/bstubert/embeddeduse.git

You find the example code in the directory

$ cd embeddeduse/BlogPosts/RelocatableQt

Also Interesting

This post is a follow-up of my earlier post Benefits of a Relocatable Qt. It fixes two deficencies of the earlier post.

Chapters 25 Installing and 26 Packaging of Craig Scott’s excellent book Professional CMake – A Practical Guide (5th edition) helped me a lot in writing this post.

Scroll to top