1

I am porting a project from Qmake to Cmake. Most of its utilities are now ok, and I already made the Cmake file for all of them. However, two projects are failing to compile on a "Undefined reference for vtable" linker error :

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

The class involved is a test class as expected by Qt Test. Here are the simplified project dependencies of the failing project :

TaskSingleTest -> needs TaskTestLib -> needs QtToolsLib

The RemoteJobsRunnerConfigurationTest stated in the error is part of TaskTestLib. It inherits AbstractJobConfigurationTest that is also part of TaskTestLib, which itself inherits from QtTestSuite that is from QtToolsLib.

The strange thing is that I have another test project already ported to Cmake that compiles and links well. Using it as an example, I noticed that those linking issues only happen with test classes from TaskTestLib. Other test libs (There have many) link fine. The issue would seem to be in the TaskTestLib project file, but it is nearly exactly the same as a working one. Here is TaskTestLib (failing lib) Cmake file :

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)

And ParsersTestLib (working lib) Cmake file :

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)

Here are the classes involved in the linking error :

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

I don't think posting QtTestSuite code or its project Cmake file is relevant as they compile and link fine with the other project using them. I've only posted the parts of the cpp file that I found relevant, but I can post more if asked (including other project files, etc...).

Does anyone have an idea of why is this project not linking?

EDIT

The answer to the related question here does not answer my problem :

  • My "Makefiles" are up to date, I regenerate them from Cmake and the problem still appears.
  • There are no unimplemented pure virtual functions. Someone raised the pure virtual CreateNewConfiguration() method in AbstractJobConfigurationTest, but the class is not being instanciated anywhere. It is its child class that is being instanciated, and it does implement the pure virtual method.

Also, please note that there is an existing qmake project for this project, and the qmake project is building and linking the project correctly, with the same source code. Therefore, I expect the issue to be in the Cmake files.

Mickaël C. Guimarães
  • 1,020
  • 2
  • 14
  • 32
  • That error (missing vtable) is quite common if you don't implement a non-pure virtual function. Are all virtual function defined and have an implementation? – Some programmer dude Jul 31 '18 at 01:31
  • 1
    Possible duplicate of [Undefined reference to vtable](https://stackoverflow.com/questions/3065154/undefined-reference-to-vtable) – 1201ProgramAlarm Jul 31 '18 at 01:37
  • 1
    As this is a `Qt` project my guess would be that these errors are caused by not linking with the code generated by [`moc`](http://doc.qt.io/qt-5/moc.html). – G.M. Jul 31 '18 at 07:29
  • 1
    While not answering the specific question, I suggest to avoid `file(GLOB SOURCES "../../src/*")`, any removal or addition of source files wouldn't be picked up. See https://cmake.org/cmake/help/latest/command/file.html – J-Christophe Jul 31 '18 at 07:54
  • Class `AbstractJobConfigurationTest` has *pure virtual* (`virtual ... = 0`) method. You definitely cannot instantiate this class (that is, create an object of this class). – Tsyvarev Jul 31 '18 at 07:58

1 Answers1

0

As pointed out by G.M., the issue was with moc files not being generated. Even though the CMAKE_AUTOMOC is set to ON, it fails to detect files with Q_OBJECT macro and generate their moc files.

The problem was that lib projects using Qt needed Qt5::Test in their dependencies. With this dependency missing, automoc didn't run. The single project that was compiling and linking fine without the dependency was working because of a mistake : the moc files had already been generated by Qmake and were present in the source folder.

Mickaël C. Guimarães
  • 1,020
  • 2
  • 14
  • 32