Using CMake to Build Qt Projects
2015-02-05 19:53
316 查看
Using CMake to Build Qt Projects
Written by: Johan ThelinQt 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 filesand 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 with
Q_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 islimited 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 requiredcomponent.
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 and helloworld_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 bymoc. All other headers can be left out of the CMakeLists.txt file. This alsoimplicates that if you add a
Q_OBJECT macro to any of your classes you mustensure that it is listed here.
To invoke moc, the macro QT4_WRAP_CPP is used. It assigns the names of theresulting files to the variable listed first. In this case the line looks asfollows.
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 the
helloworld_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 addedas well as a range of defines need to be set. This is handled through thecommands
INCLUDE and ADD_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 commands
ADD_EXECUTABLE andTARGET_LINK_LIBRARIES. Now CMake knows what to build, from what and throughwhich 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 as
QT4_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 includedirectories.
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.
13 comments
July 31, 2010
njeisecke
Lab Rat
link
|report
Hi! Any hints about adding Symbian and Meego targets to Cmake Projekts (using The Nokia
SDK)?
August 5, 2010
aplatypus
Lab Rat
link
|report
Hi and thanks Johan.
Is there a similarly useful blog marking the difference and strengths for Qmake and Cmake that you know about? As a new starter, I want my
KDE compatibility — so are there conversions between Cmake to/from Qmake (for example)?
Otherwise the most valuable part was the picture (worth 1,000 words): ‘The Qt build system’. Now if you can only find a way to explain the
QMAKESPEC, I can die old and happy.
\w/
August 12, 2010
Tobias Hunger
Hobby Entomologist
link
|report
QMake does allow for out-of-source builds, too. Qmake calls this shadowbuilding.
This feature is enabled by creator by default (with the exception of symbian where shadow building is just not possible).
August 30, 2010
TrueNeo
Lab Rat
link
|report
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 commands
INCLUDE and ADD_DEFINITIONS.
From the CMake’s docs seems that ADD_DEFINITIONS is handled internally by the QT_USE_FILE.
QT_DEFINITIONS Definitions to use when compiling code that uses Qt.
You do not need to use this if you include QT_USE_FILE. The QT_USE_FILE will also define QT_DEBUG and QT_NO_DEBUG to fit your current build type. Those are not contained in QT_DEFINITIONS.
November 6, 2010
rohityadav89
Lab Rat
link
|report
Hey, I’ve created something much advanced last year, just in case this interests you:
CMakeQt [1]: a customisable CMake Build System template for Qt based Projects.
Basically, anyone can use this as bare-bones build system, and develop on top of this. (I actually made this last year for
VLMC)
Has advance features like cross-compilation (using mingw on Linux), packaging debs, rpm, windows nsis installer, translations, uis, qrcs, etc. Feel free to download and hack the source [2], mail [3] me patches or suggest features/changes and/or use it with
your Qt based project.
[1] http://www.ohloh.net/p/cmakeqt
[2] https://github.com/rohityadav/cmakeqt
[3] rohityadav89 aT gmail.com
April 2, 2011
yeaiping
Lab Rat
link
|report
Thanks, Very nice.
April 29, 2011
dialingo
Lab Rat
link
|report
Be careful when using QTest and CMake together. There are 2 ways to avoid a compilation problem due to mocs not found:
1. Put the class definition in a separate header file as you do with normal classes.
2. Use a special Qt moc wrapper as shown in
fullmetalcoder’s post on QtCentre [qtcentre.org]
December 11, 2011
ondrejandrej
Ant Farmer
link
|report
These tools meet different criterias
Criteria is already plural, do not add ‘s’.
January 24, 2012
ryadav
Lab Rat
link
|report
Johan thanks for the great CMake article, it helped me get my CMake setup to build my Qt project!
I found the write up very well detailed and easy to follow, what I had to end up guessing was how to define the qt4 variable to help cmake. I ended up doing the following
set(QT_ROOT “$ENV{QT_ROOT}”)
set(QT_QMAKE_EXECUTABLE ${QT_ROOT}/bin/qmake)
set(QT_MOC_EXECUTABLE ${QT_ROOT}/bin/moc)
set(QT_RCC_EXECUTABLE ${QT_ROOT}/bin/rcc)
set(QT_UIC_EXECUTABLE ${QT_ROOT}/bin/uic)
set(QT_INCLUDE_DIR ${QT_ROOT}/include)
set(QT_LIBRARY_DIR ${QT_ROOT}/lib)
set(QT_QTCORE_LIBRARY ${QT_ROOT}/lib)
The environment var QT_ROOT is defined in my Linux bash .bashrc file as
export QT_ROOT=/opt/QtSDK/Desktop/Qt/474/gcc
which points to the location of my QtSDK install.
On Windows you will need to define a similar environment variable. If you installed QtSDK on the C drive, then QT_ROOT should be defined as, “C:\QtSDK\Desktop\Qt\4.7.4\mingw”
Possibly you can update your write-up to mention this.
December 12, 2013
strattonbrazil
Lab Rat
link
|report
I needed to add this to my build script to avoid linker errors.
set(CMAKE_AUTOMOC ON)
March 21, 2014
freemancw
Lab Rat
link
|report
I think it’s pretty important to note in here that the source files will not be listed in QtCreator <= 3.0.1 if the path to the project contains spaces. Would be great to update any other documentation with the same warning or, better yet,
fix the bug if at all possible.
April 15, 2014
ralpyka
Lab Rat
link
|report
How to link statically the qt libraries?
September 1, 2014
darklon
Lab Rat
link
|report
Thanks for the tutorial! I followed the instructions (adapting it to my own simple project), but unfortunately get:
CMake Error at CMakeLists.txt:30 (ADD_EXECUTABLE): Cannot find source file:
moc_qtStuff.cpp
So, is CMake supposed to invoke moc? Or only set up the target project file (in my case VS2008) to correctly handle this ?
The name of the file that’s supposed to be generated is inferred correctly (from qtStuff.h, which I’ve added using QT4_WRAP_CPP). But such a file isn’t generated, and I also don’t get any other error message.
…and it appears to be finding Qt 4.8.4 correctly (first it didn’t, but I fixed that). Any tips how to troubleshoot this?
相关文章推荐
- Using CMake to Build Qt Projects
- Using CMake to Build Qt Projects
- Using Qt to build an Omi App for iOS (and Android)
- Using Qt to build an Omi App for iOS (and Android)
- Using NAnt to Build .NET Projects
- Using a batch file to automatically build a Windows CE 5.0 and 6.0 project
- 解决Unity3D 创建UWP应用出现Exception: Failed to build Visual Studio project using arguments
- PCL( I currently use CDT with cmake to build a Point Cloud Library (PCL) project.)
- how to build java project using gradle
- Using the Dojo JavaScript Library to Build Ajax Applications一书翻译完毕
- Code Leader: Using People, Tools, and Processes to Build Successful Software
- How to build zlib 1.2.3 using Visual Studio 2008 for 32-bit and 64-bit Windows
- Using the Dojo JavaScript Library to Build Ajax Applications一书翻译完毕
- Pragmatic Project Automation: How to Build, Deploy, and Monitor Java Apps
- MS Project Tutorials - How to build a project plan
- Using Asp.net Membership and RoleProvider to Build Login Pages
- 项目管理实践【五】自动编译和发布网站【Using Visual Studio with Source Control System to build and publish website automatically】
- Using the Dojo JavaScript Library to Build Ajax Applications一书翻译完毕
- Post-Build script to fix MSI issues in Vista for VS 2005 Setup and Deployment Projects
- How to build a binary XPCOM component using Visual Studio