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 после изменения структуры каталогов.

Другие вопросы по тегам