- Qt 6.12
- Qt Qml
- The QML Reference
- QML Modules
- Tying it all together with CMake
- Qt 6.12.0 Reference Documentation

Exposing State from C++ to QML ◦ Modernizing QML modules

# Tying it all together with CMake

The qt_add_qml_module CMake command is the recommended way to define QML modules. It automates type registration, resource embedding, plugin creation, and tooling integration. This page explains the concepts behind `qt_add_qml_module` and walks through common usage patterns.

For the full reference of all options, see qt_add_qml_module.

## Key Concepts

Before looking at examples, it helps to understand what `qt_add_qml_module` actually creates:

- A backing target — a library (or executable) containing the module's C++ code, compiled QML files, and resources. This is the first argument to `qt_add_qml_module` and is the target you link against. It can either be an existing target (created earlier with `qt_add_executable` or `qt_add_library`) or `qt_add_qml_module` will create it for you.
- A plugin target — a small library that allows the QML engine to load the module dynamically at run time. It is created automatically and is separate from the backing target. When an executable links directly to the backing target, the plugin is not loaded at run time. The plugin can be omitted entirely using NO_PLUGIN.
- A qmldir file — a module metadata file that tells the QML engine what types the module provides and where to find them. It is generated automatically.
- A typeinfo file (`.qmltypes`) — machine-readable type information used by QML tooling (qmlcachegen, qmllint, qmlls, Qt Creator). Also generated automatically.

## Directory Structure

The source directory structure should mirror the module's URI. The URI is converted to a path by replacing dots with forward slashes. For example, a module with URI `MyCompany.Controls` should live in:

     src/MyCompany/Controls/CMakeLists.txt
     src/MyCompany/Controls/Button.qml
     src/MyCompany/Controls/mywidget.cpp
     src/MyCompany/Controls/mywidget.h

This convention allows the QML engine and tooling to find modules without additional configuration. If your directory structure doesn't match the URI, you'll need to set OUTPUT_DIRECTORY so that the build output lands in a path matching the URI, and IMPORT_PATH so that the QML engine and tooling can locate the module.

## Common Patterns

### QML-only Application

The simplest case: an executable with only QML files and no C++ types.

     cmake_minimum_required(VERSION 3.16)
     project(myapp LANGUAGES CXX)

     find_package(Qt6 REQUIRED COMPONENTS Quick)
     qt_standard_project_setup(REQUIRES 6.8)

     qt_add_executable(myapp)
     qt_add_qml_module(myapp
         URI MyApp
         QML_FILES
             Main.qml
             Button.qml
         RESOURCES
             images/logo.png
     )

     target_link_libraries(myapp PRIVATE Qt6::Quick)

Because the backing target is an executable, no plugin is created. The QML files are compiled and embedded as resources. The `RESOURCES` keyword adds non-QML files (images, fonts, etc.) to the same resource hierarchy.

### Application with C++ Types

An application that exposes C++ types to QML:

     qt_add_executable(myapp)
     qt_add_qml_module(myapp
         URI MyApp
         QML_FILES
             Main.qml
         SOURCES
             backend.cpp backend.h
     )

The C++ types in `backend.h` must be annotated with QML_ELEMENT (or similar macros like QML_NAMED_ELEMENT) and must use the Q_OBJECT or Q_GADGET macro. Type registration happens automatically via `AUTOMOC`. See Registering C++ Types with the QML Type System for a full overview of the available registration macros.

### Reusable Library Module

A QML module packaged as a library that other projects or modules can import:

     # In src/MyCompany/Controls/CMakeLists.txt
     qt_add_qml_module(mycontrols
         URI MyCompany.Controls
         QML_FILES
             Button.qml
             Slider.qml
         SOURCES
             theme.cpp theme.h
     )

This creates two targets: `mycontrols` (the backing library) and `mycontrolsplugin` (the plugin). Other modules import it with `import MyCompany.Controls` in QML. Applications that link to `mycontrols` directly don't need to load the plugin at run time.

### Application Using a Library Module

Using the `mycontrols` module from the Reusable Library Module example above:

     # In the application's CMakeLists.txt
     qt_add_executable(myapp)
     qt_add_qml_module(myapp
         URI MyApp
         QML_FILES Main.qml
         DEPENDENCIES TARGET mycontrols
     )

     target_link_libraries(myapp PRIVATE mycontrols)

The DEPENDENCIES line ensures that QML tooling (qmlcachegen, qmllint, qmlls) can find the types provided by `MyCompany.Controls`.

     // In Main.qml
     import MyCompany.Controls

     Button { text: "Click me" }

### Module with Singletons

QML files providing singleton types need a source file property set before the `qt_add_qml_module` call:

     set_source_files_properties(Theme.qml PROPERTIES QT_QML_SINGLETON_TYPE TRUE)

     qt_add_qml_module(mymodule
         URI MyModule
         QML_FILES
             Theme.qml
             Main.qml
     )

The QML file must also contain `pragma Singleton`. Both the CMake property and the QML pragma are required.

### Module with Custom Plugin

When you need to perform custom initialization (for example, registering an image provider), you can provide your own QQmlEngineExtensionPlugin subclass.

     # In CMakeLists.txt
     qt_add_qml_module(mymodule
         URI MyModule
         NO_GENERATE_PLUGIN_SOURCE
         NO_PLUGIN_OPTIONAL
         CLASS_NAME MyModulePlugin
         QML_FILES
             Main.qml
         SOURCES
             myimageprovider.cpp myimageprovider.h
     )

     # Add the custom plugin source to the plugin target
     target_sources(mymoduleplugin PRIVATE plugin.cpp)

     // In plugin.cpp
     #include <QtQml/QQmlEngineExtensionPlugin>
     #include "myimageprovider.h"

     class MyModulePlugin : public QQmlEngineExtensionPlugin
     {
         Q_OBJECT
         Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid)
     public:
         void initializeEngine(QQmlEngine *engine, const char *uri) override
         {
             engine->addImageProvider("myprovider", new MyImageProvider);
         }
     };

     #include "plugin.moc"

NO_GENERATE_PLUGIN_SOURCE tells the build system not to generate the default plugin source. CLASS_NAME must match the class name in your implementation. NO_PLUGIN_OPTIONAL ensures the plugin is always loaded, since it contains initialization logic that would be skipped otherwise.

## Adding Further QML Files

For QML files added after the initial `qt_add_qml_module` call, use qt_target_qml_sources:

     qt_target_qml_sources(my_qml_module
         QML_FILES
             DynamicallyAddedType.qml
     )

This is useful for conditionally including files based on platform or configuration.

## Detailed CMake Reference

For complete details on all CMake commands, properties, variables, and policies, see CMake Integration for QML.

See also QML Modules, qt_add_qml_module, and Writing QML Modules.

Exposing State from C++ to QML ◦ Modernizing QML modules