Qt 5 cmake завершается неудачно с неопределенной ссылкой на vtable в hello world с inc & src в качестве подкаталогов
Обновление 2
После небольшого перебора (и некоторого редактирования сгенерированных Make-файлов), похоже, что происходит то, что moc не обрабатывает должным образом MainWindow.h
(включено main.cpp
а также MainWindow.cpp
если он не находится в той же папке, что и исходные файлы, в которые он был включен.
Мок работает на MainWindow.cpp
, не обрабатывает включение и, следовательно, не видит макрос Q_OBJECT, поэтому переходит к созданию пустого выходного файла. Я не уверен, включает ли moc обычно процессы или просто просматривает каталог, но в любом случае заголовки, которые требуют перемещения, но находятся в других каталогах, не обрабатываются!
Обновить
Проблема, по-видимому, связана с продукцией, производимой moc. В первом случае (тот, который компилируется), hello-world_automoc.cpp
а также moc_MainWindow.cpp
генерируются. hello-world_automoc.cpp
похоже
/* This file is autogenerated, do not edit*/
#include "moc_MainWindow.cpp"
Во втором случае hello-world_automoc.cpp
производится, что выглядит как
/* This file is autogenerated, do not edit*/
enum some_compilers { need_more_than_nothing };
и нет moc_MainWindow.cpp
совсем. Если я вручную вызываю moc из cmake вместо использования automoc в неработающем случае, я получаю moc_MainWindow.cpp
но пусто
Исходный статус
Во-первых, нет, я не забыл set(CMAKE_AUTOMOC ON)
, Также обратите внимание, что MainWindow
Деструктор объявлен и реализован.
Когда моя структура каталогов выглядит так:
CMakeLists.txt | __ main.cpp | __ MainWindow.cpp | __ MainWindow.h | __ MainWindow.ui
компиляция работает просто отлично.
Тем не менее, когда это выглядит так:
Привет, мир/ | __ 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
Я бы очень хотел, чтобы мои источники и заголовки были в соответствующих подкаталогах, но я не совсем уверен, как это исправить.
На самом деле это самый простой опознаваемый случай ошибки из гораздо более крупного проекта, так что я действительно не сильно стремлюсь сгладить каталоги проекта только потому, что добавляю в него графический интерфейс Qt.
2 ответа
Как уже отмечалось, МОК не обрабатывает MainWindow.h
в вашем примере. Один из способов заставить это произойти, это позвонить qt_wrap_cpp()
непосредственно (вместо 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)
и ваш уровень 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)
Приложение:
- Это работает в вашем примере с включенной функцией AUTOMOC и без нее. Я не знаю наверняка, если это будет вызывать проблемы в будущем. Если вы не включите его, вам придется вручную перемещать любой другой материал... хотя все это может вести себя как MainWindow, в этом случае вы будете вручную перемещать заголовки независимо от этого.
- Вам не нужно устанавливать переменные каталога в верхнем уровне CMakeLists.txt, но я считаю, что это чище, чем делать
qt5_wrap_cpp(hello-world_SRC ../inc/MainWindow.h)
- Там может быть лучший способ сделать это.
- Для всех, кто сталкивался с подобными проблемами, до сих пор это решение задерживалось в более крупном проекте, с которым я изначально сталкивался. Я обновлю соответствующим образом, если он потерпит неудачу.
У меня была такая же проблема, и я нашел решение. Как прокомментировал Эрик Леманиссье в проблеме на GitHub:
Эта ошибка не связана с conan: вам нужно добавить заголовочные файлы в add_executable, иначе moc не будет их анализировать
Заголовочные файлы должны быть добавлены в проект с помощью add_executable
или же add_library
заявление. Если этого не сделать, automoc не будет анализировать файлы.
Хорошо, может быть automoc
у вас не работает, наверное, потому что CMake не находит соответствующие файлы. Проверьте документацию здесь: http://www.cmake.org/cmake/help/v2.8.12/cmake.html
В этом случае вы всегда можете вызвать команду moc вручную для них в вашем CMakeLists.txt
:
qt5_wrap_cpp(moc_sources src/MainWindow.cpp)
qt5_wrap_ui(uic_sources src/MainWindow.cpp)
list(APPEND library_sources ${moc_sources} ${uic_sources})
Примечание: вы должны убедиться, что используете команду list самостоятельно. Этот пример кода из моего проекта, где я использую определенный список источников ( library_sources
).
Это всего лишь предположение, но вы должны без автоматических попыток исключить один из возможных источников ошибок.
Также убедитесь, что вы полностью удалили кэш CMake после изменения структуры каталогов.