Compilateur de types QML
Le compilateur de types QML, qmltc, est un outil fourni avec Qt permettant de traduire les types QML en types C++ qui sont compilés à l'avance dans le cadre du code utilisateur. L'utilisation de qmltc peut améliorer les performances d'exécution grâce aux possibilités d'optimisation supplémentaires offertes au compilateur par rapport à la création d'objets via ` QQmlComponent`. qmltc fait partie de la Qt Quick Compiler chaîne d’outils.
De par sa conception, qmltc génère du code destiné à l’utilisateur. Ce code est censé être utilisé directement par l’application C++, sans quoi vous n’en tirerez aucun avantage. Ce code généré remplace essentiellement QQmlComponent et ses API pour créer des objets à partir de documents QML. Vous trouverez plus d’informations dans les sections Utilisation de qmltc dans une application QML et Principes de base de la sortie générée.
Pour activer qmltc :
- Créez un module QML adapté à votre application.
- Appelez qmltc, par exemple via l’API CMake.
#includeIntégrez le ou les fichiers d'en-tête générés dans le code source de l'application.- Instanciez un objet du type généré.
Dans ce flux de travail, qmltc s'exécute généralement pendant le processus de compilation. Ainsi, lorsque qmltc rejette un document QML (que ce soit en raison d’erreurs ou d’avertissements, ou à cause de constructions que qmltc ne prend pas encore en charge), le processus de compilation échoue. Ce comportement est similaire à celui observé lorsque vous recevez des erreurs qmllint après avoir activé la génération automatique de cibles de linting lors de la création de modules QML, puis que vous tentez de les « compiler » pour exécuter qmllint.
Avertissement : qmltc est actuellement en phase de « Tech Preview » et peut ne pas parvenir à compiler un programme QML quelconque (voir la section « Limitations connues » pour plus de détails). Lorsque qmltc échoue, rien n’est généré, car votre application ne peut pas utiliser de manière pertinente la sortie de qmltc. Si votre programme contient des erreurs (ou des avertissements insolubles), celles-ci doivent être corrigées pour permettre la compilation. La règle générale consiste à respecter les bonnes pratiques et à suivre les conseils de qmllint.
Remarque : qmltc ne garantit pas que le code C++ généré reste compatible au niveau de l’API, du code source ou du binaire entre les versions passées et futures, y compris les versions de correctif. De plus, les applications compilées avec qmltc qui utilisent les modules QML de Qt devront être liées à l’API privée de Qt. En effet, les modules QML de Qt ne fournissent généralement pas d’API C++ publique, car ils sont principalement utilisés via QML.
Utilisation de qmltc dans une application QML
Du point de vue du système de build, l’ajout de la compilation qmltc ne diffère pas beaucoup de l’ajout de la génération du cache QML. De manière simplifiée, le processus de build pourrait être décrit comme suit :

