Update 2
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 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!
Update
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"
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 };
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.
Original Status
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
compiling works just fine.
However, when it looks like:
helloworld/ |__ CMakeLists.txt |__ src/ | |__ CMakeLists.txt | |__ main.cpp | |__ MainWindow.cpp | |__ inc/ | |__ MainWindow.h | |__ gui/ |__ MainWindow.ui
I get linking errors:
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.
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.
I had the same problem and found a solution. As Eric Lemanissier commented in an issue on GitHub:
The header files have to be added to the project using an
add_executable
oradd_library
statement. If this is not done, automoc won't parse the files.As noted, moc is not processing
MainWindow.h
in your example. One way to force this to happen is to callqt_wrap_cpp()
on it directly (instead of onMainWindow.cpp
) and then include the resulting file in the call toadd_executable()
.Your top level CMakeLists.txt might look like:
and your src level one like:
Addendum:
qt5_wrap_cpp(hello-world_SRC ../inc/MainWindow.h)
Well, maybe
automoc
does not work for you, I would guess it's because CMake does not find the corresponding files. Check the documentation here: http://www.cmake.org/cmake/help/v2.8.12/cmake.html#prop_tgt:AUTOMOCIn this case, you can always call the moc command manually for them in your
CMakeLists.txt
:Note: you have to make sure you use the list command correctly yourself. This code example is from my project where I use a specific list of sources (
library_sources
).It is just a guess but you should try without the automagic first to rule out one possible source of error.
Also make sure that you fully deleted the CMake cache after changing your directory structure.