"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 avtable for RemoteJobsRunnerConfigurationTest' TaskTestLib/libTaskTestLib.a(abstractjobconfigurationtest.cpp.o): na função AbstractJobConfigurationTest::AbstractJobConfigurationTest()': abstractjobconfigurationtest.cpp:(.text+0x2315): referência indefinida avtable 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 的答案没有回答我的问题:

此外,请注意该项目已有一个 qmake 项目,正在构建 qmake 项目并link正确地 构建该项目,与源代码。因此,我希望问题出在 Cmake 文件中。

正如 G.M 所指出的,问题在于未生成 moc 文件。即使 CMAKE_AUTOMOC 设置为 ON,它也无法检测带有 Q_OBJECT 宏的文件并生成它们的 moc 文件。

问题是使用 Qt 的 lib 项目在它们的依赖项中需要 Qt5::Test。由于缺少此依赖项,automoc 没有 运行。由于一个错误,在没有依赖项的情况下编译和链接正常的单个项目正在运行:moc 文件已经由 Qmake 生成并存在于源文件夹中。