Bien que le processus de compilation réel soit bien plus complexe, ce schéma illustre les composants essentiels utilisés par qmltc : les fichiers QML eux-mêmes et qmldir avec les informations qmltypes. Les applications plus simples disposent généralement d’un qmldir encore assez rudimentaire ; cependant, en règle générale, qmldir peut s’avérer complexe, fournissant des informations de type essentielles et bien structurées sur lesquelles qmltc s’appuie pour effectuer une traduction correcte du QML vers le C++.
Néanmoins, dans le cas de qmltc, l’ajout d’une étape de compilation supplémentaire ne suffit pas. Le code de l’application doit également être modifié pour utiliser les classes générées par qmltc à la place de ` QQmlComponent ` ou de ses alternatives de plus haut niveau.
Compilation du code QML avec qmltc
À partir de la version 6, Qt utilise CMake pour construire ses différents composants. Les projets des utilisateurs peuvent — et sont encouragés à — utiliser également CMake pour construire leurs composants à l’aide de Qt. L’ajout d’un support de compilation qmltc prêt à l’emploi à votre projet nécessiterait également un flux de construction piloté par CMake, car ce flux s’articule autour de modules Qml appropriés et de leur infrastructure.
Le moyen le plus simple d’ajouter la compilation qmltc consiste à utiliser l’API CMake dédiée dans le cadre de la création d’un module QML pour l’application. Prenons l’exemple d’une structure de répertoires d’application simple :
.
├── 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 fileLe code CMake ressemblerait alors généralement à ce qui suit :
# Use "my_qmltc_example" as an application name:
set(application_name my_qmltc_example)
# Create a CMake target, add C++ source files, link libraries, etc...
# Specify a list of QML files to be compiled:
set(application_qml_files
myApp.qml
MyButton.qml
MySlider.qml
)
# Make the application into a proper QML module:
qt6_add_qml_module(${application_name}
URI QmltcExample
QML_FILES ${application_qml_files}
# Compile qml files (listed in QML_FILES) to C++ using qmltc and add these
# files to the application binary:
ENABLE_TYPE_COMPILER
NO_GENERATE_EXTRA_QMLDIRS
)
# (qmltc-specific) Link *private* libraries that correspond to QML modules:
find_package(Qt6 COMPONENTS QmlPrivate QuickPrivate)
target_link_libraries(${application_name} PRIVATE Qt::QmlPrivate Qt::QuickPrivate)Utilisation du code C++ généré
Contrairement à l’instanciation d’un ` QQmlComponent `, la sortie de `qmltc`, qui est du code C++, est utilisée directement par l’application. En général, la construction d’un nouvel objet en C++ équivaut à la création d’un nouvel objet via ` QQmlComponent::create()`. Une fois créé, l’objet peut être manipulé depuis le C++ ou, par exemple, combiné avec ` QQuickWindow ` pour être affiché à l’écran.
Si un type compilé expose certaines propriétés obligatoires, `qmltc` exigera une valeur initiale pour ces propriétés dans le constructeur de l’objet généré.
De plus, le constructeur d’un objet `qmltc` peut être fourni avec une fonction de rappel permettant de définir les valeurs initiales des propriétés du composant.
À partir d’un fichier ` myApp.qml `, le code de l’application (dans les deux cas) ressemblerait généralement à ceci :
#include <QtQml/qqmlcomponent.h>
QGuiApplication app(argc, argv);
app.setApplicationDisplayName(QStringLiteral("This example is powered by QQmlComponent :("));
QQmlEngine e;
// If the root element is Window, you don't need to create a Window.
// The snippet is for the cases where the root element is not a Window.
QQuickWindow window;
QQmlComponent component(&e);
component.loadUrl(
QUrl(QStringLiteral("qrc:/qt/qml/QmltcExample/myApp.qml")));
QScopedPointer<QObject> documentRoot(component.create());
QQuickItem *documentRootItem = qobject_cast<QQuickItem *>(documentRoot.get());
documentRootItem->setParentItem(window.contentItem());
window.setHeight(documentRootItem->height());
window.setWidth(documentRootItem->width());
// ...
window.show();
app.exec();#include "myapp.h" // include generated C++ header
QGuiApplication app(argc, argv);
app.setApplicationDisplayName(QStringLiteral("This example is powered by qmltc!"));
QQmlEngine e;
// If the root element is Window, you don't need to create a Window.
// The snippet is for the cases where the root element is not a Window.
QQuickWindow window;
QScopedPointer<QmltcExample::myApp> documentRoot(
new QmltcExample::myApp(&e, nullptr, [](auto& component){
component.setWidth(800);
}));
documentRoot->setParentItem(window.contentItem());
window.setHeight(documentRoot->height());
window.setWidth(documentRoot->width());
// ...
window.show();
app.exec();Moteur QML
Le code généré utilise QQmlEngine pour interagir avec les parties dynamiques d’un document QML, principalement le code JavaScript. Pour que cela fonctionne, aucune configuration particulière n’est nécessaire. Toute instance d’ QQmlEngine transmise au constructeur d’un objet de classe généré par qmltc devrait fonctionner correctement, tout comme QQmlComponent(engine). Cela signifie également que vous pouvez utiliser QQmlEngine methods qui affectent le comportement du QML. Il existe toutefois certaines mises en garde. Contrairement à la création d’objets basée sur QQmlComponent, qmltc ne s’appuie pas lui-même sur QQmlEngine lors de la compilation du code en C++. Par exemple, QQmlEngine::addImportPath("/foo/bar/") — qui entraîne normalement un chemin d’importation supplémentaire à analyser — serait complètement ignoré par la procédure de compilation anticipée de qmltc.
Remarque : pour ajouter des chemins d’importation à la compilation qmltc, pensez plutôt à utiliser un argument approprié de la commande CMake.
De manière générale, vous pouvez voir les choses ainsi : « QQmlEngine » implique l’exécution du processus de l’application, tandis que « qmltc » ne l’implique pas, car il s’exécute avant même que votre application ne soit compilée. Comme qmltc ne tente pas d’analyser le code source C++ de votre application, il n’a aucun moyen de connaître certains types de manipulations QML que vous effectuez en tant qu’utilisateur. Au lieu d’utiliser ` QQmlEngine ` et les routines d’exécution associées pour exposer des types à QML, d’ajouter des chemins d’importation, etc., vous êtes, dans la pratique, obligé de créer des modules QML qui se comportent correctement et d’utiliser l’enregistrement déclaratif des types QML.
Avertissement : bien que qmltc fonctionne en étroite collaboration avec QQmlEngine et génère du code C++, les classes générées ne peuvent pas être exposées davantage à QML ni utilisées via QQmlComponent.
Principes de base de la sortie générée
qmltc vise à être compatible avec le modèle d’exécution QML existant. Cela implique que le code généré est globalement équivalent à la logique de configuration interne d’ QQmlComponent; vous devriez donc pouvoir comprendre le comportement, la sémantique et l’API de votre type QML de la même manière qu’actuellement, c’est-à-dire en inspectant visuellement le document QML correspondant.
Cependant, le code généré reste quelque peu déroutant, d’autant plus que votre application devrait utiliser directement la sortie de qmltc côté C++. Le code généré comporte deux parties : la structure des fichiers de construction CMake et le format C++ généré. La première est traitée dans l’API CMake de qmltc et la seconde est abordée ici.
Prenons l’exemple d’un type HelloWorld simple, qui possède une propriété hello, une fonction permettant d’afficher cette propriété et un signal émis lors de la création d’un objet de ce type :
// HelloWorld.qml
import QtQml
QtObject {
id: me
property string hello: "Hello, qmltc!"
function printHello(prefix: string, suffix: string) {
console.log(prefix + me.hello + suffix);
}
signal created()
Component.onCompleted: me.created();
}Pour fournir une alternative en C++ à ce type QML, la classe C++ aurait besoin d’une macro du système de méta-objets spécifique à QML, d’une décoration ` Q_PROPERTY ` pour la propriété ` hello `, d’une fonction d’affichage en C++ de type ` Q_INVOKABLE ` et d’une définition de signal Qt classique. De même, qmltc traduirait le type `HelloWorld` donné en quelque chose qui ressemblerait à ceci :
class HelloWorld : public QObject
{
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QString hello READ hello WRITE setHello BINDABLE bindableHello)
public:
HelloWorld(QQmlEngine* engine, QObject* parent = nullptr, [[maybe_unused]] qxp::function_ref<void(PropertyInitializer&)> initializer = [](PropertyInitializer&){});
Q_SIGNALS:
void created();
public:
QString hello();
void setHello(const QString& hello_);
QBindable<QString> bindableHello();
Q_INVOKABLE void printHello(passByConstRefOrValue<QString> prefix, passByConstRefOrValue<QString> suffix);
// ...
};Même si les détails spécifiques du type généré peuvent varier, les aspects universels demeurent. Par exemple :
- Les types QML d’un document sont traduits en types C++, selon les informations visibles par le compilateur.
- Les propriétés sont traduites en propriétés C++ avec des déclarations de type « Q_PROPERTY ».
- Les fonctions JavaScript deviennent des fonctions C++ «
Q_INVOKABLEs ». - Les signaux QML sont transformés en signaux Qt en C++.
- Les énumérations QML sont converties en énumérations C++ avec des déclarations `
Q_ENUM`.
Un détail supplémentaire concerne la manière dont l’ qmltc génère les noms de classes. Le nom de classe d’un type QML donné est automatiquement déduit du document QML définissant ce type : le nom du fichier QML sans extension (jusqu’à la première « . » incluse, également appelé « nom de base ») devient le nom de la classe. La casse du nom de fichier est conservée. Ainsi, HelloWorld.qml donnerait lieu à une classe class HelloWorld et helloWoRlD.qml à une classe class helloWoRlD. Conformément à la convention QML, si le nom d’un fichier de document QML commence par une lettre minuscule, la classe C++ générée est considérée comme anonyme et marquée par QML_ANONYMOUS.
Pour l’instant, bien que le code généré soit prêt à être utilisé depuis l’application C++, vous devriez généralement limiter les appels aux API générées. Préférez plutôt implémenter la logique d’application en QML/JavaScript et en C++ écrit manuellement, exposée à QML, en utilisant les classes créées par qmltc pour l’instanciation simple d’objets. Bien que le code C++ généré vous offre un accès direct (et généralement plus rapide) aux éléments de type définis en QML, la compréhension de ce code peut s’avérer difficile.
Limitations connues
Bien qu’il couvre de nombreuses fonctionnalités courantes de QML, qmltc en est encore à un stade précoce de développement et certaines fonctionnalités ne sont pas encore prises en charge.
Les modules QML importés composés de types définis en QML (tels que QtQuick.Controls) risquent de ne pas être compilés correctement, même si ces types définis en QML ont été compilés par qmltc. À l’heure actuelle, vous pouvez utiliser en toute fiabilité les modules QtQml et QtQuick, ainsi que tout autre module QML ne contenant que des classes C++ exposées à QML.
À cela s’ajoutent certaines particularités plus fondamentales à prendre en compte :
- Les modules Qt Qml s’appuient généralement sur des bibliothèques C++ pour effectuer les tâches les plus lourdes. Bien souvent, ces bibliothèques ne fournissent pas d’API C++ publique (puisque leur utilisation principale se fait via QML). Pour les utilisateurs de qmltc, cela signifie que leurs applications doivent être liées à des bibliothèques Qt privées.
- En raison de la nature de la génération de code par qmltc, les plugins QML sont inutilisables à des fins de compilation. À la place, les modules QML — qui utilisent un plugin — doivent s’assurer que les données du plugin sont accessibles au moment de la compilation. Ces modules QML disposeraient alors de plugins optionnels. Dans la plupart des cas, les informations nécessaires à la compilation peuvent être fournies via un fichier d’en-tête (contenant les déclarations C++) et une bibliothèque à lier (contenant les définitions C++). Il incombe au code utilisateur (généralement via CMake) d’inclure le chemin d’accès au fichier d’en-tête et d’effectuer la liaison avec la bibliothèque du module QML.
Remarque : le compilateurétant encore en phase de préversion technique, vous pourriez rencontrer des bogues dans qmltc, dans le code généré ou dans d’autres éléments connexes. Nous vous encourageons à soumettre un rapport de bogue dans ce cas.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.