Skip to content

Add support for C++ QML Elements in CxxQtBuilder #1146

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

akiselev
Copy link
Contributor

@akiselev akiselev commented Dec 19, 2024

This PR is a WIP to add support for registering classes implemented in C++ with a QML module so that they can be included in Cargo-only builds. Instead of just running moc on a header, it also includes the generated metatype information which is needed to register the C++ QML elements.

This first implementation is one I wrote to unblock my own project so I'd appreciate some advice for how to integrate this properly into cxx-qt-build. It should probably be another property on QmlModule like so, but I couldn't figure out how to best implement it that way:

    let module: QmlModule<&str, &str> = QmlModule {
        uri: "Clippo.Theme",
        rust_files: &[
            "src/theme.rs",
        ],
        cpp_files: &[
            ("src/ThemeManager.h", "src/ThemeManager.cpp"),
        ],
        ..Default::default()
    };

With @LeonMatthesKDAB's temporary fix found in #1135, it correctly includes C++ QML elements in modules built with Cargo only.

@akiselev akiselev changed the title Add support for C++ QML QObjects in CxxQtBuilder Add support for C++ QML Elements in CxxQtBuilder Dec 19, 2024
Copy link

codecov bot commented Dec 19, 2024

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (5881415) to head (4d12f16).

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #1146   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           75        75           
  Lines        12761     12761           
=========================================
  Hits         12761     12761           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@redstrate redstrate left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this deserves a mention in CHANGELOG.md, can you add it to the MR?

/// Specify a C++ header and source file containing a Q_OBJECT macro to run [moc](https://doc.qt.io/qt-6/moc.html) on.
/// Unlike [CxxQtBuilder::qobject_header], it includes the generated metatypes.json, so that C++ classes can be included
/// in QML modules.
pub fn qml_qobject(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cpp_qobject ? I guess this could have other applications outside of QML

@LeonMatthesKDAB
Copy link
Collaborator

Hi @akiselev ,
as you mentioned, the best way to integrate this is indeed as a property on QmlModule.
The design of the QmlModule type is unfortunately a bit overly complicated, as it uses two template types, which we really don't want to expand.
My suggestion is to just hijack the existing A type, like we do for qrc_files.

I'm okay with the "list of tuples" approach you have in your initial comment.
We could even consider just a plain list of cpp_files, as we should be able to differentiate between .cpp and .h files by the extension.

Please note that for version 0.8 we are planning a larger refactor of the build system, which will likely end up supporting what you're currently asking anyway due to the nature of the proposed architecture.
See also: #1125
(basically: The qobject_header call should in future take care of registering automatically, if you're buidling a Qml module).

- Introduce qml_qobjects field to CxxQtBuilder struct
- Implement qml_qobject method for adding QML QObject files
- Process QML QObjects in build method, including moc generation
- Include generated metatypes.json for QML module support
- Update rerun-if-changed cargo instructions for added files
@Copilot Copilot AI review requested due to automatic review settings August 8, 2025 00:53
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for registering C++ QML elements in CxxQtBuilder by implementing a qml_qobject method that processes C++ header/source file pairs and includes their generated metatype information. This enables C++ classes to be properly registered with QML modules in Cargo-only builds.

  • Adds qml_qobjects field to store C++ header/source file pairs
  • Implements qml_qobject method to register C++ QML objects with metatype generation
  • Integrates MOC processing and metatypes collection into the build process

Comment on lines +594 to +595
/// Unlike [CxxQtBuilder::qobject_header], it includes the generated metatypes.json, so that C++ classes can be included
/// in QML modules.
Copy link
Preview

Copilot AI Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation should clarify the difference between this method and qobject_header more explicitly. Currently it only mentions that it 'includes the generated metatypes.json' but doesn't explain when to use each method.

Suggested change
/// Unlike [CxxQtBuilder::qobject_header], it includes the generated metatypes.json, so that C++ classes can be included
/// in QML modules.
///
/// This method is intended for integrating C++ QObject subclasses into QML modules. In addition to running `moc` on the provided files,
/// it generates and includes the `metatypes.json` file required for QML registration, allowing the C++ classes to be used directly in QML.
///
/// In contrast, [`CxxQtBuilder::qobject_header`] only runs `moc` on a header file and does **not** generate or include `metatypes.json`.
/// Use `qobject_header` when you only need to integrate a C++ QObject subclass with Qt (for example, for signal/slot support in C++),
/// but do **not** need to expose the class to QML.
///
/// **Use this method (`qml_qobject`) when you want your C++ QObject to be available in QML.**

Copilot uses AI. Check for mistakes.

}
let moc_products = qtbuild.moc(
qobject_header,
MocArguments::default().uri(qml_module.uri.clone()),
Copy link
Preview

Copilot AI Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The qml_module.uri is being cloned inside a loop. Consider cloning it once before the loop and reusing the cloned value to avoid repeated allocations.

Suggested change
MocArguments::default().uri(qml_module.uri.clone()),
MocArguments::default().uri(qml_module_uri.clone()),

Copilot uses AI. Check for mistakes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants