Is it possible to create QML component libraries where all of the QML files are in the binary and the engine still recognizes it just like QtQuick? So all of the QML files are bundled into the binary file (such as *.a
, *.lib
...) using *.qrc
files, and the user can import the library like this:
import Foo // Foo is library name
Bar { // Bar is component name.
// ...
}
Just like you would import QtQuick, and the QML engine recognizes it normally, like the library had a directory that had a qmldir
file that pointed to the QML files.
I tried putting the QML files and the qmldir
file in a QRC path and adding it as an import path to the QML engine, that did not work. Also, it is not the QML engine's fault, when I link against the library I for some reason cannot read the file (in the main function of the test application) with QFile
. And I did the QRC thing the same way you would do it for a normal application.
Hint: I found a piece of information in the Qt documentation that you should definitely read before even commenting.
Note 1: My version of Qt is Qt 6.6.1. Note 2: I am using CMake, not qmake.
Finally! I just solved it my self... but note that the solution omits qmldir
files or whatever. First you have to do the classic boilerplate for libraries and QML projects, second, you have to add a QRC file for your QML files to embed them in the binary, third, add this class to your project:
// Foo.h
#ifndef FOO_H
#define FOO_H
#include <QQmlEngineExtensionPlugin>
#include <QQmlApplicationEngine>
class Foo : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid)
public:
void registerTypes(const char *uri) override;
private:
};
[[maybe_unused]] void setupFoo(); // Do not remove [[maybe_unused]].
#endif //FOO_H
// Foo.cpp
#include <QmlTypeAndRevisionsRegistration>
#include "Foo.h"
void Foo::registerTypes(const char *uri)
{
// Register C++ types here:
// qmlRegisterType<Foo>("Bar", 1, 0, "Bar"); // This is for the QML components that are made with C++.
// Register QML types here:
qmlRegisterType(QUrl("qrc:/Foo/QML/MyComponent.qml"), "Foo", 1, 0, "Bar"); // This is the real deal, the answer to my question, this is a specific overload for qmlRegisterType() that register QML types, effectively avoiding qmldir files and engine import paths, making the setup extremely easy to do.
}
[[maybe_unused]] void setupFoo() // Do not remove [[maybe_unused]].
{
Q_INIT_RESOURCE(QML); //IMPORTANT: This is to initialize the resource explicitly because the linker might optimize and remove the auto generated code by RCC. This is so that the end user of the library can use the resources making Foo::registerTypes() work.
Foo().registerTypes("Foo"); // I would not have been forced to call the constructor if Foo::registerTypes() was static. But since it is a virtual function and is not static I cannot change this fact.
}