使用CMake将带有.pro文件的Qt项目转换为项目 - moc问题

时间:2017-09-07 13:01:04

标签: qt cmake moc

我有一个项目,当我使用带有QtCreator的.pro文件构建它时编译得很好。我正在尝试将其转换为cmake,但遇到了问题。

以极简再现的方式编辑:

项目文件夹结构:

src/foo.cpp   --> #include "ui_foo.h"
src/bar.cpp   --> #include "bar.moc"
inc/foo.h   
ui/foo.ui    

预期的编译流程(使用qmake时观察到的流程):

(1)  moc  inc/foo.h              -o moc_foo.cpp
(2)  moc  src/bar.cpp            -o bar.moc
(3)  uic  ui/foo.ui              -o ui_foo.h
(4)  gcc  src/foo.cpp            -o foo.o
(5)  gcc  src/bar.cpp            -o bar.o
(6)  gcc  moc_foo.cpp            -o moc_foo.o
(7)  ld   foo.o bar.o moc_foo.o  -o foobar

的CMakeLists.txt(1)

set(CMAKE_INCLUDE_CURRENT_DIR ON )
set(CMAKE_AUTOMOC ON )
set(CMAKE_AUTOUIC ON )
add_executable(foobar src/foo.cpp src/bar.cpp)
未创建

moc_foo.cpp(错过了第1步和第6步),并且在步骤7中未添加到add_executable。由于缺少对象而发生对vtable的未定义引用。我认为这是因为foo.cpp和foo.h位于不同的文件夹中。

的CMakeLists.txt(2)

set(CMAKE_INCLUDE_CURRENT_DIR ON )
qt5_wrap_cpp(foobar_moc inc/foo.h src/bar.cpp)
qt5_wrap_ui (foobar_ui  ui/foo.ui)
add_executable(foobar src/foo.cpp src/bar.cpp ${foobar_moc} ${foobar_ui})
在步骤2中生成

moc_bar.cpp而不是bar.moc。我收到编译器错误,因为在步骤5中找不到bar.moc

2 个答案:

答案 0 :(得分:2)

最简单的方法是添加AUTOMOC属性,然后让CMake handle QT mocs自动

get { if (_courses == null) _courses = new List<Course>(); return _courses; }

答案 1 :(得分:2)

通过尝试播放.cpp文件,你自己的生活变得不必要了。

尽管名称qt5_wrap_cpp实际上将头文件作为其参数,并调用moc来生成匹配的cpp文件:

qt5_wrap_cpp(foobar_moc inc/foo.h)

# ${foobar_moc} will contain the name 
# of the .cpp file created for foo.h
# which we pass to add_executable()

请注意,通常您会在某处放置一个foo.cpp源文件,它与moc生成的.cpp一起提供foo.h中定义的类的完整实现。

现在,如果您真的想在.cpp文件上调用moc,则过程略有不同。这里,由于类定义不再位于头文件中,因此moc生成的源文件无法访问它引用的类定义。因此,生成的源文件无法再自行编译。相反,您需要在使用#include 类定义之后将其拉入原始源文件,这不是很好。

更糟糕的是,对于CMake调用moc命令,生成的源文件仍然需要成为某个依赖链的一部分,这使得一切都非常难看。

我们将使用qt5_generate_moc命令在bar.cpp上调用moc(因为qt5_wrap_cpp还会将生成的源添加到构建中,这会破坏):

qt5_generate_moc(src/bar.cpp ${CMAKE_BINARY_DIR}/bar.moc)

请注意,我们将生成的文件放在二叉树中,以便不使用生成的文件污染源树。如果您设置了AUTOGEN_BUILD_DIR,则可能需要将生成的文件放在那里。为了让#include能够找到生成的文件,我们将二叉树添加到项目的include目录中:

target_include_directories(foobar PUBLIC ${CMAKE_BINARY_DIR})

最后,我们需要一个构建步骤依赖项的自定义目标。如果没有这个,moc命令永远不会被实际调用:

add_custom_target(moc_dummy DEPENDS ${CMAKE_BINARY_DIR}/bar.moc)
add_dependencies(foobar moc_dummy)

底线:只需将所有类定义移动到头文件,然后再将其移动。没有缺点,你会为自己节省很多丑陋的样板。