このページでは

QML 型コンパイラ

Qt QML Compiler(qmltc )は、Qtに同梱されているツールであり、QML型をC++型に変換し、ユーザーコードの一部として事前コンパイルを行います。QQmlComponent に基づくオブジェクト生成と比較して、qmltcを使用することでコンパイラが利用できる最適化の機会が増えるため、実行時のパフォーマンスが向上する可能性があります。 qmltcは、Qt Quick コンパイラツールチェーンの一部です。

設計上、qmltcはユーザー向けのコードを出力します。このコードはC++アプリケーションで直接利用されることを前提としており、そうしなければそのメリットを享受することはできません。この生成されたコードは、本質的にQQmlComponent およびそのAPIに取って代わり、QMLドキュメントからオブジェクトを作成します。詳細については、「QMLアプリケーションでのqmltcの使用」および「生成出力の基礎」を参照してください。

qmltc を有効にするには:

  • アプリケーションに適したQMLモジュールを作成します。
  • 例えば、CMake API などを通じて qmltc を呼び出します。
  • #include 生成されたヘッダーファイルをアプリケーションのソースコードに組み込みます。
  • 生成された型のオブジェクトをインスタンス化します。

このワークフローでは、qmltc は通常、ビルドプロセス中に実行されます。したがって、qmltc が QML ドキュメントを拒否した場合(エラーや警告、あるいは qmltc がまだサポートしていない構文が原因であるかどうかに関わらず)、ビルドプロセスは失敗します。 これは、QML モジュールの作成時に linting ターゲットの自動生成を有効にし、qmllint を実行するためにそれらを「ビルド」しようとすると qmllint エラーが表示されるのと同様です。

警告: qmltcは 現在テクニカルプレビュー段階にあり、任意のQMLプログラムをコンパイルできない場合があります(詳細については「既知の制限事項」を参照してください)。 qmltc が失敗した場合、アプリケーションは qmltc の出力を適切に使用できないため、何も生成されません。プログラムにエラー(または解決不可能な警告)が含まれている場合は、コンパイルを可能にするためにそれらを修正する必要があります。一般的なルールとして、ベストプラクティスを遵守し、qmllintのアドバイスに従うことが重要です。

注: qmltc は 、生成されたC++コードが、過去または将来のバージョン(パッチバージョンを含む)間で、API、ソース、またはバイナリ互換性を維持することを保証しません。 さらに、QtのQmlモジュールを使用するqmltcでコンパイルされたアプリは、QtのプライベートAPIへのリンクが必要となります。これは、QtのQmlモジュールが主にQmlを通じて使用されるため、通常はパブリックなC++ APIを提供していないためです。

QMLアプリケーションでのqmltcの使用

ビルドシステムの観点から見ると、qmltc によるコンパイルの追加は、qml キャッシュの生成を追加することとそれほど変わりません。大まかに言えば、ビルドプロセスは次のように説明できます。

このフローチャートは、qml タイプコンパイラを使用して qml ファイルと C++ ファイルをコンパイルする方法を示しています。

実際のコンパイルプロセスははるかに複雑ですが、この図は qmltc が使用する中核的なコンポーネント、すなわち QML ファイル自体と、qmltypes 情報を含む qmldir を捉えています。 単純なアプリケーションでは、qmldirは比較的原始的なものですが、一般的にはqmldirは複雑になり得ます。そこには、qmltcがQMLからC++への正しい変換を行うために依存する、不可欠で適切にパッケージ化された型情報が含まれています。

とはいえ、qmltc の場合、ビルド工程を 1 つ追加するだけでは不十分です。QQmlComponent やその上位レベルの代替手段の代わりに、qmltc が生成したクラスを使用するように、アプリケーションコードも修正する必要があります。

qmltc による QML コードのコンパイル

Qt 6 以降、Qt はそのさまざまなコンポーネントのビルドに CMake を使用しています。 ユーザープロジェクトでも、Qtを使用してコンポーネントをビルドするためにCMakeを使用することができ、また推奨されています。プロジェクトにqmltcのコンパイルサポートをそのまま追加するには、CMake主導のビルドフローも必要となります。これは、このフローが適切なQMLモジュールとそのインフラストラクチャを中心に構成されているためです。

