Skip to content

Commit d82ad6c

Browse files
Object type declarations in qmldir-files (#1349)
* added BlueRect.qml to the qml_multi_crates example. Added the file to the sub1 subproject and a call to it in main.qml. * now the qmldir generator output object type declarations * Use local paths for qml files in QmlDirBuilder The QmlDirBuilder should only build the contents of the qmldir files, and not modify any files on disk. Ensuring the files are in the correct (relative) paths of the QML module is the responsibility of register_qml_module. * Add license header to BlueRect.qml * Do not use OsStr::display due to MSRV * Remove version form QmlDirBuilder These should be specified per-file, and not for the entire module --------- Co-authored-by: Leon Matthes <leon.matthes@kdab.com>
1 parent c415678 commit d82ad6c

File tree

5 files changed

+75
-6
lines changed

5 files changed

+75
-6
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ mod utils;
4949

5050
use std::{
5151
env,
52+
ffi::OsStr,
5253
fs::File,
5354
path::{Path, PathBuf},
5455
};
@@ -171,11 +172,22 @@ impl QtBuild {
171172
// Generate qmldir file
172173
let qmldir_file_path = qml_module_dir.join("qmldir");
173174
{
175+
let qml_type_files = qml_files.iter().filter(|path| {
176+
// Qt by default only includes uppercase files in the qmldir file.
177+
// Mirror this behavior.
178+
path.as_ref()
179+
.file_name()
180+
.and_then(OsStr::to_str)
181+
.and_then(|file_name| file_name.chars().next())
182+
.map(char::is_uppercase)
183+
.unwrap_or_default()
184+
});
174185
let mut file = File::create(&qmldir_file_path).expect("Could not create qmldir file");
175186
QmlDirBuilder::new(uri.clone())
176187
.plugin(plugin_name, true)
177188
.class_name(&plugin_class_name)
178189
.type_info(plugin_type_info)
190+
.qml_files(qml_type_files)
179191
.write(&mut file)
180192
.expect("Could not write qmldir file");
181193
}

crates/qt-build-utils/src/qml/qmldir.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55

66
use crate::QmlUri;
77

8+
use std::ffi::OsStr;
89
use std::io;
10+
use std::path::{Path, PathBuf};
911

1012
/// QML module definition files builder
1113
///
@@ -16,6 +18,7 @@ pub struct QmlDirBuilder {
1618
plugin: Option<(bool, String)>,
1719
type_info: Option<String>,
1820
uri: QmlUri,
21+
qml_files: Vec<PathBuf>,
1922
}
2023

2124
impl QmlDirBuilder {
@@ -27,6 +30,7 @@ impl QmlDirBuilder {
2730
depends: vec![],
2831
plugin: None,
2932
type_info: None,
33+
qml_files: vec![],
3034
uri,
3135
}
3236
}
@@ -58,7 +62,31 @@ impl QmlDirBuilder {
5862
}
5963

6064
// Prefer is always specified for now
61-
writeln!(writer, "prefer :/qt/qml/{}/", self.uri.as_dirs())
65+
writeln!(writer, "prefer :/qt/qml/{}/", self.uri.as_dirs())?;
66+
67+
for qml_file in &self.qml_files {
68+
let is_qml_file = qml_file
69+
.extension()
70+
.map(|ext| ext.eq_ignore_ascii_case("qml"))
71+
.unwrap_or_default();
72+
73+
if !is_qml_file {
74+
panic!("QML file does not end with .qml: {}", qml_file.display(),);
75+
}
76+
77+
let path = qml_file.display();
78+
let qml_component_name = qml_file
79+
.file_stem()
80+
.and_then(OsStr::to_str)
81+
.expect("Could not get qml file stem");
82+
83+
// Qt6 simply uses version 254.0 if no specific version is provided
84+
// Until we support versions of individal qml files, we will use 254.0
85+
writeln!(writer, "{qml_component_name} 254.0 {path}",)
86+
.expect("Could not write qmldir file");
87+
}
88+
89+
Ok(())
6290
}
6391

6492
/// Provides the class name of the C++ plugin used by the module.
@@ -110,6 +138,15 @@ impl QmlDirBuilder {
110138
self
111139
}
112140

141+
/// Declares a list of .qml files that are part of the module.
142+
pub fn qml_files(mut self, qml_files: impl IntoIterator<Item = impl AsRef<Path>>) -> Self {
143+
self.qml_files = qml_files
144+
.into_iter()
145+
.map(|p| p.as_ref().to_owned())
146+
.collect();
147+
self
148+
}
149+
113150
/// Declares a type description file for the module that can be read by QML
114151
/// tools such as Qt Creator to access information about the types defined
115152
/// by the module's plugins. File is the (relative) file name of a
@@ -139,6 +176,7 @@ mod test {
139176
.depends(["QtQuick", "com.kdab.a"])
140177
.plugin("P", true)
141178
.type_info("T")
179+
.qml_files(&["qml/Test.qml"])
142180
.write(&mut result)
143181
.unwrap();
144182
assert_eq!(
@@ -150,6 +188,7 @@ typeinfo T
150188
depends QtQuick
151189
depends com.kdab.a
152190
prefer :/qt/qml/com/kdab/
191+
Test 254.0 qml/Test.qml
153192
"
154193
);
155194
}

examples/qml_multi_crates/qml/main.qml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ ApplicationWindow {
1818
title: qsTr("CXX-Qt: Hello World")
1919
visible: true
2020

21+
BlueRect {
22+
id: blueRect
23+
}
24+
2125
MainObject {
2226
id: main
2327
}

examples/qml_multi_crates/rust/sub1/build.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
use cxx_qt_build::{CxxQtBuilder, QmlModule};
77

88
fn main() {
9-
CxxQtBuilder::new_qml_module(QmlModule::new("com.kdab.cxx_qt.demo.sub1"))
10-
.qt_module("Network")
11-
.files(["src/sub1_object.rs"])
12-
.build()
13-
.export();
9+
CxxQtBuilder::new_qml_module(
10+
QmlModule::new("com.kdab.cxx_qt.demo.sub1").qml_file("qml/BlueRect.qml"),
11+
)
12+
.qt_module("Network")
13+
.files(["src/sub1_object.rs"])
14+
.build()
15+
.export();
1416
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// SPDX-FileCopyrightText: 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
2+
//
3+
// SPDX-License-Identifier: MIT OR Apache-2.0
4+
5+
import QtQuick
6+
7+
Rectangle {
8+
anchors.centerIn: parent
9+
height: 100
10+
width: 100
11+
color: "blue"
12+
}

0 commit comments

Comments
 (0)