1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
5\page qtqml-qml-type-compiler.html
6\title QML type compiler
7\brief A tool to compile QML types to C++ ahead of time.
11The QML type compiler, \c qmltc, is a tool shipped with Qt to translate QML
12types into C++ types that are \e{ahead-of-time} compiled as part of the user
13code. Using qmltc can lead to better run-time performance due to more
14optimization opportunities available to the compiler compared to a
15QQmlComponent-based object creation. The qmltc is part of the \l{Qt Quick Compiler}
18By design, qmltc outputs user-facing code. That code is supposed to be utilized
19by the C++ application directly, otherwise you won't see any benefit. This
20generated code essentially replaces QQmlComponent and its APIs to create objects
21from QML documents. You can find more information under \l{Using qmltc in a QML
22application} and \l{Generated Output Basics}.
24In order to enable qmltc:
27 \li Create a \l{qt_add_qml_module}{proper QML module} for your application.
29 \li Invoke qmltc, for example, through the \l{qmltc-cmake}{CMake API}.
31 \li \c{#include} the generated header file(s) in the application source
34 \li Instantiate an object of the generated type.
37In this workflow qmltc usually runs during the build process. Thus, when qmltc
38rejects a QML document (whether due to errors or warnings, or because of
39constructs qmltc doesn't yet support), the build process will fail. This is
40similar to how you receive qmllint errors when you enable the automatic
41generation of linting targets during \l{qt_add_qml_module}{QML module creation}
42and then attempt to "build" them to run the qmllint.
44\warning qmltc is currently in a Tech Preview stage and might not compile an
45arbitrary QML program (see \l{Known Limitations} for more details). When qmltc
46fails, nothing is generated as your application cannot sensibly use the qmltc
47output. If your program contains errors (or unsolvable warnings), they should be
48fixed to enable the compilation. The general rule is to adhere to the best
49practices and follow \l{qmllint Reference}{qmllint} advice.
51\note \c qmltc does not guarantee that the generated C++ stays API-, source- or
52binary-compatible between past or future versions, even patch versions.
53Furthermore, qmltc-compiled apps using Qt's QML modules will require linking
54against private Qt API. This is because Qt's QML modules do not usually provide
55a public C++ API since their primary usage is through QML.
58\section2 Using qmltc in a QML application
60From the build system perspective, adding qmltc compilation is not much
61different from adding qml cache generation. Naively, the build process could be
64\image qmltc-compilation-scheme.png
66While the real compilation process is much trickier, this diagram captures the
67core components that qmltc uses: the QML files themselves and qmldir with
68qmltypes information. Simpler applications typically have rather primitive
69qmldir yet, in general, qmldir could be complex, providing essential, nicely
70packed type information that qmltc relies on to perform correct QML-to-C++
73Nevertheless, adding an extra build step is not enough in qmltc case. The
74application code must also be modified to use qmltc-generated classes instead of
75QQmlComponent or its higher-level alternatives.
77\section3 Compiling QML code with qmltc
79Qt, starting from Qt 6, uses CMake to build its various components. User
80projects can - and are encouraged to - also use CMake to build their components
81using Qt. Adding out-of-the-box qmltc compilation support to your project would
82require a CMake-driven build flow as well since this flow is centered around
83proper QML modules and their infrastructure.
85The easy way to add qmltc compilation is by using the dedicated
86\l{qmltc-cmake}{CMake API} as part of a QML module creation for the application.
87Consider a simple application directory structure:
92├── myspecialtype.h // C++ type exposed to QML
94├── myApp.qml // main QML page
95├── MyButton.qml // custom UI button
96├── MySlider.qml // custom UI slider
97└── main.cpp // main C++ application file
100Then the CMake code would usually look similar to the following:
102\snippet qmltc/CMakeLists.txt qmltc-app-name
104\snippet qmltc/CMakeLists.txt qmltc-qml-files
106\snippet qmltc/CMakeLists.txt qmltc-add-qml-module
108\snippet qmltc/CMakeLists.txt qmltc-compile-to-cpp
110\section3 Using the Generated C++
112Unlike in the case of QQmlComponent instantiation, the output of qmltc, being
113C++ code, is used directly by the application. Generally, constructing a new
114object in C++ is equivalent to creating a new object through
115QQmlComponent::create(). Once created, the object could be manipulated from C++
116or, for example, combined with QQuickWindow to be drawn on screen.
118If a compiled type exposes some required properties, `qmltc` will
119require an initial value for those properties in the constructor for
122Additionally, the constructor for a qmltc object can be provided with
123with a callback to set up initial values for the component's
126Given a \c{myApp.qml} file, the application code (in both cases) would
127typically look like this:
129\if defined(onlinedocs)
130 \tab {generated-c++}{tab-qqmlcomponent}{Using QQmlComponent}{checked}
131 \tab {generated-c++}{tab-qmltc}{Using qmltc-generated class}{}
132 \tabcontent {tab-qqmlcomponent}
134 \section4 Using QQmlComponent
136\snippet qmltc/tst_qmltc_examples.cpp qqmlcomponent-include
138\snippet qmltc/tst_qmltc_examples.cpp qqmlcomponent-app-code-0
140\snippet qmltc/tst_qmltc_examples.cpp qqmlcomponent-app-code-1
142\snippet qmltc/tst_qmltc_examples.cpp qqmlcomponent-app-code-2
144\snippet qmltc/tst_qmltc_examples.cpp qmltc-app-exec
145\if defined(onlinedocs)
147 \tabcontent {tab-qmltc}
149 \section4 Using qmltc-generated class
151\snippet qmltc/tst_qmltc_examples.cpp qmltc-include
153\snippet qmltc/tst_qmltc_examples.cpp qmltc-app-code
155\snippet qmltc/tst_qmltc_examples.cpp qmltc-app-exec
156\if defined(onlinedocs)
162The generated code uses QQmlEngine to interact with dynamic parts of a QML
163document - mainly the JavaScript code. For this to work, no special arrangements
164are needed. Any QQmlEngine instance passed to the constructor of a
165qmltc-generated class object should work correctly as does
166\c{QQmlComponent(engine)}. This also means that you can use
167\l{QQmlEngine}{QQmlEngine methods} that affect QML behavior. However, there are
168caveats. Unlike QQmlComponent-based object creation, qmltc itself \e{does not}
169rely on QQmlEngine when compiling the code to C++. For instance,
170\c{QQmlEngine::addImportPath("/foo/bar/")} - normally resulting in an additional
171import path to scan for - would be completely ignored by the ahead-of-time qmltc
174\note To add import paths to the qmltc compilation, consider using a relevant
175argument of the \l{qmltc-cmake}{CMake command} instead.
177Generally, you can think of it this way: QQmlEngine involves the application
178process to run, while qmltc does not as it operates \e{before} your application
179is even compiled. Since qmltc makes no attempt to introspect your application's
180C++ source code, there is no way for it to know about certain kinds of QML
181manipulations you, as a user, do. Instead of using QQmlEngine and related
182run-time routines to expose types to QML, adding import paths, etc. you are,
183practically, required to create \l{qt_add_qml_module}{well-behaving QML modules}
184and use \l{Defining QML Types from C++}{declarative QML type registration}.
186\warning Despite qmltc working closely with QQmlEngine and creating C++ code,
187the generated classes cannot be further exposed to QML and used through
190\section2 Generated Output Basics
192\c qmltc aims to be compatible with the existing QML execution model. This
193implies that the generated code is roughly equivalent to the internal
194QQmlComponent setup logic and thus you should be able to understand your QML
195type's behavior, semantics and API the same way you do currently - by visually
196inspecting the corresponding QML document.
198However, the generated code is still somewhat confusing, especially given that
199your application should use the qmltc output on the C++ side directly. There are
200two parts of the generated code: CMake build files structure and the generated
201C++ format. The former is covered in the \l{qmltc-cmake}{CMake API of qmltc} and
202the latter is covered here.
204Consider a simple HelloWorld type, that has a \c hello property, a function to
205print that property, and a signal emitted when the object of that type is
208\snippet qmltc/special/HelloWorld.qml qmltc-hello-world-qml
210When providing a C++ alternative of this QML type, the C++ class would need a
211\l{Overview - QML and C++ Integration}{QML-specific meta-object system macro},
212Q_PROPERTY decoration for the \c hello property, \c{Q_INVOKABLE} C++ printing
213function and a regular Qt signal definition. Similarly, qmltc would translate
214the given HelloWorld type into roughly the following:
216\snippet qmltc/special/HelloWorld.qml.cpp qmltc-hello-world-generated
218Even though specific details of the generated type could differ, the universal
219aspects remain. For instance:
222 \li QML types within a document are translated into C++ types, according to
223 the compiler-visible information.
224 \li Properties are translated into C++ properties with Q_PROPERTY
226 \li JavaScript functions become \c{Q_INVOKABLE} C++ functions.
227 \li QML signals are transformed into C++ Qt signals.
228 \li QML enumerations are converted into C++ enumerations with \c{Q_ENUM}
232An additional detail is the way \c qmltc generates class names. A class name for
233a given QML type is automatically deduced from the QML document defining that
234type: the QML file name without extensions (up to and excluding the first \c{.},
235also known as the base name) becomes a class name. The file name case is
236preserved. Thus, \c{HelloWorld.qml} would result in a \c{class HelloWorld} and
237\c{helloWoRlD.qml} in a \c{class helloWoRlD}. Following the QML convention, if a
238QML document file name starts with a lower-case letter, the generated C++ class
239is assumed to be anonymous and marked with \l{QML_ANONYMOUS}.
241For now, although the generated code is ready to be used from the C++
242application side, you should generally limit calls to the generated APIs.
243Instead, prefer implementing the application logic in QML/JavaScript and
244hand-written C++ types exposed to QML, using the qmltc-created classes for
245simple object instantiation. While generated C++ gives you direct (and usually
246faster) access to QML-defined elements of the type, understanding such code
249\section2 Known Limitations
251Despite covering many common QML features, qmltc is still in the early stage of
252development with some things yet to be supported.
254Imported QML modules that consist of QML-defined types (such as
255\c{QtQuick.Controls}) might not get compiled correctly, even if those QML-defined
256types were compiled by qmltc..
257At present, you can reliably use \c{QtQml} and \c{QtQuick} modules as well as any
258other QML module that \b{only} contains C++ classes exposed to QML.
260On top of this, there are some more fundamental peculiarities to consider:
263 \li Qt's QML modules usually rely on C++ libraries to do the heavy lifting.
264 Often enough, these libraries do not provide public C++ API (since their
265 primary usage is through QML). For the users of qmltc, this means that their
266 apps need to link against private Qt libraries.
268 \li Due to the nature of qmltc code generation, QML plugins are unusable for
269 compilation purposes. Instead, QML modules - that use a plugin - have to
270 ensure that the plugin data is accessible at compile time. Such QML modules
271 would then have \e optional plugins. In most cases, the compile-time
272 information can be provided through a header file (with C++ declarations)
273 and linkable library (with C++ definitions). The user code is responsible
274 (usually through CMake) for including a path to the header file and linking
275 against the QML module library.
279Given the tech preview status of the compiler, you might also encounter bugs in
280qmltc, in the generated code, or some other related part. We encourage you to
281\l{https://bugreports.qt.io/}{submit a bug report} in this case.