qmltc コンパイル機能を追加する簡単な方法は、アプリケーション用の QML モジュール作成の一環として、専用のCMake APIを使用することです。簡単なアプリケーションのディレクトリ構造を例に考えてみましょう:

.
├── 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

その場合、CMakeコードは通常、次のようなものになります:

# 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)

生成されたC++の使用

QQmlComponent のインスタンス化とは異なり、qmltcの出力(C++コード)はアプリケーションによって直接使用されます。一般的に、C++で新しいオブジェクトを構築することは、QQmlComponent::create() を通じて新しいオブジェクトを作成することと同等です。作成されたオブジェクトは、C++から操作したり、例えばQQuickWindow と組み合わせて画面上に描画したりすることができます。

コンパイル済み型がいくつかの必須プロパティを公開している場合、`qmltc` は生成されるオブジェクトのコンストラクタにおいて、それらのプロパティの初期値を要求します。

さらに、qmltc オブジェクトのコンストラクタには、コンポーネントのプロパティの初期値を設定するためのコールバックを渡すことができます。

myApp.qml ファイルがある場合、アプリケーションコード(どちらの場合も)は通常、次のようなものになります:

#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();

QMLエンジン

生成されたコードは、QMLドキュメントの動的な部分(主にJavaScriptコード)とやり取りするためにQQmlEngine を使用します。これを機能させるために、特別な設定は必要ありません。qmltcによって生成されたクラスオブジェクトのコンストラクタに渡されるQQmlEngine インスタンスは、QQmlComponent(engine) と同様に正しく動作するはずです。これはまた、QMLの挙動に影響を与えるQQmlEngine methods を使用できることを意味します。 ただし、注意点があります。QQmlComponent に基づくオブジェクト生成とは異なり、qmltc 自体はコードを C++ にコンパイルする際、QQmlEngine に依存しません。例えば、QQmlEngine::addImportPath("/foo/bar/") は通常、スキャン対象となる追加のインポートパスを生成しますが、qmltc の事前コンパイル処理では完全に無視されます。

注: qmltc コンパイルにインポートパスを追加するには 、代わりにCMake コマンドの関連する引数を使用することを検討してください。

一般的に、次のように考えることができます。QQmlEngine はアプリケーションプロセスを実行することを前提としていますが、qmltcはアプリケーションがコンパイルされる前に動作するため、そのようなプロセスを必要としません。 qmltc はアプリケーションの C++ ソースコードを内省しようとはしないため、ユーザーであるあなたが実行する特定の種類の QML 操作について、qmltc が知る方法はありません。QQmlEngine や関連するランタイムルーチンを使用してQMLに型を公開したり、インポートパスを追加したりする代わりに、実際には、適切に動作するQMLモジュールを作成し、宣言型のQML型登録を使用する必要があります。

警告: qmltcはQQmlEngine と密接に連携してC++コードを生成しますが 、生成されたクラスをQMLにさらしてQQmlComponent を通じて使用することはできません。

生成出力の基本

qmltc は、既存のQML実行モデルとの互換性を目指しています。これは、生成されたコードがQQmlComponent の内部セットアップロジックと概ね同等であることを意味し、したがって、対応するQMLドキュメントを視覚的に確認することで、現在と同様にQML型の動作、セマンティクス、およびAPIを理解できるはずです。

ただし、特にアプリケーションのC++側でqmltcの出力を直接使用する必要があることを考えると、生成されたコードは依然として多少分かりにくい部分があります。生成されたコードには、CMakeビルドファイルの構造と生成されたC++フォーマットという2つの部分があります。前者はqmltcのCMake APIで扱われており、後者はここで説明します。

hello プロパティを持ち、そのプロパティを出力する関数、およびその型のオブジェクトが作成された際に発火するシグナルを持つ、単純なHelloWorld型を考えてみましょう:

