问题描述
在搞砸了一点(以及对生成的 Makefile 进行了一些编辑)之后,看起来正在发生的事情是 moc 没有正确处理 MainWindow.h
(包含在 main.cpp
和 MainWindow.cpp
除非它与包含它的源文件位于同一文件夹中.
After messing around a bit (and some editing of the generated Makefiles), it looks like what is happening is that moc is not properly processing MainWindow.h
(included by main.cpp
and MainWindow.cpp
unless it is in the same folder as the source files which included it.
Moc 在 MainWindow.cpp
上运行,不处理包含,因此看不到 Q_OBJECT 宏,因此继续生成一个空的输出文件.我不确定 moc 是否通常处理包含或是否只是扫描目录,但无论哪种方式,需要 mocing 但位于其他目录中的标头都不会被处理!
Moc runs on MainWindow.cpp
, doesn't process the include and thus doesn't see the Q_OBJECT macro so proceeds to produce an empty output file. I'm not sure whether moc usually processes includes or if it just scans the directory, but either way, headers that need mocing but are in other directories are not being processed!
问题似乎与 moc 产生的输出有关.在第一种情况下(编译的那个),hello-world_automoc.cpp
和 moc_MainWindow.cpp
生成.hello-world_automoc.cpp
看起来像
The problem appears to be related to the output produced by moc. In the first case (the one that compiles), hello-world_automoc.cpp
and moc_MainWindow.cpp
are generated. hello-world_automoc.cpp
looks like
/* This file is autogenerated, do not edit*/
#include "moc_MainWindow.cpp"
在第二种情况下,生成的 hello-world_automoc.cpp
看起来像
In the second case, a hello-world_automoc.cpp
is produced that looks like
/* This file is autogenerated, do not edit*/
enum some_compilers { need_more_than_nothing };
根本没有moc_MainWindow.cpp
.如果我从 cmake 手动调用 moc 而不是在损坏的情况下使用 automoc,我会得到 moc_MainWindow.cpp
但它是空的.
and there is no moc_MainWindow.cpp
at all. If I manually call moc in from cmake instead of using automoc in the broken case, I do get moc_MainWindow.cpp
but it is empty.
首先,不,我没有忘记 set(CMAKE_AUTOMOC ON)
.另请注意,MainWindow
的 析构函数已声明并实现.
Firstly, no, I haven't forgotten to set(CMAKE_AUTOMOC ON)
. Also note that MainWindow
's destructor is declared and implemented.
当我的目录结构如下所示:
When my directory structure looks like:
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
我真的很想将我的源代码和标题放在适当的子目录中,但我不太确定如何解决这个问题.
I'd really like to have my sources and headers in proper subdirectories, but I'm not quite sure how to fix this.
这实际上是一个更大的项目中最简单的可识别错误案例,所以我真的不那么热衷于仅仅因为我正在向其中添加 Qt GUI 来展平项目目录.
This is actually the simplest identifiable case of an error from a much larger project, so I'm really not all that keen to flatten the project directories just because I'm adding a Qt GUI to it.
推荐答案
如前所述,在您的示例中,moc 不处理 MainWindow.h
.强制这种情况发生的一种方法是直接在其上调用 qt_wrap_cpp()
(而不是在 MainWindow.cpp
上),然后将生成的文件包含在对 add_executable()
.
As noted, moc is not processing MainWindow.h
in your example. One way to force this to happen is to call qt_wrap_cpp()
on it directly (instead of on MainWindow.cpp
) and then include the resulting file in the call to add_executable()
.
您的顶级 CMakeLists.txt 可能如下所示:
Your top level CMakeLists.txt might look like:
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)
和你的 src 一级像:
and your src level one like:
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)
附录:
- 这适用于您启用和未启用 AUTOMOC 的示例.我不确定是否会在将来引起问题.如果你不启用它,你将不得不手动 moc 任何其他东西......尽管它可能都表现得像 MainWindow 在这种情况下你将手动 moc 标题不管.
- 您不必在顶级 CMakeLists.txt 中设置目录变量,但我发现它比执行
qt5_wrap_cpp(hello-world_SRC ../inc/MainWindow.h)
李> - 可能有更好的方法来做到这一点.
- 对于其他有类似问题的人,到目前为止,这个解决方案在我最初遇到的较大项目中得到了支持.如果它失败,我会相应地更新.
这篇关于Qt 5 cmake 失败,未定义对带有 inc & 的 hello world 上的 vtable 的引用src 作为子目录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!