Qt 5 cmake失败,未知定义引用hello world上的vtable,inc&src为子目录

Isk*_*rak 12 c++ linker qt cmake moc

更新2

稍微搞砸了(以及对生成的Makefile的一些编辑),看起来正在发生的是moc没有正确处理MainWindow.h(包括在内main.cpp,MainWindow.cpp除非它与包含它的源文件位于同一文件夹中).

Moc运行MainWindow.cpp,不处理包含,因此没有看到Q_OBJECT宏,因此继续产生一个空的输出文件.我不确定moc通常是进程包含还是只是扫描目录,但无论哪种方式,需要mocing但在其他目录中的头文件都没有被处理!

更新

问题似乎与moc产生的输出有关.在第一种情况下(编译的那个),hello-world_automoc.cppmoc_MainWindow.cpp生成.hello-world_automoc.cpp好像

/* This file is autogenerated, do not edit*/
#include "moc_MainWindow.cpp"
Run Code Online (Sandbox Code Playgroud)

在第二种情况下,hello-world_automoc.cpp产生了一个看起来像的

/* This file is autogenerated, do not edit*/
enum some_compilers { need_more_than_nothing };
Run Code Online (Sandbox Code Playgroud)

并且根本没有moc_MainWindow.cpp.如果我从cmake手动调用moc而不是在破碎的情况下使用automoc,我确实得到moc_MainWindow.cpp但它是空的.

原始状态

首先,不,我没有忘记set(CMAKE_AUTOMOC ON).还要注意的是MainWindow析构函数声明和实现.

当我的目录结构如下所示:

CMakeLists.txt
|__ main.cpp
|__ MainWindow.cpp
|__ MainWindow.h
|__ MainWindow.ui

编译工作得很好.

但是,当它看起来像:

helloworld/
|__ CMakeLists.txt
|__ src/
|   |__ CMakeLists.txt
|   |__ main.cpp
|   |__ MainWindow.cpp
|
|__ inc/
|   |__ MainWindow.h
|
|__ gui/
    |__ MainWindow.ui

我得到链接错误:

Linking CXX executable hello-world
CMakeFiles/hello-world.dir/MainWindow.cpp.o: In function `MainWindow::MainWindow()':
MainWindow.cpp:(.text+0x3b): undefined reference to `vtable for MainWindow'
MainWindow.cpp:(.text+0x4d): undefined reference to `vtable for MainWindow'
CMakeFiles/hello-world.dir/MainWindow.cpp.o: In function `MainWindow::~MainWindow()':
MainWindow.cpp:(.text+0xaf): undefined reference to `vtable for MainWindow'
MainWindow.cpp:(.text+0xc1): undefined reference to `vtable for MainWindow'
collect2: error: ld returned 1 exit status
make[2]: *** [src/hello-world] Error 1
make[1]: *** [src/CMakeFiles/hello-world.dir/all] Error 2
Run Code Online (Sandbox Code Playgroud)

我真的希望将我的源代码和标题放在适当的子目录中,但我不太确定如何解决这个问题.

这实际上是来自更大项目的错误的最简单的可识别情况,所以我真的不是那么热衷于展平项目目录只是因为我正在添加Qt GUI.

Isk*_*rak 14

如上所述,moc MainWindow.h在您的示例中不处理.强制执行此操作的一种方法是qt_wrap_cpp()直接调用它(而不是on MainWindow.cpp),然后在调用中包含生成的文件add_executable().

您的顶级CMakeLists.txt可能如下所示:

cmake_minimum_required(VERSION 2.8.9)

#set(CMAKE_AUTOMOC ON)

set(CMAKE_PREFIX_PATH "/opt/Qt/5.1.1/gcc_64")
set(CMAKE_INCLUDE_CURRENT_DIR ON)

project(hello-world)

find_package(Qt5Widgets REQUIRED)

set(HW_HEADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/inc)
set(HW_GUI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/gui)

include_directories(${HW_HEADER_DIR})

subdirs(src)
Run Code Online (Sandbox Code Playgroud)

和你的src级别一样:

qt5_wrap_cpp(hello-world_SRC ${HW_HEADER_DIR}/MainWindow.h)
qt5_wrap_ui(hello-world_UI ${HW_GUI_DIR}/MainWindow.ui)

add_executable(hello-world MainWindow.cpp main.cpp
               ${hello-world_UI} ${hello-world_SRC})
qt5_use_modules(hello-world Widgets)
Run Code Online (Sandbox Code Playgroud)

附录:

  • 这适用于启用和不启用AUTOMOC的示例.我不确定将来是否会引起问题.如果你没有启用它,你将不得不手动moc任何其他东西......虽然它可能都像MainWindow一样,在这种情况下你将手动mocing标头无论如何.
  • 您不必在顶级CMakeLists.txt中设置目录变量,但我发现它比干净更清晰 qt5_wrap_cpp(hello-world_SRC ../inc/MainWindow.h)
  • 可能有更好的方法来做到这一点.
  • 对于其他有类似问题的人来说,到目前为止,这个解决方案已经停留在我最初遇到的大型项目中.如果失败,我会相应地更新.


小智 7

我遇到了同样的问题并找到了解决方案。正如 Eric Lemanissier在 GitHub 上的一个问题中评论的那样:

这个错误与conan无关:你需要在add_executable中添加你的头文件,否则moc不会解析它们

必须使用add_executableoradd_library语句将头文件添加到项目中。如果不这样做,automoc 将不会解析文件。