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

/*!
\page qtqml-modules-cmake-integration.html
\title Tying it all together with CMake
\brief Building QML modules with CMake

The \l{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
\c{qt_add_qml_module} and walks through common usage patterns.

For the full reference of all options, see \l{qt_add_qml_module}.

\section1 Key Concepts

Before looking at examples, it helps to understand what \c{qt_add_qml_module}
actually creates:

\list
\li A \e{backing target} — a library (or executable) containing the module's
    C++ code, compiled QML files, and resources. This is the first argument to
    \c{qt_add_qml_module} and is the target you link against. It can either
    be an existing target (created earlier with \c{qt_add_executable} or
    \c{qt_add_library}) or \c{qt_add_qml_module} will create it for you.
\li A \e{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 \l{qt_add_qml_module}{NO_PLUGIN}.
\li A \e{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.
\li A \e{typeinfo file} (\c{.qmltypes}) — machine-readable type information
    used by QML tooling (\l{qmlcachegen}, \l{qmllint}, \l{\QMLLS}{qmlls},
    Qt Creator). Also generated automatically.
\endlist

\section1 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 \c{MyCompany.Controls} should live in:

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

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 \l{OUTPUT_DIRECTORY} so that the build output lands in a
path matching the URI, and \l{IMPORT_PATH} so that the QML engine and tooling
can locate the module.

\section1 Common Patterns

\section2 QML-only Application

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

\badcode
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)
\endcode

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

\section2 Application with C++ Types

An application that exposes C++ types to QML:

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

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

\section2 Reusable Library Module

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

\badcode
# 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
)
\endcode

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

\section2 Application Using a Library Module

Using the \c{mycontrols} module from the \l{Reusable Library Module} example
above:

\badcode
# 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)
\endcode

The \l{qt_add_qml_module}{DEPENDENCIES} line ensures that QML tooling
(\l{qmlcachegen}, \l{qmllint}, \l{\QMLLS}{qmlls}) can find the types provided by
\c{MyCompany.Controls}.

\badcode
// In Main.qml
import MyCompany.Controls

Button { text: "Click me" }
\endcode

\section2 Module with Singletons

QML files providing singleton types need a source file property set
\e{before} the \c{qt_add_qml_module} call:

\badcode
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
)
\endcode

The QML file must also contain \c{pragma Singleton}. Both the CMake property
and the QML pragma are required.

\section2 Module with Custom Plugin

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

\badcode
# 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)
\endcode

\badcode
// 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"
\endcode

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

\section1 Adding Further QML Files

For QML files added after the initial \c{qt_add_qml_module} call, use
\l{qt_target_qml_sources}:

\code
qt_target_qml_sources(my_qml_module
    QML_FILES
        DynamicallyAddedType.qml
)
\endcode

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

\section1 Detailed CMake Reference

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

\sa {QML Modules}, {qt_add_qml_module}, {Writing QML Modules}
*/
