Q_OBJECT 将 qmake 项目转换为 cmake 时未命名类型
Q_OBJECT does not name a type when converting a qmake project to cmake
我正在尝试将使用 Qt 5 和 Q_OBJECT
的共享库从 QMake 过渡到 CMake 3.2。这是当前 CMakeLists.txt
文件:
cmake_minimum_required(VERSION 3.2.2)
project(core)
# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Instruct CMake to run moc automatically when needed.
set(CMAKE_AUTOMOC ON)
find_package(Qt5Core REQUIRED)
find_package(Qt5Gui REQUIRED)
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Xml REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -pedantic-errors -Werror -Wextra -O2 -g -fno-omit-frame-pointer -Woverloaded-virtual")
add_definitions(-DCORE_LIBRARY)
add_definitions(-DQT_PLUGIN)
add_definitions(-DQT_NO_DEBUG)
add_definitions(-DQT_SHARED)
add_library( core SHARED
src/reflect/TypeRegistry.h
src/Profiler.h
src/reflect/typeIdMacros.h
src/reflect/Reflect.h
src/AdapterManager.h
src/core_api.h
src/core.h
src/EnvisionApplication.h
src/EnvisionException.h
src/EnvisionManager.h
src/EnvisionPlugin.h
src/PluginInfo.h
src/global.h
src/precompiled.h
src/TestEvent.h
src/TestRunner.h
src/PluginManager.h
src/EnvisionWindow.h
src/reflect/TypeRegistry.cpp
src/Profiler.cpp
src/AdapterManager.cpp
src/EnvisionException.cpp
src/EnvisionManager.cpp
src/core.cpp
src/EnvisionApplication.cpp
src/TestEvent.cpp
src/TestRunner.cpp
src/PluginManager.cpp
src/EnvisionWindow.cpp
src/global.cpp )
target_link_libraries(core Qt5::Core Qt5::Widgets Qt5::Xml Qt5::Gui)
有了这个 CMakeLists.txt
文件,我可以 运行 cmake
并且它 运行 没有任何错误或警告。但是,当我 运行 make
我得到一个错误:
$ make
[ 7%] Automatic moc for target core
Generating moc_EnvisionApplication.cpp
Generating moc_EnvisionWindow.cpp
Generating moc_TestRunner.cpp
[ 7%] Built target core_automoc
Scanning dependencies of target core
[ 14%] Building CXX object CMakeFiles/core.dir/src/reflect/TypeRegistry.cpp.o
[ 21%] Building CXX object CMakeFiles/core.dir/src/Profiler.cpp.o
[ 28%] Building CXX object CMakeFiles/core.dir/src/AdapterManager.cpp.o
[ 35%] Building CXX object CMakeFiles/core.dir/src/EnvisionException.cpp.o
[ 42%] Building CXX object CMakeFiles/core.dir/src/EnvisionManager.cpp.o
[ 50%] Building CXX object CMakeFiles/core.dir/src/core.cpp.o
In file included from /store/envision/envision/Core/src/core.cpp:27:0:
/store/envision/envision/Core/src/EnvisionWindow.h:30:1: error: expected class-name before ‘{’ token
{
^
/store/envision/envision/Core/src/EnvisionWindow.h:31:2: error: ‘Q_OBJECT’ does not name a type
Q_OBJECT
^
...
如您所见,MOC 是 运行,但似乎带有 Q_OBJECT
宏的原始头文件被原样传递给 gcc,它自然不知道是什么 Q_OBJECT
是,因此失败。也许是旧版本,QMake 生成了新的头文件并使用了这些头文件而不是原来的头文件,或者以其他方式避免了这个问题。
有什么解决这个问题的想法吗?我在网上看了看,但没有找到明确的答案,我觉得应该有一个直接的解决方案。希望我不必修改任何源代码,因为这只是更大项目的一小部分。
我发现了这个问题,它很愚蠢,但我想解释一下,以防其他人在从 QMake 转换时遇到类似的问题。
由于我的代码使用 QMake 编译得很好,所以我没有查看 gcc 抱怨的实际源文件 EnvisionWindow.h
,认为这一定是构建问题。当我终于看到时,我看到这个文件包含 没有 包含,这就是编译器找不到 Q_OBJECT
.
的定义的原因
它与 QMake 一起工作的原因是因为该构建使用预编译的 header 和用于每个源文件的 -include
标志,从而注入所有必要的定义。这是在 QMake .pro
文件中使用 PRECOMPILED_HEADER = precompiled_header_name.h
时自动获得的行为。我希望 QMake 没有这样做,因为我项目中的所有文件都应该明确包含预编译的 header.
无论如何,解决方案很简单:将预编译的 header 包含在 EnvisionWindow.h
中,现在一切都可以正常编译了。
经验教训: 从字面上理解编译器错误。
我正在尝试将使用 Qt 5 和 Q_OBJECT
的共享库从 QMake 过渡到 CMake 3.2。这是当前 CMakeLists.txt
文件:
cmake_minimum_required(VERSION 3.2.2)
project(core)
# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Instruct CMake to run moc automatically when needed.
set(CMAKE_AUTOMOC ON)
find_package(Qt5Core REQUIRED)
find_package(Qt5Gui REQUIRED)
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Xml REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -pedantic-errors -Werror -Wextra -O2 -g -fno-omit-frame-pointer -Woverloaded-virtual")
add_definitions(-DCORE_LIBRARY)
add_definitions(-DQT_PLUGIN)
add_definitions(-DQT_NO_DEBUG)
add_definitions(-DQT_SHARED)
add_library( core SHARED
src/reflect/TypeRegistry.h
src/Profiler.h
src/reflect/typeIdMacros.h
src/reflect/Reflect.h
src/AdapterManager.h
src/core_api.h
src/core.h
src/EnvisionApplication.h
src/EnvisionException.h
src/EnvisionManager.h
src/EnvisionPlugin.h
src/PluginInfo.h
src/global.h
src/precompiled.h
src/TestEvent.h
src/TestRunner.h
src/PluginManager.h
src/EnvisionWindow.h
src/reflect/TypeRegistry.cpp
src/Profiler.cpp
src/AdapterManager.cpp
src/EnvisionException.cpp
src/EnvisionManager.cpp
src/core.cpp
src/EnvisionApplication.cpp
src/TestEvent.cpp
src/TestRunner.cpp
src/PluginManager.cpp
src/EnvisionWindow.cpp
src/global.cpp )
target_link_libraries(core Qt5::Core Qt5::Widgets Qt5::Xml Qt5::Gui)
有了这个 CMakeLists.txt
文件,我可以 运行 cmake
并且它 运行 没有任何错误或警告。但是,当我 运行 make
我得到一个错误:
$ make
[ 7%] Automatic moc for target core
Generating moc_EnvisionApplication.cpp
Generating moc_EnvisionWindow.cpp
Generating moc_TestRunner.cpp
[ 7%] Built target core_automoc
Scanning dependencies of target core
[ 14%] Building CXX object CMakeFiles/core.dir/src/reflect/TypeRegistry.cpp.o
[ 21%] Building CXX object CMakeFiles/core.dir/src/Profiler.cpp.o
[ 28%] Building CXX object CMakeFiles/core.dir/src/AdapterManager.cpp.o
[ 35%] Building CXX object CMakeFiles/core.dir/src/EnvisionException.cpp.o
[ 42%] Building CXX object CMakeFiles/core.dir/src/EnvisionManager.cpp.o
[ 50%] Building CXX object CMakeFiles/core.dir/src/core.cpp.o
In file included from /store/envision/envision/Core/src/core.cpp:27:0:
/store/envision/envision/Core/src/EnvisionWindow.h:30:1: error: expected class-name before ‘{’ token
{
^
/store/envision/envision/Core/src/EnvisionWindow.h:31:2: error: ‘Q_OBJECT’ does not name a type
Q_OBJECT
^
...
如您所见,MOC 是 运行,但似乎带有 Q_OBJECT
宏的原始头文件被原样传递给 gcc,它自然不知道是什么 Q_OBJECT
是,因此失败。也许是旧版本,QMake 生成了新的头文件并使用了这些头文件而不是原来的头文件,或者以其他方式避免了这个问题。
有什么解决这个问题的想法吗?我在网上看了看,但没有找到明确的答案,我觉得应该有一个直接的解决方案。希望我不必修改任何源代码,因为这只是更大项目的一小部分。
我发现了这个问题,它很愚蠢,但我想解释一下,以防其他人在从 QMake 转换时遇到类似的问题。
由于我的代码使用 QMake 编译得很好,所以我没有查看 gcc 抱怨的实际源文件 EnvisionWindow.h
,认为这一定是构建问题。当我终于看到时,我看到这个文件包含 没有 包含,这就是编译器找不到 Q_OBJECT
.
它与 QMake 一起工作的原因是因为该构建使用预编译的 header 和用于每个源文件的 -include
标志,从而注入所有必要的定义。这是在 QMake .pro
文件中使用 PRECOMPILED_HEADER = precompiled_header_name.h
时自动获得的行为。我希望 QMake 没有这样做,因为我项目中的所有文件都应该明确包含预编译的 header.
无论如何,解决方案很简单:将预编译的 header 包含在 EnvisionWindow.h
中,现在一切都可以正常编译了。
经验教训: 从字面上理解编译器错误。