Skip to content

Commit ade9c8b

Browse files
committed
qt-build-utils: add QmlPluginCppBuilder for the extension plugin
1 parent 011efa8 commit ade9c8b

File tree

4 files changed

+97
-54
lines changed

4 files changed

+97
-54
lines changed

crates/qt-build-utils/src/builder/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
mod qmldir;
77
pub use qmldir::QmlDirBuilder;
88

9+
mod qmlplugincpp;
10+
pub use qmlplugincpp::QmlPluginCppBuilder;
11+
912
mod qmluri;
1013
pub use qmluri::QmlUriBuilder;
1114

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// SPDX-FileCopyrightText: 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
2+
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
3+
//
4+
// SPDX-License-Identifier: MIT OR Apache-2.0
5+
6+
use crate::QmlUriBuilder;
7+
8+
/// A builder for representing a QML Extension Plugin C++ code
9+
pub struct QmlPluginCppBuilder {
10+
plugin_class_name: String,
11+
qml_cache: bool,
12+
uri: QmlUriBuilder,
13+
}
14+
15+
impl QmlPluginCppBuilder {
16+
/// Construct a [QmlPluginCppBuilder] from a uri and plugin class name
17+
pub fn new(uri: QmlUriBuilder, plugin_class_name: String) -> Self {
18+
Self {
19+
plugin_class_name,
20+
qml_cache: false,
21+
uri,
22+
}
23+
}
24+
25+
/// Whether to enable qmlcache methods
26+
pub fn with_qml_cache(mut self, enabled: bool) -> Self {
27+
self.qml_cache = enabled;
28+
self
29+
}
30+
31+
/// Build the resultant QML extension plugin C++ contents
32+
pub fn build(self) -> String {
33+
let plugin_class_name = self.plugin_class_name;
34+
let qml_uri_underscores = self.uri.as_underscores();
35+
36+
let mut declarations = Vec::default();
37+
let mut usages = Vec::default();
38+
39+
let mut generate_usage = |return_type: &str, function_name: &str| {
40+
declarations.push(format!("extern {return_type} {function_name}();"));
41+
usages.push(format!("volatile auto {function_name}_usage = &{function_name};\nQ_UNUSED({function_name}_usage);"));
42+
};
43+
44+
// This function is generated by qmltyperegistrar
45+
generate_usage("void", &format!("qml_register_types_{qml_uri_underscores}"));
46+
generate_usage(
47+
"int",
48+
&format!("qInitResources_qml_module_resources_{qml_uri_underscores}_qrc"),
49+
);
50+
51+
if self.qml_cache {
52+
generate_usage(
53+
"int",
54+
&format!("qInitResources_qmlcache_{qml_uri_underscores}"),
55+
);
56+
}
57+
let declarations = declarations.join("\n");
58+
let usages = usages.join("\n");
59+
format!(
60+
r#"
61+
#include <QtQml/qqmlextensionplugin.h>
62+
63+
// TODO: Add missing handling for GHS (Green Hills Software compiler) that is in
64+
// https://code.qt.io/cgit/qt/qtbase.git/plain/src/corelib/global/qtsymbolmacros.h
65+
{declarations}
66+
67+
class {plugin_class_name} : public QQmlEngineExtensionPlugin
68+
{{
69+
Q_OBJECT
70+
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlEngineExtensionInterface")
71+
72+
public:
73+
{plugin_class_name}(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent)
74+
{{
75+
{usages}
76+
}}
77+
}};
78+
79+
// The moc-generated cpp file doesn't compile on its own; it needs to be #included here.
80+
#include "moc_{plugin_class_name}.cpp.cpp"
81+
"#
82+
)
83+
}
84+
}

crates/qt-build-utils/src/builder/qmluri.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55

66
/// A builder for representing a QML uri
7+
#[derive(Clone)]
78
pub struct QmlUriBuilder {
89
uri: Vec<String>,
910
}

crates/qt-build-utils/src/lib.rs

Lines changed: 9 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
#![allow(clippy::too_many_arguments)]
1717

1818
mod builder;
19-
pub use builder::{QResource, QResourceBuilder, QResourceFile, QmlDirBuilder, QmlUriBuilder};
19+
pub use builder::{
20+
QResource, QResourceBuilder, QResourceFile, QmlDirBuilder, QmlPluginCppBuilder, QmlUriBuilder,
21+
};
2022

2123
mod error;
2224
pub use error::QtBuildError;
@@ -172,7 +174,7 @@ impl QtBuild {
172174
// Generate qmldir file
173175
let qmldir_file_path = qml_module_dir.join("qmldir");
174176
{
175-
let qmldir = QmlDirBuilder::new(qml_uri)
177+
let qmldir = QmlDirBuilder::new(qml_uri.clone())
176178
.with_plugin(plugin_name.to_string(), true)
177179
.with_class_name(plugin_class_name.clone())
178180
.with_type_info(plugin_type_info.to_string())
@@ -272,58 +274,11 @@ impl QtBuild {
272274
let qml_plugin_cpp_path = qml_plugin_dir.join(format!("{plugin_class_name}.cpp"));
273275
let include_path;
274276
{
275-
let mut declarations = Vec::default();
276-
let mut usages = Vec::default();
277-
278-
let mut generate_usage = |return_type: &str, function_name: &str| {
279-
declarations.push(format!("extern {return_type} {function_name}();"));
280-
usages.push(format!("volatile auto {function_name}_usage = &{function_name};\nQ_UNUSED({function_name}_usage);"));
281-
};
282-
283-
// This function is generated by qmltyperegistrar
284-
generate_usage("void", &format!("qml_register_types_{qml_uri_underscores}"));
285-
generate_usage(
286-
"int",
287-
&format!("qInitResources_qml_module_resources_{qml_uri_underscores}_qrc"),
288-
);
289-
290-
if !qml_files.is_empty() && !qmlcachegen_file_paths.is_empty() {
291-
generate_usage(
292-
"int",
293-
&format!("qInitResources_qmlcache_{qml_uri_underscores}"),
294-
);
295-
}
296-
let declarations = declarations.join("\n");
297-
let usages = usages.join("\n");
298-
299-
std::fs::write(
300-
&qml_plugin_cpp_path,
301-
format!(
302-
r#"
303-
#include <QtQml/qqmlextensionplugin.h>
304-
305-
// TODO: Add missing handling for GHS (Green Hills Software compiler) that is in
306-
// https://code.qt.io/cgit/qt/qtbase.git/plain/src/corelib/global/qtsymbolmacros.h
307-
{declarations}
308-
309-
class {plugin_class_name} : public QQmlEngineExtensionPlugin
310-
{{
311-
Q_OBJECT
312-
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlEngineExtensionInterface")
313-
314-
public:
315-
{plugin_class_name}(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent)
316-
{{
317-
{usages}
318-
}}
319-
}};
320-
321-
// The moc-generated cpp file doesn't compile on its own; it needs to be #included here.
322-
#include "moc_{plugin_class_name}.cpp.cpp"
323-
"#,
324-
),
325-
)
326-
.expect("Failed to write plugin definition");
277+
let qml_plugin_cpp = QmlPluginCppBuilder::new(qml_uri, plugin_class_name.clone())
278+
.with_qml_cache(!qml_files.is_empty() && !qmlcachegen_file_paths.is_empty())
279+
.build();
280+
std::fs::write(&qml_plugin_cpp_path, qml_plugin_cpp)
281+
.expect("Failed to write plugin definition");
327282

328283
let moc_product = self.moc().compile(
329284
&qml_plugin_cpp_path,

0 commit comments

Comments
 (0)