// 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();
}

このQML型のC++版を提供する場合、C++クラスには、QML固有のメタオブジェクトシステムマクロ、hello プロパティ用のQ_PROPERTY デコレーション、Q_INVOKABLE C++出力関数、および通常のQtシグナル定義が必要となります。同様に、qmltcは与えられたHelloWorld型を、おおむね次のように変換します:

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);

    // ...
};

生成される型の具体的な詳細は異なる場合がありますが、共通する側面は変わりません。例えば:

  • ドキュメント内の QML 型は、コンパイラが認識できる情報に基づいて C++ 型に変換されます。
  • プロパティは、Q_PROPERTY 宣言を持つC++プロパティに変換されます。
  • JavaScript関数は、Q_INVOKABLE を含むC++関数となります。
  • Qt Qmlシグナルは、xml-ph-0000@deepl.internalを備えたC++のQtシグナルに変換されます。
  • QMLの列挙型は、Q_ENUM による宣言を持つC++の列挙型に変換されます。

もう 1 つ注目すべき点は、qmltc がクラス名を生成する方法です。特定の QML 型のクラス名は、その型を定義する QML ドキュメントから自動的に推測されます。つまり、拡張子を除いた QML ファイル名(最初の「. 」までの部分、つまりベース名)がクラス名になります。 ファイル名の大文字小文字は保持されます。したがって、HelloWorld.qml の場合、class HelloWorld が生成され、helloWoRlD.qml の場合、class helloWoRlD が生成されます。QMLの規約に従い、QMLドキュメントのファイル名が小文字で始まる場合、生成されるC++クラスは匿名クラスとみなされ、QML_ANONYMOUS でマークされます。

現時点では、生成されたコードは C++ アプリケーション側から利用可能ですが、一般的には生成された API への呼び出しは制限すべきです。 その代わりに、アプリケーションロジックはQML/JavaScriptおよびQMLに公開された手書きのC++型で実装し、qmltcによって生成されたクラスは単純なオブジェクトのインスタンス化にのみ使用することを推奨します。生成されたC++コードを使用すると、QMLで定義されたその型の要素に直接(そして通常はより高速に)アクセスできますが、そのようなコードの理解は困難を伴う可能性があります。

既知の制限事項

qmltc は多くの一般的な QML 機能を網羅していますが、まだ開発の初期段階にあり、サポートされていない機能もいくつかあります。

QMLで定義された型(QtQuick.Controls など)で構成されるインポートされたQMLモジュールは、たとえそれらのQMLで定義された型がqmltcによってコンパイルされていたとしても、正しくコンパイルされない可能性があります。現時点では、QtQml やQtQuick のモジュール、およびQMLに公開されているC++クラスだけを含むその他のQMLモジュールは、確実に使用できます。

これに加え、考慮すべきさらに根本的な特異性がいくつかあります:

  • QtのQmlモジュールは通常、主要な処理をC++ライブラリに依存しています。多くの場合、これらのライブラリは(主にQmlを通じて使用されるため)公開C++ APIを提供していません。qmltcのユーザーにとって、これはアプリケーションが非公開のQtライブラリに対してリンクする必要があることを意味します。
  • qmltcのコード生成の性質上、QMLプラグインはコンパイル目的では使用できません。その代わりに、プラグインを使用するQMLモジュールは、コンパイル時にプラグインのデータにアクセスできることを保証する必要があります。このようなQMLモジュールには、オプションのプラグインが搭載されることになります。 ほとんどの場合、コンパイル時の情報は、ヘッダーファイル(C++宣言を含む)とリンク可能なライブラリ(C++定義を含む)を通じて提供できます。ヘッダーファイルへのパスを指定し、QMLモジュールライブラリに対してリンクを行うのは、ユーザーコードの責任となります(通常はCMakeを通じて行われます)。

注: コンパイラは現在 テクニカルプレビュー段階であるため 、qmltc、生成されたコード、またはその他の関連部分でバグに遭遇する可能性があります。その場合は、バグレポートの提出をお願いいたします。

© 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.