Using CMake to Build Qt Projects

 Qt comes with the QMake tool for handling cross platform building issues.However, there are other build systems available such as autotools, SCons andCMake. These tools meet different criterias, for example external dependencies.

When the KDE project shifted from Qt 3 to Qt 4 the project changed build toolfrom autotools to CMake. This has given CMake a special position in the Qtworld &emdash; both from the number of users point and from a featuresupport and quality point. Seen from a workflow point of view, Qt Creatorsupports CMake since version 1.1 (1.3 if you want to use a Microsoft toolchain).

A Basic Example

In this article we will focus on CMake itself, and how to use it in conjunctionwith Qt. To do this, let's start with an overview of a simple, but typicalCMake-based project. As you can tell from the listing below, the projectconsists of some source files and a text file.

$ ls
CMakeLists.txt
hellowindow.cpp
hellowindow.h
main.cpp

Basically, the CMakeLists.txt file replaces the projectfile used by QMake. Tobuild the project, create a build directory and run cmake and then make fromthere. The reason for creating a build directory is that CMake has been builtwith out-of-source building in mind from the very start. It is possible toconfigure QMake to place intermediate files outside the source, but it requiresextra steps. With CMake, it is the default.

$ mkdir build
$ cd build
$ cmake .. && make


CMake building a basic project.

The argument given to CMake refers to the directory where the CMakeLists.txtfile resides. This file controls the whole build process. In order to fullyunderstand it, it is important to recognize how the build process looks.The figure below shows how the user files: sources, headers, forms and resourcefiles are processed by the various Qt code generators before joining thestandard C++ compilation flow. Since QMake was designed to handle this flow, ithides all the details of this flow.


The Qt build system.

When using CMake, the intermediate steps must be handled explicitly. This meansthat headers withQ_OBJECT macros must be run through moc, user interface formsmust be processed by uic and resource files must pass through rcc.

In the example that we started with the world is slightly easier, though. It is limited to a single header file that needs to meet moc. But first, theCMakeLists.txt defines a project name and includes the Qt4 package as a required component.

PROJECT(helloworld)
FIND_PACKAGE(Qt4 REQUIRED)

Then all sources involved in the build process are assigned to two variables.The SET command assigns the variable listed first with the values that follow.The names,helloworld_SOURCES andhelloworld_HEADERS, is by convention. You canname them either way you like.

SET(helloworld_SOURCES main.cpp hellowindow.cpp)
SET(helloworld_HEADERS hellowindow.h)

Notice that the headers only include the headers that needs to be processed by moc. All other headers can be left out of the CMakeLists.txt file. This alsoimplicates that if you add aQ_OBJECT macro to any of your classes you must ensure that it is listed here.

To invoke moc, the macro QT4_WRAP_CPP is used. It assigns the names of the resulting files to the variable listed first. In this case the line looks as follows.

QT4_WRAP_CPP(helloworld_HEADERS_MOC ${helloworld_HEADERS})

What happens is that all headers are processed by moc and the names of theresulting source files are listed in thehelloworld_HEADERS_MOC variable. Again,the variable name is by convention rather than forced.

In order to build a Qt application, the Qt include directories needs to be added as well as a range of defines need to be set. This is handled through the commandsINCLUDE andADD_DEFINITIONS.

INCLUDE(${QT_USE_FILE})
ADD_DEFINITIONS(${QT_DEFINITIONS})

Finally, CMake needs to know the name of the resulting executable and what tolink it to. This is conveniently handled by by the commandsADD_EXECUTABLE and TARGET_LINK_LIBRARIES. Now CMake knows what to build, from what and through which steps.

ADD_EXECUTABLE(helloworld ${helloworld_SOURCES} 
    ${helloworld_HEADERS_MOC})
TARGET_LINK_LIBRARIES(helloworld ${QT_LIBRARIES})

When reviewing the listing above, it relies on a number of variables startingwith QT_. These are generated by the Qt4 package. However, as a developer, youmust explicitly refer to them as CMake is not build as tightly to suite Qt asQMake.

