将 CMake 与 Qt5 和 Qt 插件一起使用
Using CMake with Qt5 and Qt Plugins
我想避免使用 qmake
和 .pro
文件。问题是我无法让 cmake
与 Qt 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();
}
}
我想避免使用 qmake
和 .pro
文件。问题是我无法让 cmake
与 Qt 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();
}
}