From 0e9f40e5028a46bbe1c459d587c223c71a0e0c17 Mon Sep 17 00:00:00 2001 From: Be Wilson Date: Thu, 3 Aug 2023 13:39:59 -0500 Subject: [PATCH] register QML modules at build time This is a prerequisite for using qmlcachegen https://github.com/KDAB/cxx-qt/issues/242 --- crates/cxx-qt-build/src/lib.rs | 95 ++++++------- crates/qt-build-utils/src/lib.rs | 145 +++++++++++++++++--- examples/cargo_without_cmake/build.rs | 12 +- examples/cargo_without_cmake/src/main.rs | 2 +- examples/demo_threading/CMakeLists.txt | 1 - examples/demo_threading/cpp/main.cpp | 3 +- examples/demo_threading/qml/Button.qml | 8 +- examples/demo_threading/qml/MainWindow.qml | 34 ++--- examples/demo_threading/qml/Panel.qml | 6 +- examples/demo_threading/qml/SensorUI.qml | 4 +- examples/demo_threading/qml/qml.qrc | 9 -- examples/demo_threading/qml/qml.qrc.license | 5 - examples/demo_threading/rust/build.rs | 43 +++++- examples/qml_features/CMakeLists.txt | 1 - examples/qml_features/cpp/main.cpp | 3 +- examples/qml_features/qml/main.qml | 24 ++-- examples/qml_features/qml/qml.qrc | 25 ---- examples/qml_features/rust/build.rs | 28 +++- examples/qml_minimal/CMakeLists.txt | 4 +- examples/qml_minimal/cpp/main.cpp | 3 +- examples/qml_minimal/qml/qml.qrc | 15 -- examples/qml_minimal/rust/build.rs | 9 +- tests/basic_cxx_only/rust/build.rs | 2 +- tests/basic_cxx_qt/rust/build.rs | 2 +- tests/qt_types_standalone/rust/build.rs | 2 +- 25 files changed, 293 insertions(+), 192 deletions(-) delete mode 100644 examples/demo_threading/qml/qml.qrc delete mode 100644 examples/demo_threading/qml/qml.qrc.license delete mode 100644 examples/qml_features/qml/qml.qrc delete mode 100644 examples/qml_minimal/qml/qml.qrc diff --git a/crates/cxx-qt-build/src/lib.rs b/crates/cxx-qt-build/src/lib.rs index 5ef9c38ce..67f61f869 100644 --- a/crates/cxx-qt-build/src/lib.rs +++ b/crates/cxx-qt-build/src/lib.rs @@ -24,6 +24,8 @@ use std::{ path::{Path, PathBuf}, }; +pub use qt_build_utils::QmlModule; + use cxx_qt_gen::{ parse_qt_file, write_cpp, write_rust, CppFragment, CxxQtItem, GeneratedCppBlocks, GeneratedRustBlocks, Parser, @@ -49,18 +51,6 @@ struct GeneratedCpp { file_ident: String, } -/// Metadata for registering a QML module -struct QmlModule { - /// The URI of the QML module - pub uri: String, - /// The minor version of the QML module - pub version_minor: usize, - /// The major version of the QML module - pub version_major: usize, - /// The .rs files with #[qml_element] attribute(s) - pub rust_files: Vec, -} - impl GeneratedCpp { /// Generate QObject and cxx header/source C++ file contents pub fn new(rust_file_path: impl AsRef) -> Result { @@ -226,7 +216,7 @@ impl GeneratedCpp { /// Generate C++ files from a given list of Rust files, returning the generated paths fn generate_cxxqt_cpp_files( - rs_source: &[PathBuf], + rs_source: &[impl AsRef], header_dir: impl AsRef, ) -> Vec { let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); @@ -234,7 +224,7 @@ fn generate_cxxqt_cpp_files( let mut generated_file_paths: Vec = Vec::with_capacity(rs_source.len()); for rs_path in rs_source { let cpp_directory = format!("{}/cxx-qt-gen/src", env::var("OUT_DIR").unwrap()); - let path = format!("{manifest_dir}/{}", rs_path.display()); + let path = format!("{manifest_dir}/{}", rs_path.as_ref().display()); println!("cargo:rerun-if-changed={path}"); let generated_code = match GeneratedCpp::new(&path) { @@ -251,12 +241,12 @@ fn generate_cxxqt_cpp_files( } fn panic_duplicate_file_and_qml_module( - path: &Path, + path: impl AsRef, uri: &str, version_major: usize, version_minor: usize, ) { - panic!("CXX-Qt bridge Rust file {} specified in QML module {uri} (version {version_major}.{version_minor}), but also specified via CxxQtBuilder::file. Bridge files must be specified via CxxQtBuilder::file or CxxQtBuilder::qml_module, but not both.", path.display()); + panic!("CXX-Qt bridge Rust file {} specified in QML module {uri} (version {version_major}.{version_minor}), but also specified via CxxQtBuilder::file. Bridge files must be specified via CxxQtBuilder::file or CxxQtBuilder::qml_module, but not both.", path.as_ref().display()); } /// Run cxx-qt's C++ code generator on Rust modules marked with the `cxx_qt::bridge` macro, compile @@ -270,7 +260,7 @@ fn panic_duplicate_file_and_qml_module( /// ```no_run /// use cxx_qt_build::CxxQtBuilder; /// -/// CxxQtBuilder::new() +/// CxxQtBuilder::<&str, &str>::new() /// .file("src/lib.rs") /// .build(); /// ``` @@ -292,16 +282,24 @@ fn panic_duplicate_file_and_qml_module( /// In addition to autogenerating and building QObject C++ subclasses, manually written QObject /// subclasses can be parsed by moc and built using [CxxQtBuilder::qobject_header]. #[derive(Default)] -pub struct CxxQtBuilder { +pub struct CxxQtBuilder<'a, A, B> +where + A: AsRef, + B: AsRef, +{ rust_sources: Vec, qobject_headers: Vec, qrc_files: Vec, qt_modules: HashSet, - qml_modules: Vec, + qml_modules: Vec>, cc_builder: cc::Build, } -impl CxxQtBuilder { +impl<'a, A, B> CxxQtBuilder<'a, A, B> +where + A: AsRef + PartialEq, + B: AsRef, +{ /// Create a new builder pub fn new() -> Self { let mut qt_modules = HashSet::new(); @@ -322,18 +320,18 @@ impl CxxQtBuilder { /// Specify rust file paths to parse through the cxx-qt marco /// Relative paths are treated as relative to the path of your crate's Cargo.toml file - pub fn file(mut self, rust_source: impl AsRef) -> Self { - let rust_source = rust_source.as_ref().to_path_buf(); + pub fn file(mut self, rust_source: A) -> Self { for qml_module in &self.qml_modules { if qml_module.rust_files.contains(&rust_source) { panic_duplicate_file_and_qml_module( &rust_source, - &qml_module.uri, + qml_module.uri, qml_module.version_major, qml_module.version_minor, ); } } + let rust_source = rust_source.as_ref().to_path_buf(); println!("cargo:rerun-if-changed={}", rust_source.display()); self.rust_sources.push(rust_source); self @@ -343,7 +341,7 @@ impl CxxQtBuilder { /// The generated file needs to be `#include`d in another .cpp file. For example: /// ```no_run /// # use cxx_qt_build::CxxQtBuilder; - /// CxxQtBuilder::new() + /// CxxQtBuilder::<&str, &str>::new() /// .file("src/cxxqt_module.rs") /// .qrc("src/my_resources.qrc") /// .cc_builder(|cc| { @@ -375,28 +373,18 @@ impl CxxQtBuilder { } /// Register a QML module at build time - pub fn qml_module( - mut self, - uri: &str, - version_major: usize, - version_minor: usize, - rust_files: &[impl AsRef], - ) -> Self { - let rust_files: Vec = rust_files - .iter() - .map(|p| p.as_ref().to_path_buf()) - .collect(); - for path in &rust_files { - if self.rust_sources.contains(path) { - panic_duplicate_file_and_qml_module(path, uri, version_major, version_minor); + pub fn qml_module(mut self, qml_module: QmlModule<'a, A, B>) -> CxxQtBuilder<'a, A, B> { + for path in qml_module.rust_files { + if self.rust_sources.contains(&path.as_ref().to_path_buf()) { + panic_duplicate_file_and_qml_module( + path, + qml_module.uri, + qml_module.version_major, + qml_module.version_minor, + ); } } - self.qml_modules.push(QmlModule { - uri: uri.to_owned(), - version_major, - version_minor, - rust_files, - }); + self.qml_modules.push(qml_module); self } @@ -417,7 +405,7 @@ impl CxxQtBuilder { /// ```no_run /// # use cxx_qt_build::CxxQtBuilder; /// - /// CxxQtBuilder::new() + /// CxxQtBuilder::<&str, &str>::new() /// .file("src/lib.rs") /// .cc_builder(|cc| { /// cc.include("include"); @@ -532,32 +520,31 @@ impl CxxQtBuilder { let mut cc_builder_whole_archive_files_added = false; + let lib_name = "cxx-qt-generated"; + // Bridges for QML modules are handled separately because // the metatypes_json generated by moc needs to be passed to qmltyperegistrar for qml_module in self.qml_modules { let mut qml_metatypes_json = Vec::new(); - for files in generate_cxxqt_cpp_files(&qml_module.rust_files, &generated_header_dir) { + for files in generate_cxxqt_cpp_files(qml_module.rust_files, &generated_header_dir) { self.cc_builder.file(files.plain_cpp); if let (Some(qobject), Some(qobject_header)) = (files.qobject, files.qobject_header) { self.cc_builder.file(&qobject); - let moc_products = qtbuild.moc(qobject_header, Some(&qml_module.uri)); + let moc_products = qtbuild.moc(qobject_header, Some(qml_module.uri)); self.cc_builder.file(moc_products.cpp); qml_metatypes_json.push(moc_products.metatypes_json); } } - let qml_type_registration_files = qtbuild.register_qml_types( - &qml_metatypes_json, - qml_module.version_major, - qml_module.version_minor, - &qml_module.uri, - ); + let qml_type_registration_files = + qtbuild.register_qml_module(&qml_metatypes_json, &qml_module, lib_name); self.cc_builder .file(qml_type_registration_files.qmltyperegistrar); self.cc_builder.file(qml_type_registration_files.plugin); cc_builder_whole_archive.file(qml_type_registration_files.plugin_init); + cc_builder_whole_archive.file(qml_type_registration_files.qrc); self.cc_builder.define("QT_STATICPLUGIN", None); cc_builder_whole_archive_files_added = true; } @@ -599,6 +586,6 @@ impl CxxQtBuilder { if cc_builder_whole_archive_files_added { cc_builder_whole_archive.compile("qt-static-initializers"); } - self.cc_builder.compile("cxx-qt-gen"); + self.cc_builder.compile(lib_name); } } diff --git a/crates/qt-build-utils/src/lib.rs b/crates/qt-build-utils/src/lib.rs index 4b75ca2f8..52fc99209 100644 --- a/crates/qt-build-utils/src/lib.rs +++ b/crates/qt-build-utils/src/lib.rs @@ -114,8 +114,53 @@ pub struct MocProducts { pub metatypes_json: PathBuf, } -/// Paths to C++ files generated by [QtBuild::register_qml_types] -pub struct QmlTypeRegistrationFiles { +/// Metadata for registering a QML module with [QtBuild::register_qml_module] +pub struct QmlModule<'a, A, B> +where + A: AsRef, + // Use a separate generic to allow using different types that impl AsRef + B: AsRef, +{ + /// The URI of the QML module + pub uri: &'a str, + /// The minor version of the QML module + pub version_minor: usize, + /// The major version of the QML module + pub version_major: usize, + /// The .rs files with `#[qml_element]` attribute(s) + pub rust_files: &'a [A], + /// .qml files included in the module + pub qml_files: &'a [B], + /// Other QRC resources (such as images) included in the module + // + // Reuse the `A` generic from rust_files to allow the compiler to infer the + // type when constructing the struct with Default::default. Using a separate + // generic for this field would be more flexible, but it would require users + // to explicitly specify the type even for an empty slice (like `&[] as &[&str; 0]`) + // and an empty slice is likely desired in most cases; most users probably don't + // care about this field. + pub qrc_files: &'a [A], +} + +impl<'a, A, B> Default for QmlModule<'a, A, B> +where + A: AsRef, + B: AsRef, +{ + fn default() -> Self { + QmlModule { + uri: "com.example.cxx_qt_module", + version_major: 1, + version_minor: 0, + rust_files: &[], + qml_files: &[], + qrc_files: &[], + } + } +} + +/// Paths to C++ files generated by [QtBuild::register_qml_module] +pub struct QmlModuleRegistrationFiles { /// File generated by qmltyperegistrar CLI tool pub qmltyperegistrar: PathBuf, /// File with generated [QQmlEngineExtensionPlugin](https://doc.qt.io/qt-6/qqmlengineextensionplugin.html) that calls the function generated by qmltyperegistrar @@ -124,6 +169,8 @@ pub struct QmlTypeRegistrationFiles { /// The compiled static library must be linked with [+whole-archive](https://doc.rust-lang.org/rustc/command-line-arguments.html#linking-modifiers-whole-archive) /// or the linker will discard the generated static variables because they are not referenced from `main`. pub plugin_init: PathBuf, + /// File generated by rcc for the QML plugin. Must be linked with `+whole-archive`. + pub qrc: PathBuf, } /// Helper for build.rs scripts using Qt @@ -519,7 +566,7 @@ impl QtBuild { /// Run moc on a C++ header file and save the output into [cargo's OUT_DIR](https://doc.rust-lang.org/cargo/reference/environment-variables.html). /// The return value contains the path to the generated C++ file, which can then be passed to [cc::Build::files](https://docs.rs/cc/latest/cc/struct.Build.html#method.file), - /// as well as the path to the generated metatypes.json file, which can be passed to [register_qml_types](Self::register_qml_types). + /// as well as the path to the generated metatypes.json file, which can be passed to [register_qml_module](Self::register_qml_module). /// /// * uri - Should be passed if the input_file is part of a QML module pub fn moc(&mut self, input_file: impl AsRef, uri: Option<&str>) -> MocProducts { @@ -570,14 +617,17 @@ impl QtBuild { } } - /// Generate C++ files to automatically register a QML element at build time using the JSON output from [moc](Self::moc) - pub fn register_qml_types( + /// Generate C++ files to automatically register a QML module at build time using the JSON output from [moc](Self::moc). + pub fn register_qml_module( &mut self, metatypes_json: &[impl AsRef], - major_version: usize, - minor_version: usize, - import_name: &str, - ) -> QmlTypeRegistrationFiles { + qml_module: &QmlModule, + library_name: &str, + ) -> QmlModuleRegistrationFiles + where + A: AsRef, + B: AsRef, + { if self.qmltyperegistrar_executable.is_none() { self.qmltyperegistrar_executable = Some( self.get_qt_tool("qmltyperegistrar") @@ -585,20 +635,77 @@ impl QtBuild { ); } + let uri = &qml_module.uri; + let qml_uri_dirs = uri.replace('.', "/"); + let out_dir = env::var("OUT_DIR").unwrap(); + let qml_module_dir = format!("{out_dir}/qml_modules/{qml_uri_dirs}"); + std::fs::create_dir_all(&qml_module_dir).expect("Could not create QML module directory"); + + let qml_uri_cpp_symbol_safe = uri.replace('.', "_"); + let typeinfo_path = format!("{qml_uri_cpp_symbol_safe}.qmltypes"); + let plugin_class_name = format!("{qml_uri_cpp_symbol_safe}_plugin"); + + let mut qmldir = + File::create(format!("{qml_module_dir}/qmldir")).expect("Could not create qmldir file"); + write!( + qmldir, + "module {uri} +optional plugin {library_name} +classname {plugin_class_name} +typeinfo {typeinfo_path} +prefer :/qt/qml/{qml_uri_dirs}/ +" + ) + .expect("Could not write qmldir file"); + + fn qrc_file_line(file_path: &impl AsRef) -> String { + let path_display = file_path.as_ref().display(); + format!( + " {}\n", + path_display, + std::fs::canonicalize(file_path) + .unwrap_or_else(|_| panic!("Could not canonicalize path {}", path_display)) + .display() + ) + } + + let mut qml_files_qrc = String::new(); + for file_path in qml_module.qml_files { + qml_files_qrc.push_str(&qrc_file_line(file_path)); + } + for file_path in qml_module.qrc_files { + qml_files_qrc.push_str(&qrc_file_line(file_path)); + } + + let qrc_path = format!("{qml_module_dir}/qml_module_resources.qrc"); + let mut qrc = File::create(&qrc_path).expect("Could not create qrc file"); + write!( + qrc, + r#" + + {qml_module_dir} + + +{qml_files_qrc} + {qml_module_dir}/qmldir + + +"# + ) + .expect("Could note write qrc file"); + let qrc_output = self.qrc(&qrc_path); - let qml_uri_cpp_symbol_safe = import_name.replace('.', "_"); let output_path = PathBuf::from(&format!( "{out_dir}/{qml_uri_cpp_symbol_safe}_qmltyperegistration.cpp" )); - let mut args = vec![ "--major-version".to_string(), - major_version.to_string(), + qml_module.version_major.to_string(), "--minor-version".to_string(), - minor_version.to_string(), + qml_module.version_minor.to_string(), "--import-name".to_string(), - import_name.to_string(), + uri.to_string(), "-o".to_string(), output_path.to_string_lossy().to_string(), ]; @@ -611,16 +718,15 @@ impl QtBuild { let cmd = Command::new(self.qmltyperegistrar_executable.as_ref().unwrap()) .args(args) .output() - .unwrap_or_else(|_| panic!("qmltyperegistrar failed for {import_name}")); + .unwrap_or_else(|_| panic!("qmltyperegistrar failed for {uri}")); if !cmd.status.success() { panic!( - "qmltyperegistrar failed for {import_name}:\n{}", + "qmltyperegistrar failed for {uri}:\n{}", String::from_utf8_lossy(&cmd.stderr) ); } - let plugin_class_name = format!("{qml_uri_cpp_symbol_safe}_plugin"); // This function is generated by qmltyperegistrar let register_types_function = format!("qml_register_types_{qml_uri_cpp_symbol_safe}"); @@ -651,7 +757,7 @@ public: "# ) .unwrap(); - self.moc(&qml_plugin_cpp_path, Some(import_name)); + self.moc(&qml_plugin_cpp_path, Some(uri)); let qml_plugin_init_path = PathBuf::from(format!("{out_dir}/{plugin_class_name}_init.cpp")); let mut qml_plugin_init = File::create(&qml_plugin_init_path).unwrap(); @@ -664,10 +770,11 @@ Q_IMPORT_PLUGIN({plugin_class_name}); ) .unwrap(); - QmlTypeRegistrationFiles { + QmlModuleRegistrationFiles { qmltyperegistrar: output_path, plugin: qml_plugin_cpp_path, plugin_init: qml_plugin_init_path, + qrc: qrc_output, } } diff --git a/examples/cargo_without_cmake/build.rs b/examples/cargo_without_cmake/build.rs index 178a6be9d..79a91b6ad 100644 --- a/examples/cargo_without_cmake/build.rs +++ b/examples/cargo_without_cmake/build.rs @@ -4,7 +4,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // ANCHOR: book_cargo_executable_build_rs -use cxx_qt_build::CxxQtBuilder; +use cxx_qt_build::{CxxQtBuilder, QmlModule}; fn main() { CxxQtBuilder::new() @@ -14,10 +14,12 @@ fn main() { // - Qt Qml is linked by enabling the qt_qml Cargo feature (default). // - Qt Qml requires linking Qt Network on macOS .qt_module("Network") - .qml_module("com.kdab.cxx_qt.demo", 1, 0, &["src/cxxqt_object.rs"]) - // Generate C++ code from the .qrc file with the rcc tool - // https://doc.qt.io/qt-6/resources.html - .qrc("qml/qml.qrc") + .qml_module(QmlModule { + uri: "com.kdab.cxx_qt.demo", + rust_files: &["src/cxxqt_object.rs"], + qml_files: &["qml/main.qml"], + ..Default::default() + }) .build(); } // ANCHOR_END: book_cargo_executable_build_rs diff --git a/examples/cargo_without_cmake/src/main.rs b/examples/cargo_without_cmake/src/main.rs index 8e487f78e..0c7ebd1ba 100644 --- a/examples/cargo_without_cmake/src/main.rs +++ b/examples/cargo_without_cmake/src/main.rs @@ -25,7 +25,7 @@ fn main() { // Load the QML path into the engine if let Some(engine) = engine.as_mut() { - engine.load(&QUrl::from("qrc:/main.qml")); + engine.load(&QUrl::from("qrc:/qt/qml/com/kdab/cxx_qt/demo/qml/main.qml")); } // Start the app diff --git a/examples/demo_threading/CMakeLists.txt b/examples/demo_threading/CMakeLists.txt index 70c7d1aec..138ea4e02 100644 --- a/examples/demo_threading/CMakeLists.txt +++ b/examples/demo_threading/CMakeLists.txt @@ -65,7 +65,6 @@ add_executable(${APP_NAME} cpp/helpers/sensor.h cpp/helpers/sensor.cpp images/images.qrc - qml/qml.qrc ${QML_COMPAT_RESOURCES} ) target_link_libraries(${APP_NAME} PRIVATE ${APP_NAME}_lib) diff --git a/examples/demo_threading/cpp/main.cpp b/examples/demo_threading/cpp/main.cpp index 9c9478b14..ff1ee837c 100644 --- a/examples/demo_threading/cpp/main.cpp +++ b/examples/demo_threading/cpp/main.cpp @@ -17,7 +17,8 @@ main(int argc, char* argv[]) QQmlApplicationEngine engine; - const QUrl url(QStringLiteral("qrc:/MainWindow.qml")); + const QUrl url( + QStringLiteral("qrc:/qt/qml/com/kdab/energy/qml/MainWindow.qml")); QObject::connect( &engine, &QQmlApplicationEngine::objectCreated, diff --git a/examples/demo_threading/qml/Button.qml b/examples/demo_threading/qml/Button.qml index 313dbfc52..dd3cbcc66 100644 --- a/examples/demo_threading/qml/Button.qml +++ b/examples/demo_threading/qml/Button.qml @@ -19,7 +19,7 @@ Item { Image { id: inner anchors.centerIn: parent - source: "./images/activeInner.png" + source: "qrc:/images/activeInner.png" opacity: activeF || pressed ? 1 : 0 Behavior on opacity { NumberAnimation { easing.type: Easing.InOutQuad } } } @@ -27,7 +27,7 @@ Item { Image { id: innerInactive anchors.centerIn: parent - source: "./images/inactiveInner.png" + source: "qrc:/images/inactiveInner.png" opacity: 1 - inner.opacity } @@ -41,7 +41,7 @@ Item { Image { id: outer - source: "./images/activeOuter.png" + source: "qrc:/images/activeOuter.png" anchors.centerIn: parent opacity: activeF || pressed ? 1 : 0 Behavior on opacity { NumberAnimation { easing.type: Easing.InOutQuad } } @@ -49,7 +49,7 @@ Item { Image { id: outerInactive - source: "./images/inactiveOuter.png" + source: "qrc:/images/inactiveOuter.png" anchors.centerIn: parent opacity: 1 - outer.opacity } diff --git a/examples/demo_threading/qml/MainWindow.qml b/examples/demo_threading/qml/MainWindow.qml index e7a02b3d1..ab460538a 100644 --- a/examples/demo_threading/qml/MainWindow.qml +++ b/examples/demo_threading/qml/MainWindow.qml @@ -30,21 +30,21 @@ Window { Image { id: background - source: "./images/bg.png" + source: "qrc:/images/bg.png" } Image { id: ocean x: Math.max(1008 - ((slideHouse.contentX - 600) / 9.2), 1008) y: -1 - source: "./images/ocean.png" + source: "qrc:/images/ocean.png" } Image { id: beach1 x: 955 - ((slideHouse.contentX - 600) / 7.9) y: -1 - source: "./images/beach1.png" + source: "qrc:/images/beach1.png" width: sourceSize.width * ((slideHouse.contentX / 6500) + 0.9) smooth: true } @@ -53,7 +53,7 @@ Window { id: beach2 x: 890 - (slideHouse.contentX - 600) / 6.9 y: -1 - source: "./images/beach2.png" + source: "qrc:/images/beach2.png" width: sourceSize.width * ((slideHouse.contentX / 5000) + 0.8) smooth: true } @@ -62,7 +62,7 @@ Window { id: level0 x: Math.min(0, -168 - (slideHouse.contentX - 600) / 5.9) y: -128 - source: "./images/level0.png" + source: "qrc:/images/level0.png" opacity: currentLevel=== 0 ? 1 : 0 Behavior on opacity { NumberAnimation { duration: 900; easing.type: Easing.InOutQuad } } @@ -80,7 +80,7 @@ Window { id: level0i x: level0.x y: 0 - source: "./images/level0i.png" + source: "qrc:/images/level0i.png" opacity: 1 - Math.pow(level0.opacity, 2) } Image { @@ -88,7 +88,7 @@ Window { property int xi: currentLevel > 0 ? 0 : -200 property real opi: currentLevel > 1 ? 0 : 1 x: level0.x + 86 + xi - source: "./images/level1.png" + source: "qrc:/images/level1.png" y: 79 opacity: (1 + (xi / 200)) * opi @@ -120,7 +120,7 @@ Window { Image { id: level1i x: level1.x - source: "./images/level1i.png" + source: "qrc:/images/level1i.png" y: 79 opacity: currentLevel === 0 ? 0 : (1 - Math.pow(level1.opacity, 2)) } @@ -129,7 +129,7 @@ Window { property int xi: currentLevel > 1 ? 0 : -200 property real opi: currentLevel > 2 ? 0 : 1 x: level0.x + 86 + xi - source: "./images/level2.png" + source: "qrc:/images/level2.png" y: 79 opacity: (1 + xi / 200) * opi @@ -169,7 +169,7 @@ Window { Image { id: level2i x: level1.x - source: "./images/level2i.png" + source: "qrc:/images/level2i.png" y: 79 opacity: currentLevel < 2 ? 0 : (1 - Math.pow(level2.opacity, 2)) } @@ -178,7 +178,7 @@ Window { id: level3 property int xi: currentLevel > 2 ? 0: -200 x: level0.x + 86 + xi - source: "./images/level3.png" + source: "qrc:/images/level3.png" y: 79 opacity: (1 + (xi / 200)) @@ -195,7 +195,7 @@ Window { } Image { id: sideShadow - source: "./images/sideshadow.png" + source: "qrc:/images/sideshadow.png" } Flickable { @@ -297,13 +297,13 @@ Window { Image { fillMode: Image.PreserveAspectFit - source: "./images/qt-logo.png" + source: "qrc:/images/qt-logo.png" width: parent.width } Image { fillMode: Image.PreserveAspectFit - source: "./images/rust-logo-white.png" + source: "qrc:/images/rust-logo-white.png" width: parent.width } } @@ -361,7 +361,7 @@ Window { Image { id: wireless - source: "./images/iconwirless.png" + source: "qrc:/images/iconwirless.png" x: 19 y: 22 } @@ -380,7 +380,7 @@ Window { Image { id: sensors - source: "./images/iconSensors.png" + source: "qrc:/images/iconSensors.png" anchors.left: powerusageT.right anchors.leftMargin: 16 y: 22 @@ -407,7 +407,7 @@ Window { Image { id: rLogo - source: "./images/RLogo.png" + source: "qrc:/images/RLogo.png" anchors.centerIn: buttoninfo opacity: buttoninfo.pressed ? 1 : 0.7 scale: 0.9 diff --git a/examples/demo_threading/qml/Panel.qml b/examples/demo_threading/qml/Panel.qml index d4daee52d..2f9ba40cd 100644 --- a/examples/demo_threading/qml/Panel.qml +++ b/examples/demo_threading/qml/Panel.qml @@ -24,7 +24,7 @@ Item { BorderImage { id: panel - source: "./images/panel.png" + source: "qrc:/images/panel.png" width: 900 clip: true height: parent.height - 30 @@ -54,7 +54,7 @@ Item { Image { id: kdabL - source: "./images/kdabLogo.png" + source: "qrc:/images/kdabLogo.png" x: (-panel.x / 1.5) + 60 y: 120 } @@ -78,7 +78,7 @@ Item { Image { id: rust - source: "./images/RLogolarge.png" + source: "qrc:/images/RLogolarge.png" anchors.horizontalCenter: kdabL.horizontalCenter anchors.top: kdabL.bottom anchors.topMargin: 100 diff --git a/examples/demo_threading/qml/SensorUI.qml b/examples/demo_threading/qml/SensorUI.qml index f8978eb6e..99b317aaa 100644 --- a/examples/demo_threading/qml/SensorUI.qml +++ b/examples/demo_threading/qml/SensorUI.qml @@ -36,7 +36,7 @@ Item { } Image { - source: "./images/sensor.png" + source: "qrc:/images/sensor.png" anchors.verticalCenter: parent.verticalCenter x:-6 } @@ -48,7 +48,7 @@ Item { anchors.margins: -15 Image { - source: "./images/sensorefect.png" + source: "qrc:/images/sensorefect.png" anchors.verticalCenter: parent.verticalCenter x:15 } diff --git a/examples/demo_threading/qml/qml.qrc b/examples/demo_threading/qml/qml.qrc deleted file mode 100644 index 152eeea4e..000000000 --- a/examples/demo_threading/qml/qml.qrc +++ /dev/null @@ -1,9 +0,0 @@ - - - MainWindow.qml - Button.qml - SideText.qml - SensorUI.qml - Panel.qml - - diff --git a/examples/demo_threading/qml/qml.qrc.license b/examples/demo_threading/qml/qml.qrc.license deleted file mode 100644 index 0e9731c73..000000000 --- a/examples/demo_threading/qml/qml.qrc.license +++ /dev/null @@ -1,5 +0,0 @@ -SPDX-FileCopyrightText: 2021, 2022 Klarälvdalens Datakonsult AB, a KDAB Group company -SPDX-FileContributor: Andrew Hayzen -SPDX-FileContributor: Nuno Pinheiro - -SPDX-License-Identifier: MIT OR Apache-2.0 diff --git a/examples/demo_threading/rust/build.rs b/examples/demo_threading/rust/build.rs index e99d9a387..7a23cd1f7 100644 --- a/examples/demo_threading/rust/build.rs +++ b/examples/demo_threading/rust/build.rs @@ -2,10 +2,49 @@ // SPDX-FileContributor: Andrew Hayzen // // SPDX-License-Identifier: MIT OR Apache-2.0 -use cxx_qt_build::CxxQtBuilder; +use cxx_qt_build::{CxxQtBuilder, QmlModule}; fn main() { CxxQtBuilder::new() - .qml_module("com.kdab.energy", 1, 0, &["src/lib.rs"]) + .qml_module(QmlModule { + uri: "com.kdab.energy", + rust_files: &["src/lib.rs"], + qml_files: &[ + "../qml/Button.qml", + "../qml/MainWindow.qml", + "../qml/Panel.qml", + "../qml/SensorUI.qml", + "../qml/SideText.qml", + ], + qrc_files: &[ + "../images/activeInner.png", + "../images/activeOuter.png", + "../images/beach1.png", + "../images/beach2.png", + "../images/bg.png", + "../images/iconSensors.png", + "../images/iconwirless.png", + "../images/inactiveInner.png", + "../images/inactiveOuter.png", + "../images/kdabLogo.png", + "../images/level0.png", + "../images/level0i.png", + "../images/level1.png", + "../images/level1i.png", + "../images/level2.png", + "../images/level2i.png", + "../images/level3.png", + "../images/ocean.png", + "../images/panel.png", + "../images/qt-logo.png", + "../images/RLogo.png", + "../images/RLogolarge.png", + "../images/rust-logo-white.png", + "../images/sensor.png", + "../images/sensorefect.png", + "../images/sideshadow.png", + ], + ..Default::default() + }) .build(); } diff --git a/examples/qml_features/CMakeLists.txt b/examples/qml_features/CMakeLists.txt index ef2bb400b..64b1ae3e9 100644 --- a/examples/qml_features/CMakeLists.txt +++ b/examples/qml_features/CMakeLists.txt @@ -54,7 +54,6 @@ target_link_libraries(${APP_NAME}_lib INTERFACE add_executable(${APP_NAME} cpp/main.cpp - qml/qml.qrc ) target_include_directories(${APP_NAME} PRIVATE cpp) diff --git a/examples/qml_features/cpp/main.cpp b/examples/qml_features/cpp/main.cpp index fb69218fc..0e5827993 100644 --- a/examples/qml_features/cpp/main.cpp +++ b/examples/qml_features/cpp/main.cpp @@ -17,7 +17,8 @@ main(int argc, char* argv[]) QQmlApplicationEngine engine; - const QUrl url(QStringLiteral("qrc:/main.qml")); + const QUrl url( + QStringLiteral("qrc:/qt/qml/com/kdab/cxx_qt/demo/qml/main.qml")); QObject::connect( &engine, &QQmlApplicationEngine::objectCreated, diff --git a/examples/qml_features/qml/main.qml b/examples/qml_features/qml/main.qml index cc0392999..896f17e6a 100644 --- a/examples/qml_features/qml/main.qml +++ b/examples/qml_features/qml/main.qml @@ -70,51 +70,51 @@ ApplicationWindow { model: ListModel { ListElement { name: "Properties" - source: "qrc:/pages/PropertiesPage.qml" + source: "pages/PropertiesPage.qml" } ListElement { name: "Invokables" - source: "qrc:/pages/InvokablesPage.qml" + source: "pages/InvokablesPage.qml" } ListElement { name: "Signals" - source: "qrc:/pages/SignalsPage.qml" + source: "pages/SignalsPage.qml" } ListElement { name: "Threading" - source: "qrc:/pages/ThreadingPage.qml" + source: "pages/ThreadingPage.qml" } ListElement { name: "Custom Base Class" - source: "qrc:/pages/CustomBaseClassPage.qml" + source: "pages/CustomBaseClassPage.qml" } ListElement { name: "Serialisation" - source: "qrc:/pages/SerialisationPage.qml" + source: "pages/SerialisationPage.qml" } ListElement { name: "Types" - source: "qrc:/pages/TypesPage.qml" + source: "pages/TypesPage.qml" } ListElement { name: "Containers" - source: "qrc:/pages/ContainersPage.qml" + source: "pages/ContainersPage.qml" } ListElement { name: "Multiple QObjects" - source: "qrc:/pages/MultipleQObjectsPage.qml" + source: "pages/MultipleQObjectsPage.qml" } ListElement { name: "Nested QObjects" - source: "qrc:/pages/NestedQObjectsPage.qml" + source: "pages/NestedQObjectsPage.qml" } ListElement { name: "Singleton" - source: "qrc:/pages/SingletonPage.qml" + source: "pages/SingletonPage.qml" } ListElement { name: "Custom Parent Class" - source: "qrc:/pages/CustomParentClassPage.qml" + source: "pages/CustomParentClassPage.qml" } } } diff --git a/examples/qml_features/qml/qml.qrc b/examples/qml_features/qml/qml.qrc deleted file mode 100644 index a1fd3253d..000000000 --- a/examples/qml_features/qml/qml.qrc +++ /dev/null @@ -1,25 +0,0 @@ - - - - - main.qml - pages/ContainersPage.qml - pages/CustomBaseClassPage.qml - pages/CustomParentClassPage.qml - pages/InvokablesPage.qml - pages/MultipleQObjectsPage.qml - pages/NestedQObjectsPage.qml - pages/PropertiesPage.qml - pages/SerialisationPage.qml - pages/SignalsPage.qml - pages/SingletonPage.qml - pages/ThreadingPage.qml - pages/TypesPage.qml - - diff --git a/examples/qml_features/rust/build.rs b/examples/qml_features/rust/build.rs index 15683b8ea..11e119fd8 100644 --- a/examples/qml_features/rust/build.rs +++ b/examples/qml_features/rust/build.rs @@ -5,15 +5,13 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // ANCHOR: book_build_rs -use cxx_qt_build::CxxQtBuilder; +use cxx_qt_build::{CxxQtBuilder, QmlModule}; fn main() { CxxQtBuilder::new() - .qml_module( - "com.kdab.cxx_qt.demo", - 1, - 0, - &[ + .qml_module(QmlModule { + uri: "com.kdab.cxx_qt.demo", + rust_files: &[ "src/containers.rs", "src/custom_base_class.rs", "src/custom_parent_class.rs", @@ -28,7 +26,23 @@ fn main() { "src/types.rs", "src/uncreatable.rs", ], - ) + qml_files: &[ + "../qml/main.qml", + "../qml/pages/ContainersPage.qml", + "../qml/pages/CustomBaseClassPage.qml", + "../qml/pages/CustomParentClassPage.qml", + "../qml/pages/InvokablesPage.qml", + "../qml/pages/MultipleQObjectsPage.qml", + "../qml/pages/NestedQObjectsPage.qml", + "../qml/pages/PropertiesPage.qml", + "../qml/pages/SerialisationPage.qml", + "../qml/pages/SignalsPage.qml", + "../qml/pages/SingletonPage.qml", + "../qml/pages/ThreadingPage.qml", + "../qml/pages/TypesPage.qml", + ], + ..Default::default() + }) // custom_object.cpp/h need to be handled here rather than CMakeLists.txt, // otherwise linking cargo tests fails because the symbols from those files are not found. .cc_builder(|cc| { diff --git a/examples/qml_minimal/CMakeLists.txt b/examples/qml_minimal/CMakeLists.txt index 3fc3adc37..04e3363a7 100644 --- a/examples/qml_minimal/CMakeLists.txt +++ b/examples/qml_minimal/CMakeLists.txt @@ -82,8 +82,8 @@ target_link_libraries(${APP_NAME}_lib INTERFACE # ANCHOR_END: book_cmake_use_corrosion # ANCHOR: book_cmake_executable -# Define the executable with the C++ source and Qt resource files -add_executable(${APP_NAME} cpp/main.cpp qml/qml.qrc) +# Define the executable with the C++ source +add_executable(${APP_NAME} cpp/main.cpp) # Link to the Rust library target_link_libraries(${APP_NAME} PRIVATE ${APP_NAME}_lib) diff --git a/examples/qml_minimal/cpp/main.cpp b/examples/qml_minimal/cpp/main.cpp index 124b68120..c6c53fb61 100644 --- a/examples/qml_minimal/cpp/main.cpp +++ b/examples/qml_minimal/cpp/main.cpp @@ -18,7 +18,8 @@ main(int argc, char* argv[]) QQmlApplicationEngine engine; // ANCHOR: book_qml_url - const QUrl url(QStringLiteral("qrc:/main.qml")); + const QUrl url( + QStringLiteral("qrc:/qt/qml/com/kdab/cxx_qt/demo/qml/main.qml")); // ANCHOR_END: book_qml_url QObject::connect( &engine, diff --git a/examples/qml_minimal/qml/qml.qrc b/examples/qml_minimal/qml/qml.qrc deleted file mode 100644 index a6857fb45..000000000 --- a/examples/qml_minimal/qml/qml.qrc +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - main.qml - - - diff --git a/examples/qml_minimal/rust/build.rs b/examples/qml_minimal/rust/build.rs index 7130c28f9..846a0c698 100644 --- a/examples/qml_minimal/rust/build.rs +++ b/examples/qml_minimal/rust/build.rs @@ -5,11 +5,16 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // ANCHOR: book_build_rs -use cxx_qt_build::CxxQtBuilder; +use cxx_qt_build::{CxxQtBuilder, QmlModule}; fn main() { CxxQtBuilder::new() - .qml_module("com.kdab.cxx_qt.demo", 1, 0, &["src/cxxqt_object.rs"]) + .qml_module(QmlModule { + uri: "com.kdab.cxx_qt.demo", + rust_files: &["src/cxxqt_object.rs"], + qml_files: &["../qml/main.qml"], + ..Default::default() + }) .build(); } // ANCHOR_END: book_build_rs diff --git a/tests/basic_cxx_only/rust/build.rs b/tests/basic_cxx_only/rust/build.rs index f202489a1..7ae1be27c 100644 --- a/tests/basic_cxx_only/rust/build.rs +++ b/tests/basic_cxx_only/rust/build.rs @@ -6,7 +6,7 @@ use cxx_qt_build::CxxQtBuilder; fn main() { - CxxQtBuilder::new() + CxxQtBuilder::<&str, &str>::new() .file("src/lib.rs") .cc_builder(|cc| { cc.include("../cpp"); diff --git a/tests/basic_cxx_qt/rust/build.rs b/tests/basic_cxx_qt/rust/build.rs index 74764048e..9f88d1cc5 100644 --- a/tests/basic_cxx_qt/rust/build.rs +++ b/tests/basic_cxx_qt/rust/build.rs @@ -6,7 +6,7 @@ use cxx_qt_build::CxxQtBuilder; fn main() { - CxxQtBuilder::new() + CxxQtBuilder::<&str, &str>::new() .file("src/empty.rs") .file("src/data.rs") .file("src/lib.rs") diff --git a/tests/qt_types_standalone/rust/build.rs b/tests/qt_types_standalone/rust/build.rs index aee8fdcc4..19474f979 100644 --- a/tests/qt_types_standalone/rust/build.rs +++ b/tests/qt_types_standalone/rust/build.rs @@ -6,7 +6,7 @@ use cxx_qt_build::CxxQtBuilder; fn main() { - CxxQtBuilder::new() + CxxQtBuilder::<&str, &str>::new() .file("src/qbytearray.rs") .file("src/qcolor.rs") .file("src/qcoreapplication.rs")