Qt with cmake

This page is a copy of the original page that was located at http://qtnode.net/wiki?title=Qt_with_cmake

Home

CMake Documentation

QT4 Documentation

Qt with cmake

From qtnode

cmake is a Makefile generator, that means it does not replace the "make" program (in contrast to e.g. scons).

Thus cmake is comparable to autotools (see Qt with autotools). However:

  • cmake also works on Windows
  • cmake is much easier to learn than autotools
  • cmake scripts are much easier to read than autotools scripts
  • cmake comes with many configure test macros built in
  • cmake comes with support for Qt and KDE

Contents

  1. History: KDE4
  2. Using cmake
  3. cmake for Qt/KDE 3
  4. cmake for Qt 4
  5. Installing files
  6. Configure tests
  7. Sample Projects

History: KDE4


cmake was one of the alternatives investigated by the KDE project to replace the usage of autotools for KDE4. SCons was chosen initially, but got dropped due to some inherent problems and currently (May 2006) it looks like cmake will be the default build system for KDE4. Since KDE is built upon Qt, it is logical that cmake support for both Qt and KDE will be very good once KDE4 is released. However Qt/KDE in cmake support already is very good right now.

Using cmake

When you have a cmake based project and just want to compile it, do the following:

cd project
mkdir build
cd build
cmake ..
make
make install

Or if you want to install to /home/foo/bar instead of the default install prefix:

cd project
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=/home/foo/bar ..
make
make install

You can also use "ccmake" instead of "cmake". This will give you a more or less graphical tool to configure the application - a graphical window on windows and a text/menu based program on unix.
[edit]

cmake for Qt/KDE 3

Note: we will require cmake 2.4 here. However some/most of the code below may work with previous versions, too. Here we have a look at a simple cmake based project for Qt3/KDE3. I am going to use the KDE3 macros, because I come from a KDE background and I find them much simpler to use, than the plain Qt variants, but I think you don't actually need KDE for them.

Suppose we have a simple project:

qtproject
 `-- src
      +-- main.cpp
      +-- top.cpp
      `-- top.h

To turn it into a cmake project, we add two CMakeLists.txt files, one per directory. The qtproject/CMakeLists.txt file will look like this:

project(qtproject) # the name of your project

cmake_minimum_required(VERSION 2.4.0)

# find and setup Qt3 for this project
find_package(Qt3 REQUIRED)

# find and setup KDE3 for this project
find_package(KDE3 REQUIRED)

add_definitions(${QT_DEFINITIONS} ${KDE3_DEFINITIONS})

# tell cmake where to search for libraries:
link_directories(${KDE3_LIB_DIR})

# tell cmake where to search for Qt/KDE headers:
include_directories(${KDE3_INCLUDE_DIR} ${QT_INCLUDE_DIR})

# tell cmake to process CMakeLists.txt in that subdirectory
add_subdirectory(src)

A closer look at some macros used here:

  • find_package(Qt3 REQUIRED): this is some kind of configure test. It searches for Qt3 and defines a couple of variables that we will use later on. This will be required for your Qt3 based project.
  • find_package(KDE3 REQUIRED): this does the same for KDE3. Skip this if your project is Qt only.
  • link_directories() this adds directories to the path where cmake searches for libraries, nothing else. Pretty much a -L<directory> when it comes to g++.
  • include_directories() this does not "include" a directory to cmake, but rather tells the compiler where to search for include files. I.e. -I<directory> when it comes to g++.

The actually interesting things happen in qtproject/src/CMakeLists.txt:

# the variable "qtproject_SRCS"
# contains all .cpp files of this project
set(qtproject_SRCS
    main.cpp
    top.cpp
)

# tell cmake to create .moc files for all files
# in the variable qtproject_SRCS that require
# such a file. note: this assumes that you use
# <<#include "header.moc">> in your files also
# note that you don't actually require kde to use
# this command
kde3_automoc(${qtproject_SRCS})

# create an executable file named "qtproject" from
# the source files in the variable "qtproject_SRCS".
add_executable(qtproject ${qtproject_SRCS})

# link the "qtproject" target (i.e. the executable
# file added above) agains the Qt and the kdecore
# libraries.
target_link_libraries(qtproject ${QT_AND_KDECORE_LIBRARIES})
  • set(<variable> <value>): this is pretty much a "<variable> = <value>" statement. The first argument is the variable name, the rest is a list (space or newline separated) of values for it. I just emphasize it, because it looked cryptic to me a long time ago :-)
  • kde3_automoc(): add #include "header.moc" next to your #include "header.h" and then use this macro. It will do all the moc work for you.
  • target_link_libraries(qtproject ${QT_AND_KDECORE_LIBRARIES}): link qtprojects against some libraries. You can add more to that list, adding library names (just the name, neither a prefix such as "lib", nor a suffix, such as ".so") to it (space separated). Instead of $ {QT_AND_KDECORE_LIBRARIES} you could use (for example):
  1. ${QT_LIBRARIES} - only the Qt libraries, no KDE libraries
  2. ${QT_AND_KDECORE_LIBRARIES} kdeui - create a KDE GUI program

