KDAB / cxx-qt

Safe interop between Rust and Qt
https://kdab.github.io/cxx-qt/book/
1.04k stars 74 forks source link

ahead-of-time compilation of QML #242

Closed Be-ing closed 1 year ago

Be-ing commented 2 years ago

It would be nice if qt-build could call qmlcachegen (Qt5) or qmlsc (Qt6).

https://www.qt.io/blog/the-new-qtquick-compiler-technology

However qmlsc is not open source yet:

qmlsc is available for commercial customers and some of its features are merged into qmlcachegen, which continues to be available with all versions of Qt.

https://doc.qt.io/qt-6/qtqml-tool-qmlsc.html

ahayzen-kdab commented 2 years ago

There is also the qmltc https://doc.qt.io/qt-6/qtqml-tool-qmltc.html https://www.qt.io/blog/qml-type-compilation

And we should support commercial tools as well.

Be-ing commented 1 year ago

After reading various posts on the Qt blog and the documentation for the upcoming Qt 6.5 release, I have a better understanding of the various QML processing tools and how to approach this.

Originally, in Qt 5, qmlcachegen only generated precompiled bytecode from QML files to improve startup performance. qmake could automatically call qmlcachegen and add the generated bytecode to the Qt resource system. In Qt 5, qmlcachegen didn't optimize runtime performance though.

This has changed in Qt6. qmlcachegen can now compile some parts of QML to C++ files containing "QML compilation units", which include the compiled parts of the QML and the rest as bytecode embedded into the C++ files. qmlsc does the same thing as qmlcachegen but can compile QML to C++ in more cases. qmlsc is not open source and it doesn't seem it will be, but I'm not entirely sure.

qmltc works differently than both qmlcachegen and qmlsc. It generates C++ classes from the QML files which are more efficient at runtime than the "QML compilation units" generated by qmlcachegen & qmlsc. However, qmltc only works with a limited subset of QML, so using it must be optional. In Qt 6.3 - 6.4, C++ headers generated by qmltc need to be #included to instatiate these classes. I was afraid we'd need to automatically generate Rust bindings for these, but fortunately Qt 6.5 will add a new QQmlApplicationEngine::loadFromModule function which will be able to load qmltc compiled QML types via their QML module URI and type name as QStrings, so we won't need to generate Rust bindings to the generated C++ classes.

So, qmlcachegen is helpful in any case when qmltc isn't used. However, qmlcachegen in Qt 6 has some new command line options in Qt 5 which are used by the qt_add_qml_module CMake function, so figuring out how to use qmlcachegen with Qt5 would require examining how qmake works with it. In the end, it might require substantially different code between Qt 5 and Qt 6. Considering that drawback, and that qmlcachegen only speeds up load time but not run time in Qt 5, I suggest only supporting qmlcachegen for Qt 6 (qmltc was added in Qt 6.3).

Be-ing commented 1 year ago

For examining how the qt_add_qml_module CMake function works, I pushed a branch which has commented out code to use it. It needs the headers generated by the Cargo build script, so you need to run a build first with the CMake code commented out, then uncomment the CMake code and comment linking "$<LINK_LIBRARY:WHOLE_ARCHIVE,${CRATE}-static>" to avoid duplicate symbol errors when linking.

Be-ing commented 1 year ago

qmlcachegen is helpful in any case when qmltc isn't used.

I asked about this on a recent Qt blog post and this isn't quite right. qmlcachegen is always helpful. qmltc can be used together with qmlcachegen; they work on different aspects of speeding up QML.

Be-ing commented 1 year ago

Qt 6.5 will add a new QQmlApplicationEngine::loadFromModule function which will be able to load qmltc compiled QML types via their QML module URI and type name as QStrings, so we won't need to generate Rust bindings to the generated C++ classes.

This is detailed in a new blog post now that Qt 6.5 has been released: https://www.qt.io/blog/whats-new-for-qml-modules-in-6.5