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
.
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 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;
};
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();
}
}
}
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 )
Works
QT += widgets
TARGET = HelloPlugin
TEMPLATE = lib
SOURCES += helloplugin.cpp
HEADERS += helloplugin.h \
helloplugin_global.h
CONFIG += plugin debug
INSTALLS += target
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();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With