我正在开发使用Qt 远程对象的项目,并且我想使用自动生成的ReplicaDefSimpleSource
类来测试我的一个组件(有关详细信息,请参见下面的示例)。但是,当我尝试将测试可执行文件与我的库链接时,出现以下链接器错误:
main.obj : error LNK2001: unresolved external symbol "public: static struct QMetaObject const ReplicaDefSimpleSource::staticMetaObject" (?staticMetaObject@ReplicaDefSimpleSource@@2UQMetaObject@@B)
我MyLib.dll
用 DependencyWalker 检查了我的,所需的符号在那里:
79 (0x004f), 78 (0x0000004e), public: static struct QMetaObject const ReplicaDefSimpleSource::staticMetaObject, 0x00018370, Microsoft
我也检查dumpbin /EXPORTS Debug/MyLib.lib | grep "static struct QMetaObject"
了,所需的符号又在那里:
?staticMetaObject@ReplicaDefSimpleSource@@2UQMetaObject@@B (public: static struct QMetaObject const ReplicaDefSimpleSource::staticMetaObject)
为了构建我使用 CMake 的项目:
cmake -G "Visual Studio 15 2017 Win64" ../
cmake --build . --config Debug
要重现该问题,您需要以下文件:
CMakeLists.txt
:
cmake_minimum_required(VERSION 3.11)
project(test_project)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set (CMAKE_CXX_STANDARD 17)
find_package(Qt5 COMPONENTS
Core REQUIRED
RemoteObjects REQUIRED
Test REQUIRED
)
qt5_generate_repc(GENERATED ReplicaDef.rep SOURCE)
qt5_generate_repc(GENERATED ReplicaDef.rep REPLICA)
set_source_files_properties(${GENERATED} PROPERTIES GENERATED TRUE SKIP_AUTOMOC TRUE)
add_library(MyLib SHARED a.cpp ${GENERATED})
set_target_properties(MyLib PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
target_link_libraries(MyLib
Qt5::Core
Qt5::RemoteObjects
)
add_executable(main main.cpp
# moc_rep_ReplicaDef_source.cpp
)
target_link_libraries(main MyLib Qt5::Test)
main.cpp
: 是的,我知道这不是你应该如何测试 Qt 代码,我只是将它用作最小示例(例如它没有QApplication
)
#include "rep_ReplicaDef_source.h"
#include <QTest>
#include <QSignalSpy>
#include <QUrl>
#include <memory>
void foo();
int main()
{
foo(); // here no problem with linker
ReplicaDefSimpleSource source;
QRemoteObjectHost host;
host.setHostUrl(QUrl{ "local:main" });
host.enableRemoting(&source);
// QSignalSpy is using staticMetaObject that linker complains about
QSignalSpy spy(&source, &ReplicaDefSimpleSource::settingsChanged);
spy.wait(1000);
return 0;
}
ReplicaDef.rep
:
#include <QtCore>
#include <QString>
class ReplicaDef
{
PROP(QString settings);
};
a.cpp
:它实际上可以是任何东西,我只是放了一些虚拟函数来显示来自的符号a.cpp
是可见的
#include <iostream>
void foo() { std::cout << "foo" << std::endl; }
作为一种解决方法,我可以在我的测试中明确包含自动生成的源,但这不是可接受的解决方案。
add_executable(main main.cpp
moc_rep_ReplicaDef_source.cpp
)
提供的示例当然可以在任何正常系统上编译和工作,我只是在 windows 上遇到问题,我不得不使用它(很抱歉问这个平台的问题)。
我应该怎么做才能使用自动生成的副本类来测试我的系统,而不需要多次编译它们的源?
作为一个附带问题:如果我在主可执行文件中包含副本源,为什么链接器不会抱怨多个定义?
=== 编辑 ===
为了确保当我用我的手写代码编译 Qt 自动生成的代码时不会发生任何奇怪的事情,我尝试将副本源放在一个单独的库中:
qt5_generate_repc(GENERATED ReplicaDef.rep SOURCE)
qt5_generate_repc(GENERATED ReplicaDef.rep REPLICA)
set_source_files_properties(${GENERATED} PROPERTIES GENERATED TRUE SKIP_AUTOMOC TRUE)
add_library(MyLib-replica SHARED ${GENERATED})
target_link_libraries(MyLib-replica
Qt5::Core
Qt5::RemoteObjects
)
set_target_properties(MyLib-replica PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
add_library(MyLib SHARED a.cpp)
set_target_properties(MyLib PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
target_link_libraries(MyLib
MyLib-replica
)
但问题仍然存在。如果我没有在每个目标中明确包含自动生成的源,则缺少符号。