aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-type-compiler.qdoc
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-type-compiler.qdoc')
-rw-r--r--src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-type-compiler.qdoc283
1 files changed, 283 insertions, 0 deletions
diff --git a/src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-type-compiler.qdoc b/src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-type-compiler.qdoc
new file mode 100644
index 0000000000..38f8fe039b
--- /dev/null
+++ b/src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-type-compiler.qdoc
@@ -0,0 +1,283 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtqml-qml-type-compiler.html
+\title QML type compiler
+\brief A tool to compile QML types to C++ ahead of time.
+\keyword qmltc
+\ingroup qtqml-tooling
+
+The QML type compiler, \c qmltc, is a tool shipped with Qt to translate QML
+types into C++ types that are \e{ahead-of-time} compiled as part of the user
+code. Using qmltc can lead to better run-time performance due to more
+optimization opportunities available to the compiler compared to a
+QQmlComponent-based object creation. The qmltc is part of the \l{Qt Quick Compiler}
+toolchain.
+
+By design, qmltc outputs user-facing code. That code is supposed to be utilized
+by the C++ application directly, otherwise you won't see any benefit. This
+generated code essentially replaces QQmlComponent and its APIs to create objects
+from QML documents. You can find more information under \l{Using qmltc in a QML
+application} and \l{Generated Output Basics}.
+
+In order to enable qmltc:
+
+\list
+ \li Create a \l{qt_add_qml_module}{proper QML module} for your application.
+
+ \li Invoke qmltc, for example, through the \l{qmltc-cmake}{CMake API}.
+
+ \li \c{#include} the generated header file(s) in the application source
+ code.
+
+ \li Instantiate an object of the generated type.
+\endlist
+
+In this workflow qmltc usually runs during the build process. Thus, when qmltc
+rejects a QML document (whether due to errors or warnings, or because of
+constructs qmltc doesn't yet support), the build process will fail. This is
+similar to how you receive qmllint errors when you enable the automatic
+generation of linting targets during \l{qt_add_qml_module}{QML module creation}
+and then attempt to "build" them to run the qmllint.
+
+\warning qmltc is currently in a Tech Preview stage and might not compile an
+arbitrary QML program (see \l{Known Limitations} for more details). When qmltc
+fails, nothing is generated as your application cannot sensibly use the qmltc
+output. If your program contains errors (or unsolvable warnings), they should be
+fixed to enable the compilation. The general rule is to adhere to the best
+practices and follow \l{qmllint Reference}{qmllint} advice.
+
+\note \c qmltc does not guarantee that the generated C++ stays API-, source- or
+binary-compatible between past or future versions, even patch versions.
+Furthermore, qmltc-compiled apps using Qt's QML modules will require linking
+against private Qt API. This is because Qt's QML modules do not usually provide
+a public C++ API since their primary usage is through QML.
+
+
+\section2 Using qmltc in a QML application
+
+From the build system perspective, adding qmltc compilation is not much
+different from adding qml cache generation. Naively, the build process could be
+described as:
+
+\image qmltc-compilation-scheme.png
+
+While the real compilation process is much trickier, this diagram captures the
+core components that qmltc uses: the QML files themselves and qmldir with
+qmltypes information. Simpler applications typically have rather primitive
+qmldir yet, in general, qmldir could be complex, providing essential, nicely
+packed type information that qmltc relies on to perform correct QML-to-C++
+translation.
+
+Nevertheless, adding an extra build step is not enough in qmltc case. The
+application code must also be modified to use qmltc-generated classes instead of
+QQmlComponent or its higher-level alternatives.
+
+\section3 Compiling QML code with qmltc
+
+Qt, starting from Qt 6, uses CMake to build its various components. User
+projects can - and are encouraged to - also use CMake to build their components
+using Qt. Adding out-of-the-box qmltc compilation support to your project would
+require a CMake-driven build flow as well since this flow is centered around
+proper QML modules and their infrastructure.
+
+The easy way to add qmltc compilation is by using the dedicated
+\l{qmltc-cmake}{CMake API} as part of a QML module creation for the application.
+Consider a simple application directory structure:
+
+\badcode
+.
+├── CMakeLists.txt
+├── myspecialtype.h // C++ type exposed to QML
+├── myspecialtype.cpp
+├── myApp.qml // main QML page
+├── MyButton.qml // custom UI button
+├── MySlider.qml // custom UI slider
+└── main.cpp // main C++ application file
+\endcode
+
+Then the CMake code would usually look similar to the following:
+
+\snippet qmltc/CMakeLists.txt qmltc-app-name
+\codeline
+\snippet qmltc/CMakeLists.txt qmltc-qml-files
+\codeline
+\snippet qmltc/CMakeLists.txt qmltc-add-qml-module
+\codeline
+\snippet qmltc/CMakeLists.txt qmltc-compile-to-cpp
+
+\section3 Using the Generated C++
+
+Unlike in the case of QQmlComponent instantiation, the output of qmltc, being
+C++ code, is used directly by the application. Generally, constructing a new
+object in C++ is equivalent to creating a new object through
+QQmlComponent::create(). Once created, the object could be manipulated from C++
+or, for example, combined with QQuickWindow to be drawn on screen.
+
+If a compiled type exposes some required properties, `qmltc` will
+require an initial value for those properties in the constructor for
+the generated object.
+
+Additionally, the constructor for a qmltc object can be provided with
+with a callback to set up initial values for the component's
+properties.
+
+Given a \c{myApp.qml} file, the application code (in both cases) would
+typically look like this:
+
+\if defined(onlinedocs)
+ \tab {generated-c++}{tab-qqmlcomponent}{Using QQmlComponent}{checked}
+ \tab {generated-c++}{tab-qmltc}{Using qmltc-generated class}{}
+ \tabcontent {tab-qqmlcomponent}
+\else
+ \section4 Using QQmlComponent
+\endif
+\snippet qmltc/tst_qmltc_examples.cpp qqmlcomponent-include
+\codeline
+\snippet qmltc/tst_qmltc_examples.cpp qqmlcomponent-app-code-0
+\codeline
+\snippet qmltc/tst_qmltc_examples.cpp qqmlcomponent-app-code-1
+\codeline
+\snippet qmltc/tst_qmltc_examples.cpp qqmlcomponent-app-code-2
+\codeline
+\snippet qmltc/tst_qmltc_examples.cpp qmltc-app-exec
+\if defined(onlinedocs)
+ \endtabcontent
+ \tabcontent {tab-qmltc}
+\else
+ \section4 Using qmltc-generated class
+\endif
+\snippet qmltc/tst_qmltc_examples.cpp qmltc-include
+\codeline
+\snippet qmltc/tst_qmltc_examples.cpp qmltc-app-code
+\codeline
+\snippet qmltc/tst_qmltc_examples.cpp qmltc-app-exec
+\if defined(onlinedocs)
+ \endtabcontent
+\endif
+
+\section2 QML engine
+
+The generated code uses QQmlEngine to interact with dynamic parts of a QML
+document - mainly the JavaScript code. For this to work, no special arrangements
+are needed. Any QQmlEngine instance passed to the constructor of a
+qmltc-generated class object should work correctly as does
+\c{QQmlComponent(engine)}. This also means that you can use
+\l{QQmlEngine}{QQmlEngine methods} that affect QML behavior. However, there are
+caveats. Unlike QQmlComponent-based object creation, qmltc itself \e{does not}
+rely on QQmlEngine when compiling the code to C++. For instance,
+\c{QQmlEngine::addImportPath("/foo/bar/")} - normally resulting in an additional
+import path to scan for - would be completely ignored by the ahead-of-time qmltc
+procedure.
+
+\note To add import paths to the qmltc compilation, consider using a relevant
+argument of the \l{qmltc-cmake}{CMake command} instead.
+
+Generally, you can think of it this way: QQmlEngine involves the application
+process to run, while qmltc does not as it operates \e{before} your application
+is even compiled. Since qmltc makes no attempt to introspect your application's
+C++ source code, there is no way for it to know about certain kinds of QML
+manipulations you, as a user, do. Instead of using QQmlEngine and related
+run-time routines to expose types to QML, adding import paths, etc. you are,
+practically, required to create \l{qt_add_qml_module}{well-behaving QML modules}
+and use \l{Defining QML Types from C++}{declarative QML type registration}.
+
+\warning Despite qmltc working closely with QQmlEngine and creating C++ code,
+the generated classes cannot be further exposed to QML and used through
+QQmlComponent.
+
+\section2 Generated Output Basics
+
+\c qmltc aims to be compatible with the existing QML execution model. This
+implies that the generated code is roughly equivalent to the internal
+QQmlComponent setup logic and thus you should be able to understand your QML
+type's behavior, semantics and API the same way you do currently - by visually
+inspecting the corresponding QML document.
+
+However, the generated code is still somewhat confusing, especially given that
+your application should use the qmltc output on the C++ side directly. There are
+two parts of the generated code: CMake build files structure and the generated
+C++ format. The former is covered in the \l{qmltc-cmake}{CMake API of qmltc} and
+the latter is covered here.
+
+Consider a simple HelloWorld type, that has a \c hello property, a function to
+print that property, and a signal emitted when the object of that type is
+created:
+
+\snippet qmltc/special/HelloWorld.qml qmltc-hello-world-qml
+
+When providing a C++ alternative of this QML type, the C++ class would need a
+\l{Overview - QML and C++ Integration}{QML-specific meta-object system macro},
+Q_PROPERTY decoration for the \c hello property, \c{Q_INVOKABLE} C++ printing
+function and a regular Qt signal definition. Similarly, qmltc would translate
+the given HelloWorld type into roughly the following:
+
+\snippet qmltc/special/HelloWorld.qml.cpp qmltc-hello-world-generated
+
+Even though specific details of the generated type could differ, the universal
+aspects remain. For instance:
+
+\list
+ \li QML types within a document are translated into C++ types, according to
+ the compiler-visible information.
+ \li Properties are translated into C++ properties with Q_PROPERTY
+ declarations.
+ \li JavaScript functions become \c{Q_INVOKABLE} C++ functions.
+ \li QML signals are transformed into C++ Qt signals.
+ \li QML enumerations are converted into C++ enumerations with \c{Q_ENUM}
+ declarations.
+\endlist
+
+An additional detail is the way \c qmltc generates class names. A class name for
+a given QML type is automatically deduced from the QML document defining that
+type: the QML file name without extensions (up to and excluding the first \c{.},
+also known as the base name) becomes a class name. The file name case is
+preserved. Thus, \c{HelloWorld.qml} would result in a \c{class HelloWorld} and
+\c{helloWoRlD.qml} in a \c{class helloWoRlD}. Following the QML convention, if a
+QML document file name starts with a lower-case letter, the generated C++ class
+is assumed to be anonymous and marked with \l{QML_ANONYMOUS}.
+
+For now, although the generated code is ready to be used from the C++
+application side, you should generally limit calls to the generated APIs.
+Instead, prefer implementing the application logic in QML/JavaScript and
+hand-written C++ types exposed to QML, using the qmltc-created classes for
+simple object instantiation. While generated C++ gives you direct (and usually
+faster) access to QML-defined elements of the type, understanding such code
+could be a challenge.
+
+\section2 Known Limitations
+
+Despite covering many common QML features, qmltc is still in the early stage of
+development with some things yet to be supported.
+
+Imported QML modules that consist of QML-defined types (such as
+\c{QtQuick.Controls}) might not get compiled correctly, even if those QML-defined
+types were compiled by qmltc..
+At present, you can reliably use \c{QtQml} and \c{QtQuick} modules as well as any
+other QML module that \b{only} contains C++ classes exposed to QML.
+
+On top of this, there are some more fundamental peculiarities to consider:
+
+\list
+ \li Qt's QML modules usually rely on C++ libraries to do the heavy lifting.
+ Often enough, these libraries do not provide public C++ API (since their
+ primary usage is through QML). For the users of qmltc, this means that their
+ apps need to link against private Qt libraries.
+
+ \li Due to the nature of qmltc code generation, QML plugins are unusable for
+ compilation purposes. Instead, QML modules - that use a plugin - have to
+ ensure that the plugin data is accessible at compile time. Such QML modules
+ would then have \e optional plugins. In most cases, the compile-time
+ information can be provided through a header file (with C++ declarations)
+ and linkable library (with C++ definitions). The user code is responsible
+ (usually through CMake) for including a path to the header file and linking
+ against the QML module library.
+\endlist
+
+\note
+Given the tech preview status of the compiler, you might also encounter bugs in
+qmltc, in the generated code, or some other related part. We encourage you to
+\l{https://bugreports.qt.io/}{submit a bug report} in this case.
+
+*/