#c #visual-c #qtremoteobjects
#c #visual-c #qtremoteobjects
Вопрос:
Я работаю над проектом, в котором используются удаленные объекты 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(amp;source);
// QSignalSpy is using staticMetaObject that linker complains about
QSignalSpy spy(amp;source, amp;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
)
но проблема остается той же. Пропущенные символы, если я не включаю автоматически созданные источники явно в каждую цель.