qt_build_utils/qml/
qmlplugincpp.rs1use std::io;
7
8use crate::{Initializer, QmlUri};
9
10#[non_exhaustive]
12#[derive(Clone, Copy, PartialEq, Eq)]
13pub enum PluginType {
14 Static,
16 Dynamic,
20}
21
22pub struct QmlPluginCppBuilder {
24 plugin_class_name: String,
25 qml_cache: bool,
26 uri: QmlUri,
27 plugin_type: PluginType,
28}
29
30impl QmlPluginCppBuilder {
31 pub fn new(uri: QmlUri, plugin_class_name: impl Into<String>) -> Self {
33 Self {
36 plugin_class_name: plugin_class_name.into(),
37 qml_cache: false,
38 plugin_type: PluginType::Static,
39 uri,
40 }
41 }
42
43 pub fn qml_cache(mut self, enabled: bool) -> Self {
45 self.qml_cache = enabled;
46 self
47 }
48
49 pub fn plugin_type(mut self, plugin_type: PluginType) -> Self {
57 self.plugin_type = plugin_type;
58 self
59 }
60
61 pub fn write(self, writer: &mut impl io::Write) -> io::Result<Initializer> {
63 let plugin_class_name = self.plugin_class_name;
64 let qml_uri_underscores = self.uri.as_underscores();
65
66 let mut declarations = Vec::default();
67 let mut usages = Vec::default();
68
69 let mut generate_usage = |return_type: &str, function_name: &str| {
70 declarations.push(format!("extern {return_type} {function_name}();"));
71 usages.push(format!("volatile auto {function_name}_usage = &{function_name};\nQ_UNUSED({function_name}_usage);"));
72 };
73
74 generate_usage("void", &format!("qml_register_types_{qml_uri_underscores}"));
76 generate_usage(
77 "int",
78 &format!("qInitResources_qml_module_resources_{qml_uri_underscores}_qrc"),
79 );
80
81 if self.qml_cache {
82 generate_usage(
83 "int",
84 &format!("qInitResources_qmlcache_{qml_uri_underscores}"),
85 );
86 }
87 let declarations = declarations.join("\n");
88 let usages = usages.join("\n");
89 let init_fn_name = format!("init_cxx_qt_qml_module_{plugin_class_name}");
90 write!(
91 writer,
92 r#"
93#include <QtQml/qqmlextensionplugin.h>
94
95// TODO: Add missing handling for GHS (Green Hills Software compiler) that is in
96// https://code.qt.io/cgit/qt/qtbase.git/plain/src/corelib/global/qtsymbolmacros.h
97{declarations}
98
99class {plugin_class_name} : public QQmlEngineExtensionPlugin
100{{
101 Q_OBJECT
102 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlEngineExtensionInterface")
103
104public:
105 {plugin_class_name}(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent)
106 {{
107 {usages}
108 }}
109}};
110
111extern "C" {{
112 // "drive-by initialization" causes the plugin class to be included in static linking scenarios
113 // Any function that is called from within this file causes the entire object file to be linked in.
114 // Therefore we provide an empty function that can be called at any point to ensure this file is linked in.
115 bool {init_fn_name}() {{
116 return true;
117 }}
118}}
119
120// The moc-generated cpp file doesn't compile on its own; it needs to be #included here.
121#include "moc_{plugin_class_name}.cpp.cpp"
122"#
123 )?;
124 let initializer = match self.plugin_type {
125 PluginType::Static => Initializer {
126 file: None,
127 init_call: None,
128 init_declaration: Some(format!(
129 "#include <QtPlugin>\nQ_IMPORT_PLUGIN({plugin_class_name});"
130 )),
131 },
132 PluginType::Dynamic => Initializer::default_signature(&init_fn_name),
133 };
134 Ok(initializer)
135 }
136}