将 CMake 与 Qt5 和 Qt 插件一起使用

Using CMake with Qt5 and Qt Plugins

我想避免使用 qmake.pro 文件。问题是我无法让 cmakeQt Plugins 很好地协同工作。我已经包含了下面的代码,显示了对给定 .pro 文件正常工作的接口、插件、加载程序,但我不知道如何将此功能传输到 cmake

插件界面

加载器已知的纯虚拟接口。

#include <QtCore/qglobal.h>

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

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

插件

成为 .so 由加载器加载的插件。

#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;
};

插件加载器

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

无法上班

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

有效

QT       += widgets

TARGET = HelloPlugin
TEMPLATE = lib

SOURCES += helloplugin.cpp

HEADERS += helloplugin.h \
    helloplugin_global.h

CONFIG += plugin debug

INSTALLS += target

Qt为插件生成元代码,在CMakeLists.txt中添加以下内容:

set(CMAKE_AUTOMOC ON)

这是一个完整的工作示例:

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

测试插件-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

测试-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

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