CMake Port/Porting Guide

From Qt Wiki
Jump to navigation Jump to search

Porting Notes

General porting guide

There is a python script called pro2cmake.py in qtbase/cmake/utils.

It takes a .pro file as input, and generates a CMakeLists.txt file in the same folder. You need to have python3 installed and a few packages from pip (pyparsing, sympy) to use the script.

Example:

python3 qtbase/util/cmake/pro2cmake.py qtbase/src/corelib/corelib.pro

The script can handle .pro files that add modules, plugins, examples, tests, and partial support for .pro files that just include other .pro files (subdirs).

The script does a good chunk of the conversion process for you, but you'll sometimes need to do manual fixes to the file. Make sure to mark those manual changes with a "# special case" marker. Example:

SOURCES
 foo.cpp
 bar.cpp # special case

This way when you re-run the script, you won't lose your manual modifications. You can also use block special case markers:

# special case begin
LIBRARIES
  Qt::Gui
# special case end

There is also another script called run_pro2cmake.py which runs the first script recursively on all .pro files in the given folder. A good place to use it would be on the examples folder, or on the whole repository you are porting: Example:

python3 qtbase/util/cmake/run_pro2cmake.py qtbase/examples
python3 qtbase/util/cmake/run_pro2cmake.py qtsvg

If a directory has a configure.json, you'll want to run a script called configurejson2cmake.py to generate a configure.cmake file. These files should not be modified manually, but rather the script should be fixed to handle your specific case.

python3 qtbase/util/cmake/configurejson2cmake.py qtbase/src/corelib

Porting a new repository

  • Request a wip/cmake branch for your repository from the dev branch
  • Copy the root CMakeLists.txt file from either qtsvg/CMakeLists.txt or qtimageformats/CMakeLists.txt into the root of your repository
  • Change the project name and description
  • Adjust the find_package() calls to import the required Qt Components (Core, Gui, Widgets, Test, Network, Xml, etc.) and make sure BuildInternals component is listed as well
  • Run either pro2cmake.py individually or run_pro2cmake.py on the whole repo.
  • Try to build it against an installation of qtbase, for example:
cmake ../qtsvg -DQT_USE_CCACHE=1 -GNinja -DCMAKE_INSTALL_PREFIX=/home/foo/qt/qt5_cmake/qtbase_installed && ninja
  • Fix something in the CMakeLists.txt file and rebuild again

General info

The Qt CMake port uses custom CMake macros and functions that wrap regular functions like add_executable / add_library, etc. You should prefer to use them over the CMake ones, unless strictly necessary.

Modules like Gui or Widgets are created in CMake with add_qt_module.

Plugins with add_qt_plugin.

Tools with add_qt_tool.

Tests with add_qt_test.

Examples with add_qt_executable (consistent, right?).

3rd party packages should be found using qt_find_package() instead of find_package(), and you should specify the targets that the package provides with the PROVIDED_TARGETS option. You can grep that token for examples.

Most of the macros and common CMake functionality are in the files QtBuild.cmake and QtFeature.cmake under qtbase/cmake.

There are also custom Find modules that are used by qt_find_package(), for 3rd party projects that do no provide their own Find modules or Config files. It's very probably you'll have to write many of these by yourself for libraries that are defined in configure.json.

Tools

Feature system

Developer builds

When porting a new repo, it might be a hassle to get a changed qtbase file for your own repo module, because you first need to make install qtbase. You can configure your qtbase build with -DFEATURE_developer_build=ON, and then you don't have to install anything, only run make / ninja. To build another repo against such a qtbase, pass the build directory of qtbase as the CMAKE_INSTALL_PREFIX, e.g.:

cmake ../qtsvg -DQT_USE_CCACHE=1 -GNinja -DFEATURE_developer_build=ON -DCMAKE_INSTALL_PREFIX=/home/foo/qt/qt5_cmake/qtbase_built && ninja

Common qmake <-> CMake constructs

qmake CMake
qtHaveModule(foo) if(TARGET Qt::foo)
qtConfig(foo) if (QT_FEATURE_foo)
QT += widgets find_package(Qt5 COMPONENTS Widgets) target_link_libraries(my_lib PRIVATE Qt::Widgets)
LIBS += zlib target_link_libraries(my_target PRIVATE ZLIB::ZLIB)
find a 3rdparty package qt_find_package(Cups REQUIRED PROVIDED_TARGETS Cups::Cups)