Setting up a Qt 5 CMake project for Visual Studio and Linux


CMake is cool, Qt is cool. Both together not so, if you don't know what you're doing. This describes how to build a Qt project CMakeLists.txt so everything works and how to run / debug your application in Linux and Visual Studio. Make sure to additionally check out the Qt5 CMake docs and the CMake Qt docs though.

Building a CMakeLists.txt file for a Qt 5 project

You could paste this straight to a CMakeLists.txt and adapt it to your needs. The explanations are in the comments.
# Use CMake >= 3.1.0. There have been many improvements in CMake 3, # also in regards to Qt usage, so you should not go with less than 3.1.0, # which has bee around for quite some time now...
cmake_minimum_required(VERSION 3.1.0)

# define your project name. This will be available through "${PROJECT_NAME}" now
project(MyProjectName)

# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Instruct CMake to run moc, uic and rcc automatically when needed.
# This will intelegently
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)

# Find the QtWidgets library (Qt5Widgets also finds the Qt5Core and Qt5Gui packages)
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Something REQUIRED)

# Executables fail to build with Qt 5 in the default configuration, becasue the -fPIE flag is needed. This adds it.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")

# Set up compilers (Clang, MSVC, GCC) so that C++11 can be used. The optimization settings are optional. Make sure not to "strip" the executable (-s in linker options for Clang and GCC) if you want to debug your application! Else debug information won't be available.
if (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
    #set up compiler flags for Clang
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O2") #support C++11 for std::, optimize
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -O2") #optimize
elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
    #check for G++ 5.4+
    execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE G++_VERSION)
    if (G++_VERSION VERSION_LESS 5.4)
            message(SEND_ERROR "You need at least G++ 5.4 to compile ${PROJECT_NAME}!")
    endif()
    #set up compiler flags for GCC
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O2") #support C++11 for std::, optimize
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -O2") #optimize
elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "MSVC")
    set(CMAKE_DEBUG_POSTFIX "d")
    add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
    add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") #multi-processor compilation
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP") #multi-processor compilation
endif()

# Now define your header files, .ui files here:
set(MYPROJECT_HEADERS
    ${CMAKE_CURRENT_SOURCE_DIR}/src/mainwindow.h
    ${CMAKE_CURRENT_SOURCE_DIR}/src/mainwindow.ui
)

# Your source and .qrc files go here:
set(MYPROJECT_SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/mainwindow.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/resources.qrc
)

# Optional: You can also add OS-specific header or source files:
if(WIN32)
    LIST(APPEND MYPROJECT_SOURCES
        ${CMAKE_CURRENT_SOURCE_DIR}/src/stuff_win.cpp
    )
elseif(UNIX AND NOT APPLE)
    LIST(APPEND MYPROJECT_SOURCES
        ${CMAKE_CURRENT_SOURCE_DIR}/src/stuff_linux.cpp
    )
endif()

# Optional: Or OS-specific libraries:
if(WIN32)
    set(MYPROJECT_LIBRARIES
        winmm
    )
elseif(UNIX AND NOT APPLE)
    set(MYPROJECT_LIBRARIES
        pthread
    )
endif()

# Set up your build directory
set(dir ${CMAKE_CURRENT_SOURCE_DIR})
set(EXECUTABLE_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
set(LIBRARY_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)

# Set up your project build using include and source dirs and link libraries
include_directories(${Qt5Widgets_INCLUDES})
add_executable(${PROJECT_NAME} ${MYPROJECT_SOURCES} ${MYPROJECT_HEADERS})
target_link_libraries(${PROJECT_NAME} ${Qt5Widgets_LIBRARIES} Qt5::Something ${MYPROJECT_LIBRARIES})
This should give you a working CMakeLists.txt file. Note in this example the source files are in a subdirectory "/src" below the project folder, while the CMakeLists.txt file is in the project folder.

Generating the build files

To generate build files your will need to know where Qt resides. This path must be passed in the CMAKE_PREFIX_PATH environment variable when running CMake, or you can set this in the CMake GUI. To pass this on the command line, do:
cmake -D CMAKE_PREFIX_PATH=<QT_INSTALL_DIR> <SOURCE_DIRECTORY>

Usually you would cd to your project directory and run something like this (here Qt is in "/home/<USERNAME>/Qt/5.8" and sources in the "/src" subdirectory):
cmake -D CMAKE_PREFIX_PATH=~/Qt/5.8/gcc_64/ src
Now you should be to run make and compile your code.

Running the application from Visual Studio

When you run your compiled application this works as long the Qt libraries are found. This is a problem from within VS if you don't have QTDIR set. You can work around this by either copying the correct libraries to the application dir or setting up some environment variables on startup. Set this in your project properties -> "Debugging" -> "Environment":
PATH=<QT_INSTALL_DIR>\bin;$(Path)
QT_QPA_PLATFORM_PLUGIN_PATH=<QT_INSTALL_DIR>\plugins\platforms
QT_PLUGIN_PATH=<QT_INSTALL_DIR>\plugins

Happy compiling.

Comments