10

我有一个 Qt 小部件 C++ 类,它加载在 Qt Creator 中创建的 ui 文件。类的头文件和源文件位于两个单独的目录中。我无法指示 cmake/automoc 找到该类的标题。cmake 认识到它需要 moc C++ 文件,但找不到类似的头文件。

我可以做些什么来帮助 cmake 找到文件吗?

如果 cpp 和头文件都在同一目录中,则一切正常。只有当标题在其他地方时才会出现这种情况。

我的目录结构是

project
    src
        include
            Foo
                Bar.h
    lib
        Foo
            Bar.cpp
            forms
                Bar.ui           

在 src/include/Foo/Bar.h 我有:

// Bar.h
#include <QtWidgets/QWidget>

namespace Ui { class Bar; }

class Bar : public QWidget {
    Q_OBJECT
    ...
}

在 src/Foo/Bar.cpp 文件中:

#include "Foo/Bar.h"
#include "moc_Bar.cpp"
#include "ui_Bar.h"

我在 src/lib/Foo 中的 CMakeLists.txt 设置如下:

# there is a project() call at the root that defines PROJECT_SOURCE_DIR
set(PUBLIC_HEADERS_DIR ${PROJECT_SOURCE_DIR}/src/include)

# Pick up public library headers
include_directories(${PUBLIC_HEADERS_DIR})

# Pick up private headers in library dir    
include_directories(${CMAKE_CURRENT_SOURCE_DIR})

# Set up Qt
set(CMAKE_AUTOMOC ON)                    
set(CMAKE_INCLUDE_CURRENT_DIR ON)
find_package(Qt5Core REQUIRED)
find_package(Qt5Gui REQUIRED)
find_package(Qt5Widgets REQUIRED) 
include_directories(${Qt5Core_INCLUDE_DIRS})
include_directories(${Qt5Gui_INCLUDE_DIRS})
include_directories(${Qt5Widgets_INCLUDE_DIRS})
add_definitions(${Qt5Widgets_DEFINITIONS})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")

# Set up Qt forms/resources
qt5_wrap_ui(UI_OUT_FILES forms/Bar.ui)
qt5_add_resources(RESOURCE_FILE resources.qrc)

# Library cpp and header files
set(CORE_CPP_FILES Bar.cpp)
set(LIB_CPP_FILES ${LIB_CPP_FILES} ${CORE_CPP_FILES} ${UI_OUT_FILES} ${RESOURCE_FILE}) 
set(LIB_HEADER_FILES ${PUBLIC_HEADERS_DIR}/Foo/Bar.h)

# Build library
add_library(Foo SHARED ${LIB_CPP_FILES} ${LIB_HEADER_FILES})
target_link_libraries(Foo ${Qt5Widgets_LIBRARIES})

当我运行 cmake 时,我收到以下错误:

AUTOGEN:错误:/automoc/src/lib/Foo/Bar.cpp 该文件包含 moc 文件“moc_Bar.cpp”,但找不到标题“Bar{.h,.hh,.h++,.hm,.hpp ,.hxx,.in,.txx}" 在 /automoc/src/lib/Foo/

4

2 回答 2

3

您必须手动包装头文件。将其放入您的 CMakeLists.txt:

file(GLOB HEADERS_TO_MOC src/include/Foo/ *.h)

qt5_wrap_cpp(PROCESSED_MOCS                                                                                                                                                                                                                                                                    
             ${HEADERS_TO_MOC}                                                   
             TARGET Foo
             OPTIONS --no-notes) # Don't display a note for the headers which don't produce a moc_*.cpp

target_sources(Foo PRIVATE ${PROCESSED_MOCS}) # This adds generated moc cpps to target

这种方法的真实示例 https://github.com/paceholder/nodeeditor/blob/master/CMakeLists.txt#L133

于 2016-04-21T13:10:35.960 回答
0

我发现解决方法可以通过留给AUTOMOC自己的设备来简化。这是我所做的(目前适用于我们所有支持的 CMake 版本3.2...3.17):

  1. #include "moc_Bar.cpp"从文件中删除Bar.cpp
  2. 将外部(到当前目录)头文件添加为PRIVATE目标的源:
set(CMAKE_AUTOMOC True)
target_sources(Foo PRIVATE
  ${CMAKE_SOURCE_DIR}/src/include/Foo/Bar.h
  ${CMAKE_SOURCE_DIR}/src/include/Foo/Baz.h)

AUTOMOCFoo_autogen当它 MOCs 有问题的文件时,将创建一个输出目录。moc_Bar.cpp并将moc_Baz.cpp在一个随机命名的ABDEADBEEF子目录中创建,并且mocs_compilation.cpp将创建一个文件,其内容如下:

// This file is autogenerated. Changes will be overwritten.
#include "ABDEADBEEF/moc_Bar.cpp"
#include "ABDEADBEEF/moc_Baz.cpp"

该文件被编译并与目标的最终输出链接。

使用CMAKE_AUTOMOCglobal set True,每个目标也将收到自己的target_autogen目录,尽管在没有任何 MOC'able 类的目标中不会生成任何内容。不过,最好AUTOMOC只在需要它的目标上设置目标属性:

set_property(TARGET Foo PROPERTY AUTOMOC ON)
于 2020-02-25T18:19:17.810 回答