【问题标题】:"Undefined reference for vtable" on a Cmake Project ported from Qmake从 Qmake 移植的 Cmake 项目上的“未定义的 vtable 引用”
【发布时间】:2018-07-31 01:29:17
【问题描述】:

我正在将一个项目从 Qmake 移植到 Cmake。它的大多数实用程序现在都可以了,我已经为所有这些实用程序制作了 Cmake 文件。 但是,两个项目因“未定义的 vtable 引用”链接器错误而无法编译:

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:错误:ld 返回 1 个退出状态

所涉及的类是 Qt Test 所期望的测试类。以下是失败项目的简化项目依赖关系:

TaskSingleTest -> 需要TaskTestLib -> 需要QtToolsLib

错误中所述的RemoteJobsRunnerConfigurationTest 是TaskTestLib 的一部分。它继承了 AbstractJobConfigurationTest,它也是 TaskTestLib 的一部分,TaskTestLib 本身继承自 QtToolsLib 的 QtTestSuite。

奇怪的是我有另一个测试项目已经移植到Cmake,编译和链接都很好。以它为例,我注意到这些链接问题只发生在来自 TaskTestLib 的测试类中。其他测试库(有很多)链接很好。 问题似乎在 TaskTestLib 项目文件中,但它几乎与工作文件完全相同。 这是TaskTestLib(失败的lib)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)

以下是链接错误中涉及的类:

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();
}

我不认为发布 QtTestSuite 代码或其项目 Cmake 文件是相关的,因为它们可以很好地编译并与使用它们的其他项目链接。 我只发布了我认为相关的 cpp 文件部分,但如果有要求,我可以发布更多内容(包括其他项目文件等...)。

有人知道为什么这个项目没有链接吗?

编辑

相关问题here的答案没有回答我的问题:

  • 我的“Makefile”是最新的,我从 Cmake 重新生成它们,但问题仍然存在。
  • 没有未实现的纯虚函数。有人在 AbstractJobConfigurationTest 中提出了纯虚拟 CreateNewConfiguration() 方法,但该类没有在任何地方实例化。实例化的是它的子类,它确实实现了纯虚方法。

另外,请注意,该项目有一个现有的 qmake 项目,并且 qmake 项目正在正确构建和链接该项目,具有相同的源代码。因此,我预计问题出在 Cmake 文件中。

【问题讨论】:

  • 如果您不实现非纯虚函数,该错误(缺少 vtable)很常见。是否所有虚函数都已定义并有实现?
  • 由于这是一个Qt 项目,我猜这些错误是由于没有链接到moc 生成的代码造成的。
  • 虽然没有回答具体问题,但我建议避免file(GLOB SOURCES "../../src/*"),任何删除或添加源文件都不会被拾取。见cmake.org/cmake/help/latest/command/file.html
  • AbstractJobConfigurationTest 具有 纯虚拟 (virtual ... = 0) 方法。你绝对不能实例化这个类(即创建这个类的对象)。

标签: c++ cmake linker-errors


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-14
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    相关资源
    最近更新 更多