LZR
LZR

Reputation: 958

QT QLibrary "Cannot load library *.so: (*.so: undefined symbol: staticMetaObject)"

I am working on a big project where I am trying to load dynamically a shared library with QLibrary, I was able to reproduce the run-time link error (undefined symbol: staticMetaObject) in the following example:

Folder structure:

root\
-- src\
---- TestLib\
------ TestLib.pro
------ Derived.h
------ Derived.cpp
------ TestLibModuleBridge.h
------ TestLibModuleBridge.cpp
---- TestLibCommon\
------ IBase.h
---- TestLibManager\
------ TestLibManager.pro
------ main.cpp
--lib\

TestLib files:

# TestLib.pro

QT       -= gui

TARGET = TestLib
TEMPLATE = lib

QMAKE_CXXFLAGS += -Wall

DEFINES += TESTLIB_LIBRARY

SOURCES += Derived.cpp \
    TestLibModuleBridge.cpp

HEADERS += Derived.h \
    TestLibModuleBridge.h

INCLUDEPATH += ../TestLibCommon

unix {
    target.path = ../../lib
    INSTALLS += target
}

-

// Derived.h

#ifndef DERIVED_H
#define DERIVED_H

#include "IBase.h"

#include <iostream>

class Derived : public IBase
{
    Q_OBJECT
public:
    Derived();
    virtual ~Derived();

public:
    virtual void methodA();
    virtual void methodB();
};

#endif // DERIVED_H

-

// Derived.cpp

#include "Derived.h"

Derived::Derived()
{

}

Derived::~Derived()
{

}

void Derived::methodA()
{
    std::cout << "methodA()" << std::endl;
}

void Derived::methodB()
{
    std::cout << "methodB()" << std::endl;
}

-

// TestLibModuleBridge.h

#ifndef TESTLIBMODULEBRIDGE_H
#define TESTLIBMODULEBRIDGE_H

#include "IBase.h"

#ifdef __cplusplus
extern "C" {
#endif
    IBase* getModuleInterface();
#ifdef __cplusplus
}
#endif

#endif // TESTLIBMODULEBRIDGE_H

-

// TestLibModuleBridge.cpp

#include "TestLibModuleBridge.h"
#include "Derived.h"

IBase* getModuleInterface()
{
    return new Derived();
}

TestLibManager Files:

// TestLibManager.pro

QT       += core

QT       -= gui

TARGET = TestLibManager
CONFIG   += console
CONFIG   -= app_bundle

QMAKE_CXXFLAGS += -Wall

TEMPLATE = app

SOURCES += main.cpp

INCLUDEPATH += ../TestLibCommon

-

// main.cpp
#include <QCoreApplication>
#include <QLibrary>
#include <QDebug>

#include "IBase.h"

typedef IBase* (*ModuleGetterFunction) (void);

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QLibrary testLib("../../lib/libTestLib.so");

    if (!testLib.load())
    {
        qDebug() << "Error : " << testLib.errorString();
        exit(EXIT_FAILURE);
    }
    else
    {
        ModuleGetterFunction getModuleInterfaceFunc = (ModuleGetterFunction) testLib.resolve("getModuleInterface");

        if (getModuleInterfaceFunc)
        {
            IBase* obj = getModuleInterfaceFunc();

            obj->methodA();
            obj->methodB();
        }
    }

    return a.exec();
}

TestLibCommon Files

// IBase.h

#ifndef IBASE_H
#define IBASE_H

#include <QObject>

class IBase : public QObject
{
    Q_OBJECT
protected:
    virtual ~IBase() {}

public:
    virtual void methodA() = 0;
    virtual void methodB() = 0;
};

#endif // IBASE_H

The testLib.load() fails with Error : "Cannot load library ../../lib/libTestLib.so: (../../lib/libTestLib.so: undefined symbol: _ZN5IBase16staticMetaObjectE)"

How can I fix this, removing Q_OBJECT macro from IBase.h will fix the error but in the production project that interface contains signals and slots, and it is from a project we're not allowed to change.

Upvotes: 4

Views: 3973

Answers (1)

Timo
Timo

Reputation: 1814

It looks like moc has not been run before compiling the testlib. moc is responsible for generating the staticMetaObject for classes which contain the Q_OBJECT Macro and are listed under the HEADERS section in the pro file.

Adding TestLibCommon\IBase.h to the HEADERS in TestLib.pro should probably fix this problem. (Untested).


Possible improvement of your solution:
Instead of using QLibrary take a look at QPluginLoader.

QPluginLoader will give you a QObject which you can then cast to any interface you want using qobject_cast<T*>(pluginloader.instance())

Here's an example using QPluginLoader: http://doc.qt.io/qt-5/qtwidgets-tools-plugandpaint-example.html

Upvotes: 4

Related Questions