"Undefined reference for vtable" 在从 Qmake 移植的 Cmake 项目上
"Undefined reference for vtable" on a Cmake Project ported from Qmake
我正在将一个项目从 Qmake 移植到 Cmake。它的大部分实用程序现在都可以了,我已经为所有这些实用程序制作了 Cmake 文件。
但是,两个项目无法编译 "Undefined reference for vtable" linker 错误:
TaskTestLib/libTaskTestLib.a(remotejobsrunnerconfigurationtest.cpp.o): na função RemoteJobsRunnerConfigurationTest::RemoteJobsRunnerConfigurationTest()':
remotejobsrunnerconfigurationtest.cpp:(.text+0x2293): referência indefinida a
vtable for RemoteJobsRunnerConfigurationTest'
TaskTestLib/libTaskTestLib.a(abstractjobconfigurationtest.cpp.o): na função AbstractJobConfigurationTest::AbstractJobConfigurationTest()':
abstractjobconfigurationtest.cpp:(.text+0x2315): referência indefinida a
vtable for AbstractJobConfigurationTest'
collect2: error: ld returned 1 exit status
涉及的class是Qt Test预期的测试class。以下是失败项目的简化项目依赖关系:
TaskSingleTest -> 需要 TaskTestLib -> 需要 QtToolsLib
错误中所述的 RemoteJobsRunnerConfigurationTest 是 TaskTestLib 的一部分。它继承了 AbstractJobConfigurationTest,它也是 TaskTestLib 的一部分,它本身继承自来自 QtToolsLib 的 QtTestSuite。
奇怪的是,我有另一个测试项目已经移植到编译的 Cmake 并且link很好。以它为例,我注意到那些 linking 问题只发生在来自 TaskTestLib 的测试 classes 中。其他测试库(有很多)link 很好。 问题似乎出在 TaskTestLib 项目文件中,但它与工作文件几乎完全相同。
这是 TaskTestLib(失败的库)Cmake 文件:
cmake_minimum_required (VERSION 3.2)
project (TaskTestLib)
file(GLOB SOURCES "../../src/*")
set(INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../src/")
add_library(TaskTestLib ${SOURCES})
set_target_properties(TaskTestLib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${INCLUDE_DIR}")
target_link_libraries (TaskTestLib TaskLib QtToolsLib)
和 ParsersTestLib(工作库)Cmake 文件:
cmake_minimum_required (VERSION 3.2)
project (ParsersTestLib)
file(GLOB SOURCES "../../src/*")
set(INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../src/")
add_library(ParsersTestLib ${SOURCES})
set_target_properties(ParsersTestLib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${INCLUDE_DIR}")
target_link_libraries (ParsersTestLib ParsersLib QtToolsLib)
这是 linking 错误中涉及的 classes :
class RemoteJobsRunnerConfigurationTest : public AbstractJobConfigurationTest
{
Q_OBJECT
public:
RemoteJobsRunnerConfigurationTest() = default;
//RemoteJobsRunnerConfigurationTest();
virtual ~RemoteJobsRunnerConfigurationTest() = default;
private Q_SLOTS:
void testConfigure_ConfFileProperty();
void testConfigure_TimedRunProperty_data();
void testConfigure_TimedRunProperty();
protected:
AbstractJobConfiguration* CreateNewConfiguration() const override;
private:
void TestConfFileProperty(const std::string& propertyValue);
void TestTimedRunProperty(const std::string& propertyValue, const bool expectedValue);
};
class AbstractJobConfigurationTest : public QtTestSuite
{
Q_OBJECT
public:
AbstractJobConfigurationTest();
virtual ~AbstractJobConfigurationTest() = default;
private Q_SLOTS:
void testConfigure_NullConfiguration();
void testConfigure_UnknownProperty();
void testConfigure_UnknownSubObject();
protected:
AbstractJob *TestConfiguration(ConfigurationObject* confObject,
const std::vector<std::string>& expectedErrorMessages);
AbstractJob *TestConfigurationWithoutErrors(ConfigurationObject* confObject);
virtual AbstractJobConfiguration* CreateNewConfiguration() const = 0;
ConfigurationObject* CreateSimpleConfigurationObject(
const std::string& property, const std::string& value);
private:
AbstractJob* RunConfiguration(ConfigurationObject* confObject,
std::vector<std::string> &errorMessages);
void CheckErrorMessages(const std::vector<std::string> &errorMessages,
const std::vector<std::string> &expectedErrorMessages);
std::string BuildUnknownError(const std::string& object,
const std::string& name) const;
};
AbstractJobConfigurationTest::AbstractJobConfigurationTest()
: QtTestSuite("", "")
{
}
AbstractJobConfiguration*RemoteJobsRunnerConfigurationTest::CreateNewConfiguration() const
{
return new RemoteJobsRunnerConfiguration();
}
我不认为 posting QtTestSuite 代码或其项目 Cmake 文件是相关的,因为它们编译并且 link 与使用它们的其他项目无关。
我只 post 编辑了 cpp 文件中我发现相关的部分,但如果有人问我我可以 post 更多(包括其他项目文件等)。
有人知道为什么这个项目没有 link 吗?
编辑
相关问题 here 的答案没有回答我的问题:
- 我的 "Makefiles" 是最新的,我从 Cmake 重新生成它们,问题仍然出现。
- 没有未实现的纯虚函数。有人在 AbstractJobConfigurationTest 中提出了纯虚拟 CreateNewConfiguration() 方法,但是 class 没有在任何地方实例化。正在实例化的是它的子 class,它确实实现了纯虚方法。
此外,请注意该项目已有一个 qmake 项目,正在构建 qmake 项目并link正确地 构建该项目,与源代码。因此,我希望问题出在 Cmake 文件中。
正如 G.M 所指出的,问题在于未生成 moc 文件。即使 CMAKE_AUTOMOC 设置为 ON,它也无法检测带有 Q_OBJECT 宏的文件并生成它们的 moc 文件。
问题是使用 Qt 的 lib 项目在它们的依赖项中需要 Qt5::Test。由于缺少此依赖项,automoc 没有 运行。由于一个错误,在没有依赖项的情况下编译和链接正常的单个项目正在运行:moc 文件已经由 Qmake 生成并存在于源文件夹中。
我正在将一个项目从 Qmake 移植到 Cmake。它的大部分实用程序现在都可以了,我已经为所有这些实用程序制作了 Cmake 文件。 但是,两个项目无法编译 "Undefined reference for vtable" linker 错误:
TaskTestLib/libTaskTestLib.a(remotejobsrunnerconfigurationtest.cpp.o): na função
RemoteJobsRunnerConfigurationTest::RemoteJobsRunnerConfigurationTest()': remotejobsrunnerconfigurationtest.cpp:(.text+0x2293): referência indefinida a
vtable for RemoteJobsRunnerConfigurationTest' TaskTestLib/libTaskTestLib.a(abstractjobconfigurationtest.cpp.o): na funçãoAbstractJobConfigurationTest::AbstractJobConfigurationTest()': abstractjobconfigurationtest.cpp:(.text+0x2315): referência indefinida a
vtable for AbstractJobConfigurationTest' collect2: error: ld returned 1 exit status
涉及的class是Qt Test预期的测试class。以下是失败项目的简化项目依赖关系:
TaskSingleTest -> 需要 TaskTestLib -> 需要 QtToolsLib
错误中所述的 RemoteJobsRunnerConfigurationTest 是 TaskTestLib 的一部分。它继承了 AbstractJobConfigurationTest,它也是 TaskTestLib 的一部分,它本身继承自来自 QtToolsLib 的 QtTestSuite。
奇怪的是,我有另一个测试项目已经移植到编译的 Cmake 并且link很好。以它为例,我注意到那些 linking 问题只发生在来自 TaskTestLib 的测试 classes 中。其他测试库(有很多)link 很好。 问题似乎出在 TaskTestLib 项目文件中,但它与工作文件几乎完全相同。 这是 TaskTestLib(失败的库)Cmake 文件:
cmake_minimum_required (VERSION 3.2)
project (TaskTestLib)
file(GLOB SOURCES "../../src/*")
set(INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../src/")
add_library(TaskTestLib ${SOURCES})
set_target_properties(TaskTestLib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${INCLUDE_DIR}")
target_link_libraries (TaskTestLib TaskLib QtToolsLib)
和 ParsersTestLib(工作库)Cmake 文件:
cmake_minimum_required (VERSION 3.2)
project (ParsersTestLib)
file(GLOB SOURCES "../../src/*")
set(INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../src/")
add_library(ParsersTestLib ${SOURCES})
set_target_properties(ParsersTestLib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${INCLUDE_DIR}")
target_link_libraries (ParsersTestLib ParsersLib QtToolsLib)
这是 linking 错误中涉及的 classes :
class RemoteJobsRunnerConfigurationTest : public AbstractJobConfigurationTest
{
Q_OBJECT
public:
RemoteJobsRunnerConfigurationTest() = default;
//RemoteJobsRunnerConfigurationTest();
virtual ~RemoteJobsRunnerConfigurationTest() = default;
private Q_SLOTS:
void testConfigure_ConfFileProperty();
void testConfigure_TimedRunProperty_data();
void testConfigure_TimedRunProperty();
protected:
AbstractJobConfiguration* CreateNewConfiguration() const override;
private:
void TestConfFileProperty(const std::string& propertyValue);
void TestTimedRunProperty(const std::string& propertyValue, const bool expectedValue);
};
class AbstractJobConfigurationTest : public QtTestSuite
{
Q_OBJECT
public:
AbstractJobConfigurationTest();
virtual ~AbstractJobConfigurationTest() = default;
private Q_SLOTS:
void testConfigure_NullConfiguration();
void testConfigure_UnknownProperty();
void testConfigure_UnknownSubObject();
protected:
AbstractJob *TestConfiguration(ConfigurationObject* confObject,
const std::vector<std::string>& expectedErrorMessages);
AbstractJob *TestConfigurationWithoutErrors(ConfigurationObject* confObject);
virtual AbstractJobConfiguration* CreateNewConfiguration() const = 0;
ConfigurationObject* CreateSimpleConfigurationObject(
const std::string& property, const std::string& value);
private:
AbstractJob* RunConfiguration(ConfigurationObject* confObject,
std::vector<std::string> &errorMessages);
void CheckErrorMessages(const std::vector<std::string> &errorMessages,
const std::vector<std::string> &expectedErrorMessages);
std::string BuildUnknownError(const std::string& object,
const std::string& name) const;
};
AbstractJobConfigurationTest::AbstractJobConfigurationTest()
: QtTestSuite("", "")
{
}
AbstractJobConfiguration*RemoteJobsRunnerConfigurationTest::CreateNewConfiguration() const
{
return new RemoteJobsRunnerConfiguration();
}
我不认为 posting QtTestSuite 代码或其项目 Cmake 文件是相关的,因为它们编译并且 link 与使用它们的其他项目无关。 我只 post 编辑了 cpp 文件中我发现相关的部分,但如果有人问我我可以 post 更多(包括其他项目文件等)。
有人知道为什么这个项目没有 link 吗?
编辑
相关问题 here 的答案没有回答我的问题:
- 我的 "Makefiles" 是最新的,我从 Cmake 重新生成它们,问题仍然出现。
- 没有未实现的纯虚函数。有人在 AbstractJobConfigurationTest 中提出了纯虚拟 CreateNewConfiguration() 方法,但是 class 没有在任何地方实例化。正在实例化的是它的子 class,它确实实现了纯虚方法。
此外,请注意该项目已有一个 qmake 项目,正在构建 qmake 项目并link正确地 构建该项目,与源代码。因此,我希望问题出在 Cmake 文件中。
正如 G.M 所指出的,问题在于未生成 moc 文件。即使 CMAKE_AUTOMOC 设置为 ON,它也无法检测带有 Q_OBJECT 宏的文件并生成它们的 moc 文件。
问题是使用 Qt 的 lib 项目在它们的依赖项中需要 Qt5::Test。由于缺少此依赖项,automoc 没有 运行。由于一个错误,在没有依赖项的情况下编译和链接正常的单个项目正在运行:moc 文件已经由 Qmake 生成并存在于源文件夹中。