Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How do I use Qt headers in a CMake sub-project?



  • I'm using Windows. I have a CMake project that uses Qt and I wish to divide it into subprojects for clarity.

    However, if I compile a class outside of the root folder, I get an error that CMake cannot find the Qt headers.

    For example, let's say I have the following project tree :

    root/
    -->gui/
       -->CMakeLists.txt
       -->mainwindow.cpp
       -->mainwindow.h
    -->CMakeLists.txt
    -->main.cpp
    

    CMakeLists.txt:

    cmake_minimum_required(VERSION 3.5)
    
    project(testcmake VERSION 0.1 LANGUAGES CXX)
    
    set(CMAKE_INCLUDE_CURRENT_DIR ON)
    
    set(CMAKE_AUTOUIC ON)
    set(CMAKE_AUTOMOC ON)
    set(CMAKE_AUTORCC ON)
    
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    
    find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
    find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)
    
    add_subdirectory(gui)
    
    set(PROJECT_SOURCES main.cpp)
    
    add_executable(testcmake ${PROJECT_SOURCES})
    
    target_link_libraries(testcmake PRIVATE gui Qt${QT_VERSION_MAJOR}::Widgets)
    

    main.cpp:

    #include "gui/mainwindow.h"
    
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
      QApplication a(argc, argv);
      MainWindow w;
      w.show();
      return a.exec();
    }
    

    gui/CMakeLists.txt:

    set(GUI_SRC mainwindow.cpp mainwindow.h)
    add_library(gui ${GUI_SRC})
    

    gui/mainwindow.h:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    
    class QPushButton;
    
    class MainWindow : public QMainWindow
    {
      Q_OBJECT
    
    public:
      MainWindow(QWidget *parent = nullptr);
      ~MainWindow();
    
    private:
      QPushButton *m_button;
    };
    #endif // MAINWINDOW_H
    

    gui/mainwindow.cpp:

    #include "mainwindow.h"
    
    #include <QPushButton>
    
    MainWindow::MainWindow(QWidget *parent)
      : QMainWindow(parent)
    {
      m_button = new QPushButton("Hello CMake!", this);
      m_button->resize(150, 50);
    }
    
    MainWindow::~MainWindow()
    {
    }
    

    In this example, if I put class MainWindow in the root folder, the project compiles. But MainWindow class is in a subfolder, I get this error:

    [build] ...\build\gui\gui_autogen\include_debug\ewiega46ww\../../../../../gui/mainwindow.h(4): fatal error C1083: Impossible d'ouvrir le fichier include : 'QMainWindow' : No such file or directory [...\build\gui\gui.vcxproj]
    [build]   mainwindow.cpp
    [build] ...\gui\mainwindow.h(4): fatal error C1083: Impossible d'ouvrir le fichier include : 'QMainWindow' : No such file or directory [...\build\gui\gui.vcxproj]
    

    Which means, at the preprocessing step, the compiler cannot find any Qt header file, because the source file is in a sub-folder.
    How do I let CMake use the Qt headers, which are retrieved from the find_package command in the root folder?



  • I've been bitten by this before; forgetting to add a library to a target_link_libraries() statement and getting 'include' errors during compilation. Then, not checking the target_link_libraries() statements; wrongly think they would only come into play during linking.


  • Lifetime Qt Champion

    If you want to use a library you have to link against this library with target_link_libraries()



  • I've been bitten by this before; forgetting to add a library to a target_link_libraries() statement and getting 'include' errors during compilation. Then, not checking the target_link_libraries() statements; wrongly think they would only come into play during linking.



  • OK, I think I have a solution, or maybe a workaround. I added linking to the Qt libraries at the end of gui/CMakeLists.txt:

    set(GUI_SRC mainwindow.cpp mainwindow.h)
    add_library(gui ${GUI_SRC})
    target_link_libraries(gui PUBLIC Qt${QT_VERSION_MAJOR}::Widgets)
    

    and then it compiles.
    Even though it's just a library, I guess I still need to link the Qt libraries so my code can use the header files.



  • Your gui sub-project still needs to link to the libraries, it's not just so it can find the header files. In the compile/build output you should see a link step.


  • Lifetime Qt Champion

    @tuzepoito said in How do I use Qt headers in a CMake sub-project?:

    I think I have a solution, or maybe a workaround.

    Why workaround? If you want to use a library, you have to link against it what you're doing now - how should this be a workaround?