Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using CMake with Qt5 and Qt Plugins

Tags:

c++

cmake

qt

qt5

qmake

I'd like to avoid using qmake and .pro files. The problem is that I cannot get cmake to work nicely with Qt Plugins. I've included the code below showing the interface, plugin, loader that work correctly for the given .pro file but I cannot figure out how to transfer this functionality to cmake.

Plugin Interface

Pure virtual interface, known by the loader.

#include <QtCore/qglobal.h>

class HelloPluginInterface
{
public:
    virtual void DoSomething() const = 0;
};

Q_DECLARE_INTERFACE( HelloPluginInterface, "com.harbrick.Qt.HelloPluginInterface")

Plugin

Plugin that becomes a .so to be loaded by the loader.

#include <QtPlugin>
#include "helloplugin_global.h"

class HelloPlugin : public QObject, public HelloPluginInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA( IID "com.harbrick.Qt.HelloPluginInterface" )
    Q_INTERFACES( HelloPluginInterface )

public:
    void DoSomething() const;
};

Plugin Loader

void MainWindow::LoadPlugin( const QString& pathToLibrary )
{
    QPluginLoader loader( pathToLibrary );
    QObject* instance = loader.instance();

    if( instance )
    {
        HelloPluginInterface *plugin = qobject_cast< HelloPluginInterface* >( instance );
        if(plugin)
        {
            //do stuff
            ...
        }
        else
        {
            qDebug() << "Not a plugin: " << Filename << " = " << loader.errorString();
        }
    }
}

CMakeLists.txt

Can't get to work

project( HelloPlugin )
cmake_minimum_required( VERSION 2.8.11 )

set( CMAKE_INCLUDE_CURRENT_DIR ON )

find_package(Qt5Widgets)

include_directories( 
    ${CMAKE_CURRENT_SOURCE_DIR} 
)

set( INCLUDE
    cmakeplugin.h
    cmakeplugininterface.h
)

set( SOURCES
    cmakeplugin.cpp
)

add_executable(${PROJECT_NAME} ${INCLUDE} ${SOURCES} ${SRC_LIST})

add_library( cmakePlugin SHARED cmakeplugin.cpp )

QMake .pro

Works

QT       += widgets

TARGET = HelloPlugin
TEMPLATE = lib

SOURCES += helloplugin.cpp

HEADERS += helloplugin.h \
    helloplugin_global.h

CONFIG += plugin debug

INSTALLS += target
like image 515
davepmiller Avatar asked Jun 03 '15 19:06

davepmiller


1 Answers

Qt generates meta code for plugins, add the following to CMakeLists.txt:

set(CMAKE_AUTOMOC ON)

Here's a complete working example:

CMakeLists.txt

project(test-plugin)
cmake_minimum_required(VERSION 3.2.0)

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)

find_package(Qt5Widgets REQUIRED)

set(COMPILE_OPTIONS -std=c++11)

add_library(test-plugin SHARED test-plugin.cpp)
target_link_libraries(test-plugin PRIVATE Qt5::Widgets)
target_compile_options(test-plugin PRIVATE ${COMPILE_OPTIONS})

add_executable(test-plugin-exec main.cpp)
target_link_libraries(test-plugin-exec PRIVATE Qt5::Widgets)
target_compile_options(test-plugin-exec PRIVATE ${COMPILE_OPTIONS})

test-plugin-interface.hpp

#ifndef TEST_PLUGIN_INTERFACE
#define TEST_PLUGIN_INTERFACE
#include <QtPlugin>

class TestPluginInterface
{
public:
    virtual ~TestPluginInterface() {}
    virtual void doSomething() const = 0;
};

#define TestPluginInterface_iid "whatever.you.want.TestPluginInterface"
Q_DECLARE_INTERFACE(TestPluginInterface, TestPluginInterface_iid)
#endif // TEST_PLUGIN_INTERFACE

test-plugin.hpp

#ifndef TEST_PLUGIN_HPP
#define TEST_PLUGIN_HPP
#include <QObject>
#include <QtPlugin>
#include "test-plugin-interface.hpp"

class TestPlugin : public QObject, public TestPluginInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID TestPluginInterface_iid)
    Q_INTERFACES(TestPluginInterface)

public:
    ~TestPlugin() override {}
    void doSomething() const override;
};
#endif // TEST_PLUGIN_HPP

test-plugin.cpp

#include <QDebug>
#include "test-plugin.hpp"

void TestPlugin::doSomething() const
{
    qDebug()<< "hot dog!";
}

main.cpp

#include <assert.h>
#include <QDebug>
#include <QPluginLoader>
#include "test-plugin.hpp"

constexpr auto ABSOLUTE_PATH_TO_PLUGIN = 
    "/path/to/build/libtest-plugin.so";

int main(int argc, char* argv[])
{
    assert(QLibrary::isLibrary(ABSOLUTE_PATH_TO_PLUGIN));
    QPluginLoader loader(ABSOLUTE_PATH_TO_PLUGIN);
    if (auto instance = loader.instance()) {
        if (auto plugin = qobject_cast< TestPluginInterface* >(instance)){
            plugin->doSomething();
        }
        else {
            qDebug()<< "qobject_cast<> returned nullptr";
        }
    }
    else {
      qDebug()<< loader.errorString();
    }
}
like image 62
davepmiller Avatar answered Oct 17 '22 08:10

davepmiller