Adding More Qt

Moving beyond the initial example, we now look at a project with both resourcesand user interface forms. The resulting application will look quite similar toits predecessor, but all the magic takes place under the hood.

The CMakeLists.txt file start by naming the project and including the Qt4package - the complete file can be downloaded as a source code packageaccompanying this article. Then all the input files are listed and assigned totheir corresponding variables.

SET(helloworld_SOURCES main.cpp hellowindow.cpp)
SET(helloworld_HEADERS hellowindow.h)
SET(helloworld_FORMS hellowindow.ui)
SET(helloworld_RESOURCES images.qrc)

The new file types are then handled by QT4_WRAP_UI and QT4_ADD_RESOURCES. Thesemacros operate in the same ways asQT4_WRAP_CPP. This means that the resultingfiles are assigned to variable given as the left-most argument. Notice that theheader files generated by uic are needed as we need to build a dependencyrelationship between them and the final executable. Otherwise they will not becreated.

QT4_WRAP_CPP(helloworld_HEADERS_MOC ${helloworld_HEADERS})
QT4_WRAP_UI(helloworld_FORMS_HEADERS ${helloworld_FORMS})
QT4_ADD_RESOURCES(helloworld_RESOURCES_RCC ${helloworld_RESOURCES})

All the resulting files are then added as dependencies to the ADD_EXECUTABLEmacro. This includes the uic generated headerfiles. This establishes thedependency from the executable to the hellowindow.ui file through theintermediary ui_hellowindow.h header.

ADD_EXECUTABLE(helloworld ${helloworld_SOURCES} 
    ${helloworld_HEADERS_MOC} 
    ${helloworld_FORMS_HEADERS} 
    ${helloworld_RESOURCES_RCC})

Before this file can be used to build the project there is a small caveat tohandle. As all intermediate files are generated outside the source tree, theheader file generated by uic will not be located by the compiler. In order tohandle this, the build directory needs to be added to the list of include directories.

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})

With this line, all intermediary files will be available in the include path.

Qt Modules

Until now we have relied on the QtCore and QtGui modules. To be able to use moremodules, the CMake environment must be tuned to enable them. By setting them toTRUE using the SET command, the included modules can be controlled.

For instance, to enable OpenGL support add the following line to yourCMakeLists.txt.

SET(QT_USE_QTOPENGL TRUE)

The most commonly used modules are controlled using the following variables.

  • QT_USE_QTNETWORK
  • QT_USE_QTOPENGL
  • QT_USE_QTSQL
  • QT_USE_QTXML
  • QT_USE_QTSVG
  • QT_USE_QTTEST
  • QT_USE_QTDBUS
  • QT_USE_QTSCRIPT
  • QT_USE_QTWEBKIT
  • QT_USE_QTXMLPATTERNS
  • QT_USE_PHONON

In addition to these, the variable QT_DONT_USE_QTGUI can be used to disable theuse to QtGui. There is a similar variable to disable QtCore, but that is more tobe feature complete than to actually add much useful value.

Added Value and Complexity

It is not as trivial to use CMake as QMake, but the rewards are more features.The most notable point when moving from QMake is CMake's built in support forout-of-source builds. It can really change habits, and thus make versioning codemuch easier.

It is also possible to add conditionals for various platforms and buildscenarios. For instance, use different libraries for different platforms, aswell as tuning the same project differently for different situations.

Other powerful features are the ability to generate multiple executables andlibraries in one build as well as using said executables and libraries in thesame build. This, in combination with the QtTest module can handle complex buildsituations from a single configuration.

The choice between CMake and QMake is really quite easy. For straight forward Qtprojects, QMake is the obvious choice. When the build requirements passes thecomplexity threshold for QMake, CMake can take its place. With Qt Creator'ssupport for CMake, the same tools can still be used.


linkwebsite http://developer.qt.nokia.com/quarterly/view/using_cmake_to_build_qt_projects



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值