QtCS2021 - CMake API for QML modules
Session Summary
Let's talk about how we're supposed to write QML modules in Qt 6.2+. It differs quite a bit from what you're used to.
Session Owners
- Ulf Hermann (ulf.hermann@qt.io)
Notes
(Notes by alcroito)
Demoing qmake project
- Sharing Qt Creator screen
- Showing Qt Creator example with how to write qml plugins and qml modules in qmake
- Requires specific structure and lots of fancy qmake magic
- It is error prone
- It doesn't work with Qt static plugins
- It doesn't use qmlcachegen, nothing is copied to the resources
- Not documented, not many people really know what qml modules are
Demoing CMake project
- Showing new qml CMake API example
- Creates a new C++ library to be linked
- Need to specify the version, URI, c++ sources are optional, qml files are optional
- Can specify extra resources to embed (pngs)
- Can specify Qml dependencies (QtQuick, QtQml)
- Uses qmlcachegen to process the qml files, allows fast loading of qmls at runtime
- Packs the resources both into Qt resource files, and also puts it on the file system
- Creates qmldir file QML runtime and qmltypes files for the tooling (like Design Studio)
- Generates an optional library plugin, not needed if you directly link to the backing library
- The module can be built as both a dynamic library or a static library
- Much nicer and better way of building QML modules compared to before
Poll
Created a poll on how many attendants tried to create a QML module.
- 29% - I have written a QML module before
- 31% - I have not
- 6% - I didn't know I wrote a QML module
- 20 people didn't answer
Further freeform notes
A QML module can also be attached to any existing target, like an executable. It will compiled the QML module directly into the executable. You don't need a plugin or a backing library for that.
Showing how the executable source code just loads the copied main.qml from the file system. You can also have multiple QML modules in the same binary, by creating multiple static QML modules which will be linked into the executable.
You might have some QML modules that do need a plugin, because they provide a new image provider class. Just provide NO_PLUGIN_OPTIONAL and NO_CREATE_PLUGIN_SOURCE and specify a custom plugin.cpp. qmlRegister should not be explicitly called in plugin.cpp, it should be done declaratively.
How are QML plugins found? There's a concept qml import paths. One default import path is the current application directory path. There's also a global import path, the qml subdirectory of your Qt installation. You shouldn't put your plugins in there though, unless strictly necessary. Other import paths can be added from C++ as paths and Qt resource paths.
The CMkae API also allows specifying custom import paths to pass to qmlimportscanner, custom output directory, or custom resource prefixes.
Question about how to install plugins. Team hopes to make it easier by providing convenience in future Qt versions. Currently it's a manual process where the project needs to be bundle everything using existing CMake facilities
- qmldir files - qmltypes files - qml files - resources - optional plugin library
Pointed out that all of this should be documented more, but it's still fresh. https://bugreports.qt.io/browse/QTBUG-89274 This will be public API in 6.2. Some docs should be added to the Qt Quick best practices document.
WIP docs for the API can be found at https://codereview.qt-project.org/c/qt/qtdeclarative/+/354443
Question about what does install actually means. One approach is creating a bundle directory on which tools like *deployqt operate Another approach is creating an installable package like a linux distribution does These aspects are still to be figured out There are internal APIs to install everything into Qt's default path, but you don't usually want that for user projects. Something like that might become public API.
Question about offering convenience CMake API to export qml module targets as cmake packages, to be reusable in other cmake projects. There is not builtin convenience at the moment, but it can already be achieved using existing CMake facilities.
Another advantage of using the QML API is that we create qmllint custom CMake target, so that qmllint tool can be run on the qml sources.
Some feedback that a previous project had to spent lots of time to try and modularize a QML module with qmake, and it was very hard So new API is nice addition
One feedback point: Hmm... One tiny note, guessing it's too late to make that strict now, but perhaps adding in the option to add an explicit TARGET before the target you want to operate on would be good? Seems to be how many other things work :) (to say that you're operating on an existing target as opposed to creating a new one... just syntactic sugar, but it'd read nice :) )
Answer: It's pretty common for CMake commands that operate on a target to take the target as the first argument (with no keyword). Eg target_link_libraries(target...) etc. And the target is a mandatory argument, most of the rest are not.
Question: What do we do qmake? No new API for qmake, it's pretty hard to make it better in qmake There's one existing abstraction load(qml_module), but it's internal API only available for the qt build However qmake doesn't really have a concept of QML modules Not high priority to try and adress that
There will be future work to improve performance of properly defined QML modules, by leveraging the qml object compiler.