2

I have a CMake project which I simplified to find the root of my error. The project has a single CMakeLists.txt file that adds a library and an executable, which links to the library. Both the library and the executable include ui-files. In order to generate header-files of the ui-files, the variable CMAKE_AUTOUIC is used. Both, the library and the executable are able to include their own ui-files: They are found inside the subdirectory [projectname]_autogen\include_Debug of my build directory. However, another file in my executable includes a file from the library, which in turns includes a ui-file. Here I get the error:

Error   C1083   Cannot open include file: 'ui_MainWidget.h': No such file or directory  QtGUI
\QtGUI\src\QtWidgets\include\MainWidget.h   5

My project looks like this:

cmake_minimum_required (VERSION 3.14 FATAL_ERROR)

project(QtGUI)

find_package(Qt5 COMPONENTS Widgets Core Gui REQUIRED)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)

add_library(QtWidgets
    QtWidgets/source/MainWidget.cpp
    QtWidgets/include/MainWidget.h
    QtWidgets/include/MainWidget.ui
)
target_link_libraries(QtWidgets
    PUBLIC
        Qt5::Widgets
        Qt5::Core
        Qt5::Gui
)
target_include_directories(QtWidgets
    PUBLIC
        QtWidgets/include
)

add_executable(${PROJECT_NAME}
    Main/include/MainWindow.h
    Main/include/MainWindow.ui
    Main/source/MainWindow.cpp
    Main/source/Main.cpp
)
target_link_libraries(${PROJECT_NAME}
    PUBLIC
        QtWidgets
)
target_include_directories(${PROJECT_NAME}
    PUBLIC
        Main/include
)

And the MainWindow.cpp file from the project QtGUI, where the error occurs:

#include "MainWindow.h" // inside this project
#include "MainWidget.h" // inside the linked library 'QtWidgets'

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{ 
...

The MainWidget.h looks like this

// Qt Includes
#include <ui_MainWidget.h> // inside this project
#include <QWidget>

namespace Ui
{
    class MainWidget;
}

class MainWidget : public QWidget
{
    Q_OBJECT

public:
...

What am I missing here? I know that it would be cleaner to split the CMakeLists.txt and have an own CMakeLists.txt inside the linked library and move the add_library stuff there (and do the same for the executable, e.g. an application-directory) but I think this example makes it easier to understand the structure.

Edit / Addition

I came back to this (unfortunately unanswered) question and found out this: Looking into "Configuration Properties -> C/C++ -> Additional Include Directories" of my QtGUI-Project (the executable) I see the following:

  • QtGUI\build\QtGUI_autogen\include_Debug
  • QtGUI\src\Main\include
  • QtGUI\src\QtWidgets\include

and some more.

But the required ui_MainWidget.h is located inside QtGUI\build\QtWidgets_autogen\include_Debug, which is not set as additional include directory. I added it manually and everything works.

How do I need to modify my CMakeLists.txt file to have this directory automatically set for my additional include directories?

PS: I also checked Implementing Qt project through CMake but couldn't find any relevant difference in the configuration.

amka
  • 71
  • 1
  • 10

1 Answers1

2

After some more digging I realized that the way the AUTOUIC target property is designed, CMake is looking in specific directories to find the generated UI header file. These directories are automatically added to the target’s INCLUDE_DIRECTORIES, which was [projectname]_autogen\include_Debug as mentioned above. This is only done for each target and not across targets.

One option would be to set the target property AUTOGEN_BUILD_DIR to a directory that can easily be included without any special string:

set_target_properties(QtWidgets
                      PROPERTIES AUTOGEN_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR})

However, the problem with that approach is that I have two targets so the mocs_compilation.cpp will be both put in the same directory and thus one gets overwritten. In the end I had to do something like

set_target_properties(${PROJECT_NAME}
                      PROPERTIES AUTOGEN_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/QtWidgets")

which makes the whole thing superfluous.

Answering my latest edited question, on how to include the other targets autogen-include directory: $<$<CONFIG:DEBUG>:${CMAKE_CURRENT_BINARY_DIR}/QtWidgets_autogen/include_Debug> can be used inside target_include_directories for the QtGUI-target, which results in

target_include_directories(${PROJECT_NAME}
    PUBLIC
        Main/include
    $<$<CONFIG:DEBUG>:${CMAKE_CURRENT_BINARY_DIR}/QtWidgets_autogen/include_Debug>
    $<$<CONFIG:RELEASE>:${CMAKE_CURRENT_BINARY_DIR}/QtWidgets_autogen/include_Release>
)

Additionally, the code could be changed to use the classic qt5_wrap_ui and qt5_wrap_cpp approach, which would put the generated UI header files into my QtGUI\build directory.

Edit / Addition

Looking into "Configuration Properties -> C/C++ -> Additional Include Directories" of my QtGUI-Project (the executable) I can now see the following:

  • QtGUI\build\QtGUI_autogen\include_Debug
  • QtGUI\src\Main\include
  • QtGUI\build\QtWidgets_autogen\include_Debug
  • QtGUI\src\QtWidgets\include

and some more.

amka
  • 71
  • 1
  • 10