cmake for Qt 4

Qt4 support in cmake is being developed in particular with the KDE project for KDE4. Qt4 support in cmake is already (cmake version 2.4.x) good at this point. Most things can be done similar as in Qt/KDE 3, so have a look at the section above for a full introduction.

qtproject/CMakeLists.txt:

# the name of your project
project(qtproject)

cmake_minimum_required(VERSION 2.4.0)

# find and setup Qt4 for this project
find_package(Qt4 REQUIRED)

# tell cmake to process CMakeLists.txt
# in that subdirectory
add_subdirectory(src)

qtproject/src/CMakeLists.txt:

# the next line sets up include and link directories and defines some variables that we will use.
# you can modify the behavior by setting some variables, e.g.
#   set(QT_USE_OPENGL TRUE)
# -> this will cause cmake to include and link against the OpenGL module
include(${QT_USE_FILE})

# the variable "qtproject_SRCS" contains all .cpp files of this project
set(qtproject_SRCS
    main.cpp
    top.cpp
)

# tell cmake to create .moc files for all files in
# the variable qtproject_SRCS that require such a
# file. note: this assumes that you use
# <<#include "header.moc">> in your files
qt4_automoc(${qtproject_SRCS})

# create an executable file named "qtproject" from
# the source files in the variable "qtproject_SRCS".
add_executable(qtproject ${qtproject_SRCS})

# link the "qtproject" target against the Qt
# libraries. which libraries exactly, is defined by
# the "include(${QT_USE_FILE})" line above, which
# sets up this variable.
target_link_libraries(qtproject ${QT_LIBRARIES})

If you need cmake to generate ui*.h files from .ui files then you need to use QT4_WRAP_UI macro like this:

SET(qtproject_UIS
    main_window.ui
)

QT4_WRAP_UI(qtproject_UIS_H ${qtproject_UIS})

# Don't forget to include output directory, otherwise
# the UI file won't be wrapped!
include_directories(${CMAKE_CURRENT_BINARY_DIR})

#Now add these generated files to the ADD_EXECUTABLE
# step. If this is NOT done, then the ui_*.h files
# will not be generated
add_executable(qtproject
                 ${qtproject_SRCS}
                 ${qtproject_UIS_H}
                 )

If you don't use the #include "header.moc" convention, you can use the QT4_WRAP_CPP macro. This generates a list of moc_xxxx.cxx files to be generated. You pass in the list of headers to be moc'ed, and get back a list of source files to add to your build target. This is similar to how qmake works with Qt4. An example usage is:

SET(foo_SRCS
  Class1.cpp
  Class2.cpp
  Class3.cpp
)

SET(foo_MOC_HDRS
  Class1.h
  Class2.h
  Class3.h
)

# After this call, foo_MOC_SRCS =
#    moc_Class1.cxx moc_Class2.cxx moc_Class3.cxx.
QT4_WRAP_CPP(foo_MOC_SRCS ${foo_MOC_HDRS})

ADD_EXECUTABLE(foo ${foo_SRCS} ${foo_MOC_SRCS})

To add support for Qt4 libraries like network or qttest, you need to add both the include files and corresponding libraries. For example, to add support for the network and qttest libraries, you can use:

INCLUDE_DIRECTORIES(
   ${QT_INCLUDE_DIR}
   ${QT_QTNETWORK_INCLUDE_DIR}
   ${QT_QTTEST_INCLUDE_DIR}
)

TARGET_LINK_LIBRARIES(
   ${QT_LIBRARIES}
   ${QT_QTNETWORK_LIBRARIES}
   ${QT_QTTEST_LIBRARIES}
)

To build a Qt plugin, you must add some defines and build your library as a shared library. For example, to build a plugin in release mode:

ADD_DEFINITIONS(${QT_DEFINITIONS})
ADD_DEFINITIONS(-DQT_PLUGIN)
ADD_DEFINITIONS(-DQT_NO_DEBUG)
ADD_DEFINITIONS(-DQT_SHARED)

...

ADD_LIBRARY(foo SHARED ${foo_SRCS})


Installing files

Installing in cmake is very easy - to install the "qtproject" executable created above add this to the end of the CMakeLists.txt file:

install(TARGETS qtproject DESTINATION bin)

This will install to the "bin" subdirectory of CMAKE_INSTALL_PREFIX.

Instead of TARGETS you could also use FILES, which would allow you to install any random file that exists in the source directory.

For a complete reference of the install() macro, see the cmake documentation at http://www.cmake.org.

Sample Projects

Qt based projects using cmake: