// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only

/*!
\page qtqml-qml-script-compiler.html
\title QML script compiler
\brief A tool to compile functions and expressions in QML.
\keyword qmlsc
\ingroup qtqml-tooling
\ingroup qtqml-tooling-internal

The QML script compiler compiles functions and expressions in QML and JavaScript
files to a byte code that can be interpreted or Just-in-time compiled by the
QML engine.

In addition, it compiles some functions and expressions in QML files into C++
code, within limitations set by the nature of JavaScript. It generates C++ code
for functions that can be exhaustively analyzed. The following flow chart
explains the compilation workflow.

\image qmlsc-compilation-scheme.png {Flow chart shows the compilation schemes}

QML script compiler is available in two versions. One is \e qmlcachegen, which
is a part of the \l{Qt Quick Compiler}. Another one is \e qmlsc, which is a part
of the commercial-only add-on \e{Qt Quick Compiler Extensions}.

\section1 qmlcachegen
\e qmlcachegen uses the meta-object system and generates lookups and stores them in a
central place, a compilation unit. The compilation unit contains a representation of
document structure, compact byte code representation for each function and expression,
and native code for functions and bindings that compiler fully understands.
The byte code in a compilation unit can be used by the QML engine to avoid re-compilation
and to speed up execution.

\section1 qmlsc
\e qmlsc, on the flip side, extends the base functionality of qmlcachegen by providing
two extra modes.

\list
\li \l {static mode}
\li \l {direct mode}
\endlist

\section2 static mode
In static mode, qmlsc assumes that no properties of any types exposed to C++ can be
shadowed by derived types. It eliminates the shadow checking mechanism and allows more
JavaScript code to be compiled to C++ and eventually generates faster code.

To enable static mode in qmlsc, you should pass \c{--static} via \c{QT_QMLCACHEGEN_ARGUMENTS} to \l{qt_add_qml_module}.
\badcode
    qt_add_qml_module(someTarget
    ...
    )

    set_target_properties(someTarget PROPERTIES
        QT_QMLCACHEGEN_ARGUMENTS "--static"
    )
\endcode

\warning qmlsc static-mode generates invalid code if any properties are shadowed in
the QML document.

\section2 direct mode
In direct mode, qmlsc assumes that all C++ types used in your QML code are available
and can be included as C++ headers to the generated code. Then the generated code
accesses or modifies properties by directly calling getters, setters and invokable
functions in those headers which makes the execution even faster. This means you have to
link to private Qt APIs in CMake.

\warning Private Qt APIs change often. You will need to recompile Qt for each new version.

\warning If a type is only defined in a plugin or has no header, you can’t use it in direct mode.

To enable direct mode, you should consider the followings:

\list
    \li you should pass \c{--direct-calls} via \c{QT_QMLCACHEGEN_ARGUMENTS} to \l{qt_add_qml_module}.

\badcode
    qt_add_qml_module(someTarget
    ...
    )

    set_target_properties(someTarget PROPERTIES
        QT_QMLCACHEGEN_ARGUMENTS "--direct-calls"
    )
\endcode

    \li Link all the relavant private Qt modules instead of their public counterparts.
\badcode
    find_package(Qt6 COMPONENTS QmlPrivate QuickPrivate)

    qt_add_qml_module(someTarget
    ...
    )

    target_link_libraries(someTarget PRIVATE
        Qt::QmlPrivate
        Qt::QuickPrivate
        ...
    )
\endcode

    \li Do not set the \c{PLUGIN_TARGET} to be the same as the backing library target.
\badcode
    # direct mode will not function in this setup.
    qt_add_qml_module(someTarget
    PLUGIN_TARGET someTarget
    ...
    )
\endcode
\endlist

\section1 Limitations when compiling JavaScript to C++

Many JavaScript constructs cannot be efficiently represented in C++. The QML
script compiler skips the C++ code generation for functions that contain such
constructs and only generates byte code to be interpreted or run through the
Just-in-time compiler. Most common QML expressions are rather simple: value
lookups on QObjects, arithmetics, simple if/else or loop constructs. Those can
easily be expressed in C++, and doing so makes your application run faster.

\section1 Obtaining statistics about the compilation of functions and bindings

The QML Script Compiler records statistics when compiling QML to C++. These can
give insight into the compilation of functions and bindings and whether it was
successful or which error has caused it to fail. In addition to
showing these results per binding or function, the statistics are also
summarized per file, per module, and at the project level. This can give a
quick overview of how well a project is being compiled.

To show statistics, invoke the \e{all_aotstats} cmake target.

The collection of compilation statistics is enabled by default. In order to
disable it, set the \l{QT_QML_GENERATE_AOTSTATS} CMake variable to OFF before
the first call to \l{qt_add_qml_module}.

\note These statistics are only available for modules registered through the
\l{qt_add_qml_module} cmake API

*/
