简体   繁体   中英

Creating a Qt qml C++ Plugin with CMake

I'm trying to create a C++ qml plugin using cmake (instead of using QtCreator ). Here's a dummy project mimicking my plugin setup:

./CMakeLists.txt

project(circle_plugin)

find_package(Qt5 COMPONENTS Core Qml Quick REQUIRED)

set(HEADERS
    include/Circle.hpp
    include/Plugin.hpp
    )

add_library(circle_plugin STATIC ${HEADERS})

set_target_properties(circle_plugin PROPERTIES AUTOMOC ON)
target_link_libraries(circle_plugin PUBLIC Qt5::Core Qt5::Qml Qt5::Quick)
target_include_directories(circle_plugin PUBLIC include)

./include/Circle.hpp

#pragma once

#include <QObject>

namespace test {

class Circle: public QQuickItem {
    Q_OBJECT

public:
    Circle(QQuickItem* parent = nullptr);
    virtual ~Circle() = default;
};

} // namespace test

./include/Plugin.hpp

#pragma once

#include <QObject>

namespace test {

class CirclePlugin : public QQmlExtensionPlugin {
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "com.test.CirclePlugin")

public:
    CirclePlugin();
    ~CirclePlugin();

    void registerTypes(const char *uri) {
        Q_ASSERT(uri == QLatin1String("CirclePlugin"));
        qmlRegisterType<Circle>(uri, 1, 0, "Circle");
    }
};

} // namespace test

./qml/View.qml

import QtQuick 2.2
import CirclePlugin 1.0

Item {

    Circle {
    }

}

I'm linking to circle_plugin from my main application. Whenever I import CirclePlugin 1.0 in my main app's qml files, I get the message module "Circle" is not installed .

I've found the following guides on the topic, but I'm still unsure how I can get it working.

QML Plugin Example

CMake Maunal

Following the comments in the question, we found out that QtQuick plugins must indeed be installed before being found and used by other QtQuick applications or plugins * . This means that:

  1. The plugin must be in its own project which is composed of Plugin.hpp and (at least) a qmldir file (assuming that Plugin.hpp is built into a plugin library named libcircleplugin.so ) that looks like:

     module CirclePlugin plugin circleplugin 
  2. The plugin (ie libcircleplugin.so and qmldir ) must be installed inside QT_ROOT/QT_VERSION/ARCHITECTURE/qml/CirclePlugin/

Some detailed information about this procedure can be found at http://doc.qt.io/qt-5/qtqml-modules-cppplugins.html

Of course, this is all assuming that you use qmake with a circle-plugin.pro file such as:

QT += qml quick
CONFIG += qt c++ nostrip plugin
CONFIG -= android_install #If you care about Android

HEADERS += Plugin.hpp

TEMPLATE = lib
TARGET = circleplugin

TARGET = $$qtLibraryTarget($$TARGET)
uri = CirclePlugin
qmldir.files = qmldir
OTHER_FILES += qmldir.files

installPath = $$[QT_INSTALL_QML]/$$replace(uri, \\., /)
qmldir.path = $$installPath
target.path = $$installPath
INSTALLS += target qmldir

With this, you can make install and your plugin will be found just like any other QtQuick module which are themselves such plugins. This procedure must also be replicated using cmake if similar behavior is desired. This requires QT_INSTALL_QML to be known which can be queried by executing qmake -query QT_INSTALL_QML . Important note : This is not a sandboxed approach since it modifies the Qt SDK itself. Be aware that this is evil but also is the current best solution.


* While this is true for Android (see What is the proper way of deploying C++ QML plugins on mobile device? ), a work around is possible on desktop by setting QML2_IMPORT_PATH or QT_PLUGIN_PATH environment variables to where you installed your plugins (none of which is well documented; in fact, this whole issue is still not well documented to this day). The problem with Android is that the plugin does not get bundled into the apk as long as it is not in QT_INSTALL_QML so the final application cannot find the plugin; ie it must get the same treatment as the other official qml plugins. Manual installation and bundling efforts were fruitless from our side, the plugin was just not found during runtime even if manually forced into the apk (by going as far as writing custom android-libapplication.so-deployment-settings.json files per application). A discussion (that went pretty much nowhere beyond qmake -query QT_INSTALL_QML ) on this topic is in https://bugreports.qt.io/browse/QTBUG-29987 . This brings me to my actual point which is below:


Why should qmake be preferred over cmake when building Qt plugins/apps?

Although I believe that cmake is not only more general but altogether a superior build system to qmake , qmake still has internals that are sometimes needed (such as QT_INSTALL_QML ) and is actually maintained by Qt for Qt and its applications/plugins. Support for cmake for Qt will always be external (and "crippling" as stated by Qt developers themselves). This means potentially more maintenance load in the future on your side as developer, as the solutions to such problems as the above may randomly break with new versions.

I too once dreamed of building my Qt plugins and apps nicely with cmake and also maybe cross-compiling them with .toolchain.cmake 's like https://github.com/taka-no-me/android-cmake . I quickly found out that it is simply not worth doing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM