Deploying to Linux with CMake
December 22, 2022 by Jörg Bornemann | Comments
A while ago, I blogged about our CMake deployment API that allows you to enhance the cmake --install
step with instructions that deploy Qt libraries, plugins and assets. At the time of writing, Linux was not supported yet. But not anymore: Qt 6.5 comes with deployment support for Linux!
Quick recap how it looks like to deploy a simple Qt application. Consider the following project.
cmake_minimum_required(VERSION 3.22)
project(MyApp)
find_package(Qt6 REQUIRED COMPONENTS Widgets)
qt_standard_project_setup()
qt_add_executable(MyApp main.cpp)
target_link_libraries(MyApp PRIVATE Qt::Widgets)
Now, we install the application and enhance the installation step. Our goal is to have a (mostly) self-contained directory after installation.
# Install the executable into "${CMAKE_INSTALL_PREFIX}/bin".
install(TARGETS MyApp
BUNDLE DESTINATION .
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
# Generate the deployment script for the target MyApp.
qt_generate_deploy_app_script(
TARGET MyApp
FILENAME_VARIABLE deploy_script
NO_UNSUPPORTED_PLATFORM_ERROR
)
# Call the deployment script on "cmake --install".
install(SCRIPT ${deploy_script})
We build and install the project:
$ qt-cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/tmp/my-application ..
[output omitted]
$ cmake --build .
[output omitted]
$ cmake --install .
-- Install configuration: "Release"
-- Installing: /tmp/my-application/bin/myapp
-- Set runtime path of "/tmp/my-application/bin/myapp" to "$ORIGIN:$ORIGIN/../lib"
-- Writing /tmp/my-application/bin/qt.conf
-- Running generic Qt deploy tool on /home/someone/playground/myapp/build/myapp
-- Installing: /tmp/my-application/lib/libQt6Core.so.6
-- Installing: /tmp/my-application/lib/libQt6Core.so.6.6.0
-- Installing: /tmp/my-application/lib/libQt6DBus.so.6
-- Installing: /tmp/my-application/lib/libQt6DBus.so.6.6.0
-- Installing: /tmp/my-application/lib/libQt6EglFSDeviceIntegration.so.6
-- Installing: /tmp/my-application/lib/libQt6EglFSDeviceIntegration.so.6.6.0
-- Installing: /tmp/my-application/lib/libQt6EglFsKmsSupport.so.6
-- Installing: /tmp/my-application/lib/libQt6EglFsKmsSupport.so.6.6.0
-- Installing: /tmp/my-application/lib/libQt6Gui.so.6
-- Installing: /tmp/my-application/lib/libQt6Gui.so.6.6.0
-- Installing: /tmp/my-application/lib/libQt6OpenGL.so.6
-- Installing: /tmp/my-application/lib/libQt6OpenGL.so.6.6.0
-- Installing: /tmp/my-application/lib/libQt6Widgets.so.6
-- Installing: /tmp/my-application/lib/libQt6Widgets.so.6.6.0
-- Installing: /tmp/my-application/lib/libQt6XcbQpa.so.6
-- Installing: /tmp/my-application/lib/libQt6XcbQpa.so.6.6.0
-- Installing: /tmp/my-application/plugins/egldeviceintegrations/libqeglfs-emu-integrat...
-- Installing: /tmp/my-application/plugins/egldeviceintegrations/libqeglfs-kms-egldevic...
-- Installing: /tmp/my-application/plugins/egldeviceintegrations/libqeglfs-x11-integrat...
-- Installing: /tmp/my-application/plugins/imageformats/libqgif.so
-- Installing: /tmp/my-application/plugins/imageformats/libqico.so
-- Installing: /tmp/my-application/plugins/imageformats/libqjpeg.so
-- Installing: /tmp/my-application/plugins/xcbglintegrations/libqxcb-egl-integration.so
-- Installing: /tmp/my-application/plugins/xcbglintegrations/libqxcb-glx-integration.so
-- Installing: /tmp/my-application/plugins/platforms/libqxcb.so
After the myapp
executable is installed into /tmp/my-application/bin/
, the deployment script handles the following tasks:
- Create a
qt.conf
file next to the executable that contains information about the directory layout. This is needed at runtime to find the plugins and assets. See the qt.conf documentation for details. - Inspect the executable and used Qt plugins with CMake's built-in file(GET_RUNTIME_DEPENDENCIES) to determine which Qt libraries to deploy.
- Install the necessary Qt plugins and Qt libraries.
The installation directory can now be copied to a different machine, and the application should still work.
Packaging the installation folder
After installation, we have a nice self-contained directory that can be packaged and shipped. For the sake of example, we'll create a .deb
package using cpack
.
Add the following at the end of the project file:
set(CPACK_PACKAGE_NAME my-app)
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "My amazing application")
set(CPACK_PACKAGE_VENDOR "My Company")
set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME})
set(CPACK_VERBATIM_VARIABLES ON)
set(CPACK_PACKAGING_INSTALL_PREFIX "/opt/myapp")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Manfred Maintainer <mm@example.com>")
set(CPACK_DEBIAN_PACKAGE_DEPENDS libc6 libstdc++6 libgcc-s1)
include(CPack)
Re-configure the project and run cpack
:
$ cpack -G DEB
CPack: Create package using DEB
CPack: Install projects
CPack: - Install project: MyApp []
CPack: Create package
CPack: - package: /home/someone/projects/myapp/build/my_app-1.0-Linux.deb generated.
That's already it. The package has been wrapped and is ready to be shipped.
You can inspect the content of the package with dpkg -c my_app-1.0-Linux.deb
and install with
.
sudo dpkg -i my_app-1.0-Linux.deb
Summary
We have seen how to deploy a simple Qt application on Linux using Qt 6.5's CMake deployment API. There's no dedicated linuxdeployqt tool. The current solution wholly relies on CMake's built-in functionality.
These are the platforms that are covered by Qt's CMake deployment API:
- Windows
- macOS
- Linux
For Android and iOS there's still the need to call androiddeployqt / macdeployqt manually - or you let Qt Creator handle these details.
The relocatable installation folder can be conveniently wrapped into a package using tools like cpack
.
Please report any issues you find while playing with this at our bug tracker.
Blog Topics:
Comments
Subscribe to our newsletter
Subscribe Newsletter
Try Qt 6.9 Now!
Download the latest release here: www.qt.io/download.
Qt 6.9 is now available, with new features and improvements for application developers and device creators.
We're Hiring
Check out all our open positions here and follow us on Instagram to see what it's like to be #QtPeople.
Commenting for this post has ended.
Cmake is very verbose compare to qmale :-(
That's true. But to be fair, qmake never had such a deployment API in the first place ...
Yes, this is true.
This will be very helpful for SNAP, Flatpak and especially AppImage.
Awesome, well done. Using this in a recent project. Glad to hear I don't have to do something custom for linux
deb
is very cool! However what aboutAppImage
orrpm
?linuxdeployqt
can produce appimages.See https://cmake.org/cmake/help/latest/manual/cpack-generators.7.html for supported
cpack
generators.rpm
is supported,AppImage
is not part of the list. There is an issue regardingAppImage
CPack https://gitlab.kitware.com/cmake/cmake/-/issues/18782 with also a WIP patch https://gitlab.kitware.com/cmake/cmake/-/merge_requests/2645Thanks, this looks very promising!
FYI: there is linuxdeployqt, just not from Qt Group. It works more or less as windeployqt.