diff --git a/.github/workflows/github-cxx-qt-tests.yml b/.github/workflows/github-cxx-qt-tests.yml index 24f9b9cd1..b4baead5c 100644 --- a/.github/workflows/github-cxx-qt-tests.yml +++ b/.github/workflows/github-cxx-qt-tests.yml @@ -193,13 +193,8 @@ jobs: # Ensure clippy and rustfmt is installed, they should come from github runner # # Note we still need rustfmt for the cxx-qt-gen tests - # - # TODO: Remove the `rustup default 1.77` selection. - # This is a workaround for Github Actions, which cannot currently compile CXX-Qt with Rust 1.78. - # - # See: https://github.com/KDAB/cxx-qt/issues/958 - name: "Install Rust toolchain" - run: rustup default 1.77 && rustup component add clippy rustfmt + run: rustup component add clippy rustfmt - name: "Rust tools cache" uses: actions/cache@v4 diff --git a/Cargo.toml b/Cargo.toml index 7197a5984..98c90e4c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ cxx = "1.0.95" cxx-build = { version = "1.0.95", features = [ "parallel" ] } cxx-gen = "0.7.121" convert_case = "0.6" +indoc = "2.0" proc-macro2 = "1.0" syn = { version = "2.0", features = ["extra-traits", "full"] } quote = "1.0" diff --git a/crates/cxx-qt-build/Cargo.toml b/crates/cxx-qt-build/Cargo.toml index b676e8280..b2e488ce8 100644 --- a/crates/cxx-qt-build/Cargo.toml +++ b/crates/cxx-qt-build/Cargo.toml @@ -17,6 +17,7 @@ cc.workspace = true cxx-gen.workspace = true cxx-qt.workspace = true cxx-qt-gen.workspace = true +indoc.workspace = true proc-macro2.workspace = true quote.workspace = true qt-build-utils.workspace = true diff --git a/crates/cxx-qt-build/src/init.rs b/crates/cxx-qt-build/src/init.rs new file mode 100644 index 000000000..070127a09 --- /dev/null +++ b/crates/cxx-qt-build/src/init.rs @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company +// SPDX-FileContributor: Andrew Hayzen +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +/// Initialiser definitions for the builder to inject +pub struct CxxQtBuilderInit { + pub(crate) method_name: String, + pub(crate) source: String, +} + +impl CxxQtBuilderInit { + /// Create an initialisers with the given method name and source + pub fn new(method_name: &str, source: &str) -> Self { + Self { + source: source.to_owned(), + method_name: method_name.to_owned(), + } + } +} diff --git a/crates/cxx-qt-build/src/lib.rs b/crates/cxx-qt-build/src/lib.rs index ae7c28af1..45fa5bf3b 100644 --- a/crates/cxx-qt-build/src/lib.rs +++ b/crates/cxx-qt-build/src/lib.rs @@ -16,6 +16,9 @@ mod cfg_evaluator; mod diagnostics; use diagnostics::{Diagnostic, GeneratedError}; +mod init; +pub use init::CxxQtBuilderInit; + mod opts; pub use opts::CxxQtBuildersOpts; pub use opts::QObjectHeaderOpts; @@ -24,6 +27,7 @@ mod qml_modules; use qml_modules::OwningQmlModule; pub use qml_modules::QmlModule; +use indoc::formatdoc; pub use qt_build_utils::MocArguments; use quote::ToTokens; use std::{ @@ -314,6 +318,8 @@ pub struct CxxQtBuilder { qml_modules: Vec, cc_builder: cc::Build, extra_defines: HashSet, + inits: Vec, + generate_init: bool, } impl CxxQtBuilder { @@ -329,6 +335,8 @@ impl CxxQtBuilder { qml_modules: vec![], cc_builder: cc::Build::new(), extra_defines: HashSet::new(), + inits: vec![], + generate_init: true, } } @@ -469,6 +477,18 @@ impl CxxQtBuilder { // Add any of the Qt modules self.qt_modules.extend(opts.qt_modules); + // Add any of the initialisers + self.inits.extend(opts.inits); + + self + } + + #[doc(hidden)] + /// Disable the init method generation + /// + /// This is used internally + pub fn disable_init_generation(mut self) -> Self { + self.generate_init = false; self } @@ -496,6 +516,139 @@ impl CxxQtBuilder { } } + fn build_inits_for_qrc(&mut self) { + // Build the resources + let init_resources = self + .qrc_files + .iter() + .filter_map(|qrc| qrc.file_stem().and_then(|file_stem| file_stem.to_str())) + .map(|file_stem| { + // The name is the base name of the file with characters that cannot + // be part of a C++ function replaced by underscores + // https://doc.qt.io/qt-6/qtresource-qtcore-proxy.html#Q_INIT_RESOURCE + let qrc_name = file_stem.replace('-', "_"); + // Note this cannot be inside a namespace + format!(" Q_INIT_RESOURCE({qrc_name};") + }) + .collect::>() + .join("\n"); + + if !init_resources.is_empty() { + self.inits.push(CxxQtBuilderInit::new( + "cxx_qt_init_resources", + &formatdoc! { + r#" + #include + + #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + #include + #else + #include + #endif + + void + cxx_qt_init_resources() + {{ + {init_resources} + }} + "# + }, + )); + } + } + + fn build_inits_for_qml_plugins(&mut self) { + // Build the QML files + let import_plugins = self + .qml_modules + .iter() + .map(|qml_module| { + // The name is the URI with dots replaced by underscores + // and add _plugin to match the CLASS_NAME set in QtBuild::register_qml_module + // + // https://doc.qt.io/qt-6/qqmlengineextensionplugin.html#Q_IMPORT_QML_PLUGIN + let plugin_name = qml_module.uri.replace('.', "_"); + format!(" Q_IMPORT_PLUGIN({plugin_name}_plugin);") + }) + .collect::>() + .join("\n"); + if !import_plugins.is_empty() { + self.inits.push(CxxQtBuilderInit::new( + "cxx_qt_import_plugins", + &formatdoc! { + r#" + #include + + void + cxx_qt_import_plugins() + {{ + {import_plugins} + }} + "# + }, + )); + } + } + + fn write_init_method(&self) -> String { + // Build any initialisers from builder opts + let mut call_methods = vec![]; + let mut sources = vec![]; + + for init in &self.inits { + call_methods.push(format!("{}();", init.method_name)); + sources.push(init.source.as_str()); + } + + let call_methods = call_methods.join("\n"); + let sources = sources.join("\n"); + + let header = formatdoc! { + r#" + #pragma once + + extern "C" void __cxx_qt_init(); + + namespace cxx_qt {{ + void + init(); + }} + "# + }; + let source = formatdoc! { + r#" + #include + + void + __cxx_qt_init() + {{ + cxx_qt::init(); + }} + + {sources} + + namespace cxx_qt {{ + void + init() + {{ + {call_methods} + }} + }} + "# + }; + + let header_root = header_root(); + std::fs::create_dir_all(format!("{header_root}/cxx-qt")) + .expect("Could not create cxx header directory"); + let h_path = format!("{header_root}/cxx-qt/init.h"); + let mut header_file = File::create(h_path).expect("Could not create init.h"); + write!(header_file, "{}", header).expect("Could not write init.h"); + let source_path = format!("{header_root}/cxx-qt/init.cpp"); + let mut source_file = File::create(source_path.clone()).expect("Could not create init.cpp"); + write!(source_file, "{}", source).expect("Could not write init.cpp"); + source_path + } + /// Generate and compile cxx-qt C++ code, as well as compile any additional files from /// [CxxQtBuilder::qobject_header] and [CxxQtBuilder::cc_builder]. pub fn build(mut self) { @@ -505,7 +658,7 @@ impl CxxQtBuilder { let header_root = header_root(); let generated_header_dir = format!("{header_root}/cxx-qt-gen"); - let mut qtbuild = qt_build_utils::QtBuild::new(self.qt_modules.into_iter().collect()) + let mut qtbuild = qt_build_utils::QtBuild::new(self.qt_modules.iter().cloned().collect()) .expect("Could not find Qt installation"); qtbuild.cargo_link_libraries(&mut self.cc_builder); @@ -623,6 +776,22 @@ impl CxxQtBuilder { } } + // Build inits which are generated + self.build_inits_for_qrc(); + self.build_inits_for_qml_plugins(); + if qtbuild.version().major < 6 { + // Inject Qt 5 compat type registers + self.inits.push(CxxQtBuilderInit::new( + "cxx_qt_qt5_compat", + include_str!("std_types_qt5.cpp"), + )); + } + + // Generate init method + if self.generate_init { + cc_builder_whole_archive.file(self.write_init_method()); + } + // Run moc on C++ headers with Q_OBJECT macro for QObjectHeaderOpts { path, @@ -633,8 +802,6 @@ impl CxxQtBuilder { self.cc_builder.file(moc_products.cpp); } - let mut cc_builder_whole_archive_files_added = false; - let lib_name = "cxx-qt-generated"; // Bridges for QML modules are handled separately because @@ -668,13 +835,11 @@ impl CxxQtBuilder { self.cc_builder .file(qml_module_registration_files.qmltyperegistrar); self.cc_builder.file(qml_module_registration_files.plugin); - cc_builder_whole_archive.file(qml_module_registration_files.plugin_init); cc_builder_whole_archive.file(qml_module_registration_files.rcc); for qmlcachegen_file in qml_module_registration_files.qmlcachegen { cc_builder_whole_archive.file(qmlcachegen_file); } self.cc_builder.define("QT_STATICPLUGIN", None); - cc_builder_whole_archive_files_added = true; // If any of the files inside the qml module change, then trigger a rerun for path in qml_module.qml_files.iter().chain( @@ -694,40 +859,10 @@ impl CxxQtBuilder { for qrc_inner_file in qtbuild.qrc_list(&qrc_file) { println!("cargo:rerun-if-changed={}", qrc_inner_file.display()); } - - cc_builder_whole_archive_files_added = true; - } - - // If we are using Qt 5 then write the std_types source - // This registers std numbers as a type for use in QML - // - // Note that we need this to be compiled into the whole_archive builder - // as they are stored in statics in the source. - // - // TODO: once +whole-archive and +bundle are allowed together in rlibs - // we should be able to move this into cxx-qt so that it's only built - // once rather than for every cxx-qt-build. When this happens also - // ensure that in a multi project that numbers work everywhere. - // - // Also then it should be possible to use CARGO_MANIFEST_DIR/src/std_types_qt5.cpp - // as path for cc::Build rather than copying the .cpp file - // - // https://github.com/rust-lang/rust/issues/108081 - // https://github.com/KDAB/cxx-qt/pull/598 - if qtbuild.version().major == 5 { - let std_types_contents = include_str!("std_types_qt5.cpp"); - let std_types_path = format!( - "{out_dir}/std_types_qt5.cpp", - out_dir = env::var("OUT_DIR").unwrap() - ); - let mut source = - File::create(&std_types_path).expect("Could not create std_types source"); - write!(source, "{std_types_contents}").expect("Could not write std_types source"); - cc_builder_whole_archive.file(&std_types_path); - cc_builder_whole_archive_files_added = true; } - if cc_builder_whole_archive_files_added { + // We normally have initialisers due to cxx_qt::init + if cc_builder_whole_archive.get_files().count() > 0 { cc_builder_whole_archive.compile("qt-static-initializers"); } diff --git a/crates/cxx-qt-build/src/opts.rs b/crates/cxx-qt-build/src/opts.rs index 4800dce47..42a5a27ff 100644 --- a/crates/cxx-qt-build/src/opts.rs +++ b/crates/cxx-qt-build/src/opts.rs @@ -8,7 +8,7 @@ use std::{ path::{Path, PathBuf}, }; -use crate::MocArguments; +use crate::{CxxQtBuilderInit, MocArguments}; /// Options for external crates to use #[derive(Default)] @@ -19,6 +19,8 @@ pub struct CxxQtBuildersOpts { pub(crate) headers: Vec<(String, String, String)>, /// Qt modules that are required pub(crate) qt_modules: HashSet, + /// Any initialisers for the builder to inject + pub(crate) inits: Vec, } impl CxxQtBuildersOpts { @@ -40,6 +42,12 @@ impl CxxQtBuildersOpts { self } + /// Add any [CxxQtBuilderInit] initialisers + pub fn init(mut self, init: CxxQtBuilderInit) -> Self { + self.inits.push(init); + self + } + /// Link additional [Qt modules](https://doc.qt.io/qt-6/qtmodules.html) for this opt. /// Specify their names without the `Qt` prefix, for example `"Widgets"`. pub fn qt_module(mut self, module: &str) -> Self { diff --git a/crates/cxx-qt-build/src/std_types_qt5.cpp b/crates/cxx-qt-build/src/std_types_qt5.cpp index 1075f3a54..335ff115a 100644 --- a/crates/cxx-qt-build/src/std_types_qt5.cpp +++ b/crates/cxx-qt-build/src/std_types_qt5.cpp @@ -7,36 +7,26 @@ #include -// For versions less than Qt 6 we need to manually register the std numerics #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) -#include - #include -namespace rust { -namespace cxxqtlib1 { +#include +#endif -// Ensure that std int types are registered -// so that they can be used with QML in Qt 5 +void +cxx_qt_qt5_compat() +{ +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + // This registers std numbers as a type for use in QML -static const int register_i8 = qRegisterMetaType<::std::int8_t>("::std::int8_t"); -static const int register_i16 = qRegisterMetaType<::std::int16_t>("::std::int16_t"); -static const int register_i32 = qRegisterMetaType<::std::int32_t>("::std::int32_t"); -static const int register_i64 = qRegisterMetaType<::std::int64_t>("::std::int64_t"); -static const int register_u8 = qRegisterMetaType<::std::uint8_t>("::std::uint8_t"); -static const int register_u16 = qRegisterMetaType<::std::uint16_t>("::std::uint16_t"); -static const int register_u32 = qRegisterMetaType<::std::uint32_t>("::std::uint32_t"); -static const int register_u64 = qRegisterMetaType<::std::uint64_t>("::std::uint64_t"); - -} -} #endif +} diff --git a/crates/cxx-qt-gen/Cargo.toml b/crates/cxx-qt-gen/Cargo.toml index d0b90eedf..53902a79e 100644 --- a/crates/cxx-qt-gen/Cargo.toml +++ b/crates/cxx-qt-gen/Cargo.toml @@ -19,7 +19,7 @@ syn.workspace = true quote.workspace = true convert_case.workspace = true clang-format = "0.3" -indoc = "2.0" +indoc.workspace = true [dev-dependencies] pretty_assertions = "1.2" diff --git a/crates/cxx-qt-lib-headers/include/core/init.cpp b/crates/cxx-qt-lib-headers/include/core/init.cpp new file mode 100644 index 000000000..aa8b98b0a --- /dev/null +++ b/crates/cxx-qt-lib-headers/include/core/init.cpp @@ -0,0 +1,111 @@ +// clang-format off +// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company +// clang-format on +// SPDX-FileContributor: Andrew Hayzen +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +#include +#include +#include +#include +#include + +void +cxx_qt_lib_core_init() +{ + // QHash + qRegisterMetaType<::QHash_i32_QByteArray>("QHash_i32_QByteArray"); + // Ensure that QHash (aka QVariantHash) is registered + // otherwise it cannot be used in QML + qRegisterMetaType<::QHash_QString_QVariant>("QHash_QString_QVariant"); + + // QList + qRegisterMetaType<::QList_bool>("QList_bool"); + qRegisterMetaType<::QList_f32>("QList_f32"); + qRegisterMetaType<::QList_f64>("QList_f64"); + qRegisterMetaType<::QList_i8>("QList_i8"); + qRegisterMetaType<::QList_i16>("QList_i16"); + qRegisterMetaType<::QList_i32>("QList_i32"); + qRegisterMetaType<::QList_i64>("QList_i64"); + qRegisterMetaType<::QList_QByteArray>("QList_QByteArray"); + qRegisterMetaType<::QList_QDate>("QList_QDate"); + qRegisterMetaType<::QList_QDateTime>("QList_QDateTime"); + qRegisterMetaType<::QList_QMargins>("QList_QMargins"); + qRegisterMetaType<::QList_QMarginsF>("QList_QMarginsF"); + qRegisterMetaType<::QList_QPersistentModelIndex>( + "QList_QPersistentModelIndex"); + qRegisterMetaType<::QList_QPoint>("QList_QPoint"); + qRegisterMetaType<::QList_QPointF>("QList_QPointF"); + qRegisterMetaType<::QList_QRect>("QList_QRect"); + qRegisterMetaType<::QList_QRectF>("QList_QRectF"); + qRegisterMetaType<::QList_QSize>("QList_QSize"); + qRegisterMetaType<::QList_QSizeF>("QList_QSizeF"); + qRegisterMetaType<::QList_QString>("QList_QString"); + qRegisterMetaType<::QList_QTime>("QList_QTime"); + qRegisterMetaType<::QList_QUrl>("QList_QUrl"); + // Ensure that QList (aka QVariantList) is registered + // otherwise it cannot be used in QML + qRegisterMetaType<::QList_QVariant>("QList_QVariant"); + qRegisterMetaType<::QList_u8>("QList_u8"); + qRegisterMetaType<::QList_u16>("QList_u16"); + qRegisterMetaType<::QList_u32>("QList_u32"); + qRegisterMetaType<::QList_u64>("QList_u64"); + + // QMap + // Ensure that QMap (aka QVariantMap) is registered + // otherwise it cannot be used in QML + qRegisterMetaType<::QMap_QString_QVariant>("QMap_QString_QVariant"); + + // QSet + qRegisterMetaType<::QSet_bool>("QSet_bool"); + qRegisterMetaType<::QSet_f32>("QSet_f32"); + qRegisterMetaType<::QSet_f64>("QSet_f64"); + qRegisterMetaType<::QSet_i8>("QSet_i8"); + qRegisterMetaType<::QSet_i16>("QSet_i16"); + qRegisterMetaType<::QSet_i32>("QSet_i32"); + qRegisterMetaType<::QSet_i64>("QSet_i64"); + qRegisterMetaType<::QSet_QByteArray>("QSet_QByteArray"); + qRegisterMetaType<::QSet_QDate>("QSet_QDate"); + qRegisterMetaType<::QSet_QDateTime>("QSet_QDateTime"); + qRegisterMetaType<::QSet_QPersistentModelIndex>("QSet_QPersistentModelIndex"); + qRegisterMetaType<::QSet_QString>("QSet_QString"); + qRegisterMetaType<::QSet_QTime>("QSet_QTime"); + qRegisterMetaType<::QSet_QUrl>("QSet_QUrl"); + qRegisterMetaType<::QSet_u8>("QSet_u8"); + qRegisterMetaType<::QSet_u16>("QSet_u16"); + qRegisterMetaType<::QSet_u32>("QSet_u32"); + qRegisterMetaType<::QSet_u64>("QSet_u64"); + + // QVector + qRegisterMetaType<::QVector_bool>("QVector_bool"); + qRegisterMetaType<::QVector_f32>("QVector_f32"); + qRegisterMetaType<::QVector_f64>("QVector_f64"); + qRegisterMetaType<::QVector_i8>("QVector_i8"); + qRegisterMetaType<::QVector_i16>("QVector_i16"); + qRegisterMetaType<::QVector_i32>("QVector_i32"); + qRegisterMetaType<::QVector_i64>("QVector_i64"); + qRegisterMetaType<::QVector_QByteArray>("QVector_QByteArray"); + qRegisterMetaType<::QVector_QDate>("QVector_QDate"); + qRegisterMetaType<::QVector_QDateTime>("QVector_QDateTime"); + qRegisterMetaType<::QVector_QMargins>("QVector_QMargins"); + qRegisterMetaType<::QVector_QMarginsF>("QVector_QMarginsF"); + qRegisterMetaType<::QVector_QPersistentModelIndex>( + "QVector_QPersistentModelIndex"); + qRegisterMetaType<::QVector_QPoint>("QVector_QPoint"); + qRegisterMetaType<::QVector_QPointF>("QVector_QPointF"); + qRegisterMetaType<::QVector_QRect>("QVector_QRect"); + qRegisterMetaType<::QVector_QRectF>("QVector_QRectF"); + qRegisterMetaType<::QVector_QSize>("QVector_QSize"); + qRegisterMetaType<::QVector_QSizeF>("QVector_QSizeF"); + qRegisterMetaType<::QVector_QString>("QVector_QString"); + qRegisterMetaType<::QVector_QTime>("QVector_QTime"); + qRegisterMetaType<::QVector_QUrl>("QVector_QUrl"); + // Ensure that QVector (aka QVariantList) is registered + // otherwise it cannot be used in QML + qRegisterMetaType<::QVector_QVariant>("QVector_QVariant"); + qRegisterMetaType<::QVector_u8>("QVector_u8"); + qRegisterMetaType<::QVector_u16>("QVector_u16"); + qRegisterMetaType<::QVector_u32>("QVector_u32"); + qRegisterMetaType<::QVector_u64>("QVector_u64"); +} diff --git a/crates/cxx-qt-lib-headers/include/gui/init.cpp b/crates/cxx-qt-lib-headers/include/gui/init.cpp new file mode 100644 index 000000000..3a74258cf --- /dev/null +++ b/crates/cxx-qt-lib-headers/include/gui/init.cpp @@ -0,0 +1,19 @@ +// clang-format off +// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company +// clang-format on +// SPDX-FileContributor: Andrew Hayzen +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +#include +#include + +void +cxx_qt_lib_gui_init() +{ + // QList + qRegisterMetaType<::QList_QColor>("QList_QColor"); + + // QVector + qRegisterMetaType<::QVector_QColor>("QVector_QColor"); +} diff --git a/crates/cxx-qt-lib-headers/src/lib.rs b/crates/cxx-qt-lib-headers/src/lib.rs index 1c47f6803..cccf14805 100644 --- a/crates/cxx-qt-lib-headers/src/lib.rs +++ b/crates/cxx-qt-lib-headers/src/lib.rs @@ -8,6 +8,8 @@ //! The headers for cxx-qt-lib, when combined into cxx-qt-lib crate this fails to build on Windows. //! The issue occurs when cxx-qt-lib is a build-dependency of an example +use cxx_qt_build::CxxQtBuilderInit; + /// Retrieves the headers for cxx-qt-lib /// /// These can be passed into [cxx_qt_build::CxxQtBuilder]. @@ -110,9 +112,21 @@ pub fn build_opts() -> cxx_qt_build::CxxQtBuildersOpts { opts = opts.header(file_contents, "cxx-qt-lib", file_name); } + // Add the Qt Core initialisers + opts = opts.init(CxxQtBuilderInit::new( + "cxx_qt_lib_core_init", + include_str!("../include/core/init.cpp"), + )); + #[cfg(feature = "qt_gui")] { - opts = opts.define("CXX_QT_GUI_FEATURE").qt_module("Gui"); + opts = opts + .define("CXX_QT_GUI_FEATURE") + .qt_module("Gui") + .init(CxxQtBuilderInit::new( + "cxx_qt_lib_gui_init", + include_str!("../include/gui/init.cpp"), + )); } #[cfg(feature = "qt_qml")] diff --git a/crates/cxx-qt-lib/build.rs b/crates/cxx-qt-lib/build.rs index 0ff576591..812462d9f 100644 --- a/crates/cxx-qt-lib/build.rs +++ b/crates/cxx-qt-lib/build.rs @@ -249,5 +249,9 @@ fn main() { }); println!("cargo:rerun-if-changed=src/assertion_utils.h"); - builder.with_opts(cxx_qt_lib_headers::build_opts()).build(); + builder + .with_opts(cxx_qt_lib_headers::build_opts()) + // Disable init generation as we are not the final target + .disable_init_generation() + .build(); } diff --git a/crates/cxx-qt-lib/src/core/qhash/qhash.cpp b/crates/cxx-qt-lib/src/core/qhash/qhash.cpp index 089513908..20c3a20b1 100644 --- a/crates/cxx-qt-lib/src/core/qhash/qhash.cpp +++ b/crates/cxx-qt-lib/src/core/qhash/qhash.cpp @@ -28,10 +28,3 @@ CXX_QT_QHASH_ASSERTS(QString, QVariant, QString_QVariant); CXX_QT_QHASH_ASSERTS(::std::int32_t, QByteArray, i32_QByteArray); - -static const int register_QHash_i32_QByteArray = - qRegisterMetaType<::QHash_i32_QByteArray>("QHash_i32_QByteArray"); -// Ensure that QHash (aka QVariantHash) is registered -// otherwise it cannot be used in QML -static const int register_QHash_QString_QVariant = - qRegisterMetaType<::QHash_QString_QVariant>("QHash_QString_QVariant"); diff --git a/crates/cxx-qt-lib/src/core/qlist/qlist.cpp b/crates/cxx-qt-lib/src/core/qlist/qlist.cpp index 4644aff17..df797c6de 100644 --- a/crates/cxx-qt-lib/src/core/qlist/qlist.cpp +++ b/crates/cxx-qt-lib/src/core/qlist/qlist.cpp @@ -60,63 +60,3 @@ CXX_QT_QLIST_ASSERTS(::std::uint8_t, u8); CXX_QT_QLIST_ASSERTS(::std::uint16_t, u16); CXX_QT_QLIST_ASSERTS(::std::uint32_t, u32); CXX_QT_QLIST_ASSERTS(::std::uint64_t, u64); - -static const int register_QList_bool = - qRegisterMetaType<::QList_bool>("QList_bool"); -static const int register_QList_f32 = - qRegisterMetaType<::QList_f32>("QList_f32"); -static const int register_QList_f64 = - qRegisterMetaType<::QList_f64>("QList_f64"); -static const int register_QList_i8 = qRegisterMetaType<::QList_i8>("QList_i8"); -static const int register_QList_i16 = - qRegisterMetaType<::QList_i16>("QList_i16"); -static const int register_QList_i32 = - qRegisterMetaType<::QList_i32>("QList_i32"); -static const int register_QList_i64 = - qRegisterMetaType<::QList_i64>("QList_i64"); -static const int register_QList_QByteArray = - qRegisterMetaType<::QList_QByteArray>("QList_QByteArray"); -#ifdef CXX_QT_GUI_FEATURE -static const int register_QList_QColor = - qRegisterMetaType<::QList_QColor>("QList_QColor"); -#endif -static const int register_QList_QDate = - qRegisterMetaType<::QList_QDate>("QList_QDate"); -static const int register_QList_QDateTime = - qRegisterMetaType<::QList_QDateTime>("QList_QDateTime"); -static const int register_QList_QMargins = - qRegisterMetaType<::QList_QMargins>("QList_QMargins"); -static const int register_QList_QMarginsF = - qRegisterMetaType<::QList_QMarginsF>("QList_QMarginsF"); -static const int register_QList_QPersistentModelIndex = - qRegisterMetaType<::QList_QPersistentModelIndex>( - "QList_QPersistentModelIndex"); -static const int register_QList_QPoint = - qRegisterMetaType<::QList_QPoint>("QList_QPoint"); -static const int register_QList_QPointF = - qRegisterMetaType<::QList_QPointF>("QList_QPointF"); -static const int register_QList_QRect = - qRegisterMetaType<::QList_QRect>("QList_QRect"); -static const int register_QList_QRectF = - qRegisterMetaType<::QList_QRectF>("QList_QRectF"); -static const int register_QList_QSize = - qRegisterMetaType<::QList_QSize>("QList_QSize"); -static const int register_QList_QSizeF = - qRegisterMetaType<::QList_QSizeF>("QList_QSizeF"); -static const int register_QList_QString = - qRegisterMetaType<::QList_QString>("QList_QString"); -static const int register_QList_QTime = - qRegisterMetaType<::QList_QTime>("QList_QTime"); -static const int register_QList_QUrl = - qRegisterMetaType<::QList_QUrl>("QList_QUrl"); -// Ensure that QList (aka QVariantList) is registered -// otherwise it cannot be used in QML -static const int register_QList_QVariant = - qRegisterMetaType<::QList_QVariant>("QList_QVariant"); -static const int register_QList_u8 = qRegisterMetaType<::QList_u8>("QList_u8"); -static const int register_QList_u16 = - qRegisterMetaType<::QList_u16>("QList_u16"); -static const int register_QList_u32 = - qRegisterMetaType<::QList_u32>("QList_u32"); -static const int register_QList_u64 = - qRegisterMetaType<::QList_u64>("QList_u64"); diff --git a/crates/cxx-qt-lib/src/core/qmap/qmap.cpp b/crates/cxx-qt-lib/src/core/qmap/qmap.cpp index 6e059cf69..e4270b41a 100644 --- a/crates/cxx-qt-lib/src/core/qmap/qmap.cpp +++ b/crates/cxx-qt-lib/src/core/qmap/qmap.cpp @@ -27,8 +27,3 @@ static_assert(::std::is_copy_constructible::value); CXX_QT_QMAP_ASSERTS(QString, QVariant, QString_QVariant); - -// Ensure that QMap (aka QVariantMap) is registered -// otherwise it cannot be used in QML -static const int register_QMap_QString_QVariant = - qRegisterMetaType<::QMap_QString_QVariant>("QMap_QString_QVariant"); diff --git a/crates/cxx-qt-lib/src/core/qset/qset.cpp b/crates/cxx-qt-lib/src/core/qset/qset.cpp index 5e345d720..28b97fb6c 100644 --- a/crates/cxx-qt-lib/src/core/qset/qset.cpp +++ b/crates/cxx-qt-lib/src/core/qset/qset.cpp @@ -39,30 +39,3 @@ CXX_QT_QSET_ASSERTS(::std::uint8_t, u8); CXX_QT_QSET_ASSERTS(::std::uint16_t, u16); CXX_QT_QSET_ASSERTS(::std::uint32_t, u32); CXX_QT_QSET_ASSERTS(::std::uint64_t, u64); - -static const int register_QSet_bool = - qRegisterMetaType<::QSet_bool>("QSet_bool"); -static const int register_QSet_f32 = qRegisterMetaType<::QSet_f32>("QSet_f32"); -static const int register_QSet_f64 = qRegisterMetaType<::QSet_f64>("QSet_f64"); -static const int register_QSet_i8 = qRegisterMetaType<::QSet_i8>("QSet_i8"); -static const int register_QSet_i16 = qRegisterMetaType<::QSet_i16>("QSet_i16"); -static const int register_QSet_i32 = qRegisterMetaType<::QSet_i32>("QSet_i32"); -static const int register_QSet_i64 = qRegisterMetaType<::QSet_i64>("QSet_i64"); -static const int register_QSet_QByteArray = - qRegisterMetaType<::QSet_QByteArray>("QSet_QByteArray"); -static const int register_QSet_QDate = - qRegisterMetaType<::QSet_QDate>("QSet_QDate"); -static const int register_QSet_QDateTime = - qRegisterMetaType<::QSet_QDateTime>("QSet_QDateTime"); -static const int register_QSet_QPersistentModelIndex = - qRegisterMetaType<::QSet_QPersistentModelIndex>("QSet_QPersistentModelIndex"); -static const int register_QSet_QString = - qRegisterMetaType<::QSet_QString>("QSet_QString"); -static const int register_QSet_QTime = - qRegisterMetaType<::QSet_QTime>("QSet_QTime"); -static const int register_QSet_QUrl = - qRegisterMetaType<::QSet_QUrl>("QSet_QUrl"); -static const int register_QSet_u8 = qRegisterMetaType<::QSet_u8>("QSet_u8"); -static const int register_QSet_u16 = qRegisterMetaType<::QSet_u16>("QSet_u16"); -static const int register_QSet_u32 = qRegisterMetaType<::QSet_u32>("QSet_u32"); -static const int register_QSet_u64 = qRegisterMetaType<::QSet_u64>("QSet_u64"); diff --git a/crates/cxx-qt-lib/src/core/qvector/qvector.cpp b/crates/cxx-qt-lib/src/core/qvector/qvector.cpp index 1e1332046..f1ae8617a 100644 --- a/crates/cxx-qt-lib/src/core/qvector/qvector.cpp +++ b/crates/cxx-qt-lib/src/core/qvector/qvector.cpp @@ -61,65 +61,3 @@ CXX_QT_QVECTOR_ASSERTS(::std::uint8_t, u8); CXX_QT_QVECTOR_ASSERTS(::std::uint16_t, u16); CXX_QT_QVECTOR_ASSERTS(::std::uint32_t, u32); CXX_QT_QVECTOR_ASSERTS(::std::uint64_t, u64); - -static const int register_QVector_bool = - qRegisterMetaType<::QVector_bool>("QVector_bool"); -static const int register_QVector_f32 = - qRegisterMetaType<::QVector_f32>("QVector_f32"); -static const int register_QVector_f64 = - qRegisterMetaType<::QVector_f64>("QVector_f64"); -static const int register_QVector_i8 = - qRegisterMetaType<::QVector_i8>("QVector_i8"); -static const int register_QVector_i16 = - qRegisterMetaType<::QVector_i16>("QVector_i16"); -static const int register_QVector_i32 = - qRegisterMetaType<::QVector_i32>("QVector_i32"); -static const int register_QVector_i64 = - qRegisterMetaType<::QVector_i64>("QVector_i64"); -static const int register_QVector_QByteArray = - qRegisterMetaType<::QVector_QByteArray>("QVector_QByteArray"); -#ifdef CXX_QT_GUI_FEATURE -static const int register_QVector_QColor = - qRegisterMetaType<::QVector_QColor>("QVector_QColor"); -#endif -static const int register_QVector_QDate = - qRegisterMetaType<::QVector_QDate>("QVector_QDate"); -static const int register_QVector_QDateTime = - qRegisterMetaType<::QVector_QDateTime>("QVector_QDateTime"); -static const int register_QVector_QMargins = - qRegisterMetaType<::QVector_QMargins>("QVector_QMargins"); -static const int register_QVector_QMarginsF = - qRegisterMetaType<::QVector_QMarginsF>("QVector_QMarginsF"); -static const int register_QVector_QPersistentModelIndex = - qRegisterMetaType<::QVector_QPersistentModelIndex>( - "QVector_QPersistentModelIndex"); -static const int register_QVector_QPoint = - qRegisterMetaType<::QVector_QPoint>("QVector_QPoint"); -static const int register_QVector_QPointF = - qRegisterMetaType<::QVector_QPointF>("QVector_QPointF"); -static const int register_QVector_QRect = - qRegisterMetaType<::QVector_QRect>("QVector_QRect"); -static const int register_QVector_QRectF = - qRegisterMetaType<::QVector_QRectF>("QVector_QRectF"); -static const int register_QVector_QSize = - qRegisterMetaType<::QVector_QSize>("QVector_QSize"); -static const int register_QVector_QSizeF = - qRegisterMetaType<::QVector_QSizeF>("QVector_QSizeF"); -static const int register_QVector_QString = - qRegisterMetaType<::QVector_QString>("QVector_QString"); -static const int register_QVector_QTime = - qRegisterMetaType<::QVector_QTime>("QVector_QTime"); -static const int register_QVector_QUrl = - qRegisterMetaType<::QVector_QUrl>("QVector_QUrl"); -// Ensure that QVector (aka QVariantList) is registered -// otherwise it cannot be used in QML -static const int register_QVector_QVariant = - qRegisterMetaType<::QVector_QVariant>("QVector_QVariant"); -static const int register_QVector_u8 = - qRegisterMetaType<::QVector_u8>("QVector_u8"); -static const int register_QVector_u16 = - qRegisterMetaType<::QVector_u16>("QVector_u16"); -static const int register_QVector_u32 = - qRegisterMetaType<::QVector_u32>("QVector_u32"); -static const int register_QVector_u64 = - qRegisterMetaType<::QVector_u64>("QVector_u64"); diff --git a/crates/cxx-qt/src/init.rs b/crates/cxx-qt/src/init.rs new file mode 100644 index 000000000..c618e3f9c --- /dev/null +++ b/crates/cxx-qt/src/init.rs @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company +// SPDX-FileContributor: Andrew Hayzen +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +// Find CXX-Qt initialise method when we link at the end +extern "C" { + fn __cxx_qt_init(); +} + +/// Initialise any static initialisers needed by CXX-Qt +/// - `Q_IMPORT_PLUGIN` QML plugins defined in the build.rs +/// - `Q_INIT_RESOURCE` qrc paths defined in the build.rs +/// - Register types with Qt that are required +pub fn init() { + unsafe { + __cxx_qt_init(); + } +} diff --git a/crates/cxx-qt/src/lib.rs b/crates/cxx-qt/src/lib.rs index edee54915..7af77ba65 100644 --- a/crates/cxx-qt/src/lib.rs +++ b/crates/cxx-qt/src/lib.rs @@ -13,12 +13,14 @@ use std::{fs::File, io::Write, path::Path}; mod connection; mod connectionguard; +mod init; #[doc(hidden)] pub mod signalhandler; mod threading; pub use cxx_qt_macro::bridge; pub use cxx_qt_macro::qobject; +pub use init::init; pub use connection::{ConnectionType, QMetaObjectConnection}; pub use connectionguard::QMetaObjectConnectionGuard; diff --git a/crates/qt-build-utils/src/lib.rs b/crates/qt-build-utils/src/lib.rs index b8562fe13..93b7b5937 100644 --- a/crates/qt-build-utils/src/lib.rs +++ b/crates/qt-build-utils/src/lib.rs @@ -176,8 +176,6 @@ pub struct QmlModuleRegistrationFiles { pub qmltyperegistrar: PathBuf, /// File with generated [QQmlEngineExtensionPlugin](https://doc.qt.io/qt-6/qqmlengineextensionplugin.html) that calls the function generated by qmltyperegistrar. pub plugin: PathBuf, - /// File that automatically registers the QQmlExtensionPlugin at startup. Must be linked with `+whole-archive`. - pub plugin_init: PathBuf, } /// Helper for build.rs scripts using Qt @@ -863,7 +861,6 @@ prefer :/qt/qml/{qml_uri_dirs}/ // Generate QQmlEngineExtensionPlugin let qml_plugin_cpp_path = PathBuf::from(format!("{out_dir}/{plugin_class_name}.cpp")); - let qml_plugin_init_path = PathBuf::from(format!("{out_dir}/{plugin_class_name}_init.cpp")); { // This function is generated by qmltyperegistrar let register_types_function = format!("qml_register_types_{qml_uri_underscores}"); @@ -886,6 +883,9 @@ public: {{ volatile auto registration = &{register_types_function}; Q_UNUSED(registration); + + // Ensure that the QML resources are initalised + Q_INIT_RESOURCE(qml_module_resources_{qml_uri_underscores}_qrc); }} }}; @@ -901,17 +901,6 @@ public: ..Default::default() }, ); - - // Generate file to load static QQmlExtensionPlugin - let mut qml_plugin_init = File::create(&qml_plugin_init_path).unwrap(); - write!( - qml_plugin_init, - r#" -#include -Q_IMPORT_PLUGIN({plugin_class_name}); -"# - ) - .unwrap(); } QmlModuleRegistrationFiles { @@ -919,7 +908,6 @@ Q_IMPORT_PLUGIN({plugin_class_name}); qmlcachegen: qmlcachegen_file_paths, qmltyperegistrar: qmltyperegistrar_output_path, plugin: qml_plugin_cpp_path, - plugin_init: qml_plugin_init_path, } } diff --git a/examples/cargo_without_cmake/src/main.rs b/examples/cargo_without_cmake/src/main.rs index 56fb170e4..e8609c63a 100644 --- a/examples/cargo_without_cmake/src/main.rs +++ b/examples/cargo_without_cmake/src/main.rs @@ -19,6 +19,9 @@ use cxx_qt_lib::{QGuiApplication, QQmlApplicationEngine, QUrl}; // ANCHOR: book_cargo_rust_main fn main() { + // Initialise CXX-Qt and any types + cxx_qt::init(); + // Create the application and engine let mut app = QGuiApplication::new(); let mut engine = QQmlApplicationEngine::new(); diff --git a/examples/demo_threading/CMakeLists.txt b/examples/demo_threading/CMakeLists.txt index c8e712633..1de58cc39 100644 --- a/examples/demo_threading/CMakeLists.txt +++ b/examples/demo_threading/CMakeLists.txt @@ -53,7 +53,7 @@ corrosion_set_env_vars(${CRATE} add_library(${APP_NAME}_lib INTERFACE) target_include_directories(${APP_NAME}_lib INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}") target_link_libraries(${APP_NAME}_lib INTERFACE - "$" + ${CRATE} Qt::Core Qt::Gui Qt::Qml diff --git a/examples/demo_threading/cpp/main.cpp b/examples/demo_threading/cpp/main.cpp index ff1ee837c..1f3e21c15 100644 --- a/examples/demo_threading/cpp/main.cpp +++ b/examples/demo_threading/cpp/main.cpp @@ -7,12 +7,16 @@ #include #include +#include + #include "helpers/energyusageproxymodel.h" #include "helpers/sensor.h" int main(int argc, char* argv[]) { + cxx_qt::init(); + QGuiApplication app(argc, argv); QQmlApplicationEngine engine; diff --git a/examples/qml_features/CMakeLists.txt b/examples/qml_features/CMakeLists.txt index ebdab49a4..022a6f914 100644 --- a/examples/qml_features/CMakeLists.txt +++ b/examples/qml_features/CMakeLists.txt @@ -52,7 +52,7 @@ corrosion_set_env_vars(${CRATE} add_library(${APP_NAME}_lib INTERFACE) target_include_directories(${APP_NAME}_lib INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}") target_link_libraries(${APP_NAME}_lib INTERFACE - "$" + ${CRATE} Qt::Core Qt::Gui Qt::Qml diff --git a/examples/qml_features/cpp/main.cpp b/examples/qml_features/cpp/main.cpp index 081e463fb..c08de9a0e 100644 --- a/examples/qml_features/cpp/main.cpp +++ b/examples/qml_features/cpp/main.cpp @@ -8,12 +8,16 @@ #include #include +#include + #include "custom_object.h" #include "external_qobject.h" int main(int argc, char* argv[]) { + cxx_qt::init(); + QGuiApplication app(argc, argv); QQmlApplicationEngine engine; diff --git a/examples/qml_features/tests/main.cpp b/examples/qml_features/tests/main.cpp index d60f81761..efc501ad4 100644 --- a/examples/qml_features/tests/main.cpp +++ b/examples/qml_features/tests/main.cpp @@ -7,6 +7,8 @@ #include #include +#include + #include "custom_object.h" #include "external_qobject.h" @@ -17,6 +19,7 @@ class Setup : public QObject public: Setup() { + cxx_qt::init(); qRegisterMetaType("CustomStruct"); // Note the _cpp at the end of the URI. If qmlRegisterMetatype is used here diff --git a/examples/qml_minimal/CMakeLists.txt b/examples/qml_minimal/CMakeLists.txt index 464bebedc..542bac7bf 100644 --- a/examples/qml_minimal/CMakeLists.txt +++ b/examples/qml_minimal/CMakeLists.txt @@ -79,9 +79,7 @@ add_library(${APP_NAME}_lib INTERFACE) target_include_directories(${APP_NAME}_lib INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}") target_link_libraries(${APP_NAME}_lib INTERFACE - # WHOLE_ARCHIVE is needed for the generated QML plugin to register on startup, - # otherwise the linker will discard the static variables that initialize it. - "$" + ${CRATE} Qt::Core Qt::Gui Qt::Qml diff --git a/examples/qml_minimal/cpp/main.cpp b/examples/qml_minimal/cpp/main.cpp index c6c53fb61..2542d4652 100644 --- a/examples/qml_minimal/cpp/main.cpp +++ b/examples/qml_minimal/cpp/main.cpp @@ -10,9 +10,13 @@ #include #include +#include + int main(int argc, char* argv[]) { + cxx_qt::init(); + QGuiApplication app(argc, argv); QQmlApplicationEngine engine; diff --git a/examples/qml_minimal/tests/myobject/tst_myobject.cpp b/examples/qml_minimal/tests/myobject/tst_myobject.cpp index 5cfa32052..48a4abb12 100644 --- a/examples/qml_minimal/tests/myobject/tst_myobject.cpp +++ b/examples/qml_minimal/tests/myobject/tst_myobject.cpp @@ -9,9 +9,14 @@ #include #include +#include + class Setup : public QObject { Q_OBJECT + +public: + Setup() { cxx_qt::init(); } }; QUICK_TEST_MAIN_WITH_SETUP(myobject, Setup) diff --git a/tests/basic_cxx_qt/CMakeLists.txt b/tests/basic_cxx_qt/CMakeLists.txt index e144c7483..ba2896163 100644 --- a/tests/basic_cxx_qt/CMakeLists.txt +++ b/tests/basic_cxx_qt/CMakeLists.txt @@ -39,8 +39,11 @@ corrosion_set_env_vars(${CRATE} "QMAKE=${QMAKE}" $<$:RUSTC_WRAPPER=${CMAKE_RUSTC_WRAPPER}> ) -target_include_directories(${CRATE} INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}") -target_link_libraries(${CRATE} INTERFACE + +add_library(${APP_NAME}_lib INTERFACE) +target_include_directories(${APP_NAME}_lib INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}") +target_link_libraries(${APP_NAME}_lib INTERFACE + ${CRATE} Qt::Core Qt::Gui Qt::Qml @@ -49,6 +52,6 @@ target_link_libraries(${CRATE} INTERFACE add_executable(${APP_NAME} cpp/main.cpp) target_link_libraries(${APP_NAME} PRIVATE - ${CRATE} + ${APP_NAME}_lib Qt::Test ) diff --git a/tests/basic_cxx_qt/cpp/main.cpp b/tests/basic_cxx_qt/cpp/main.cpp index 4b08c4c77..0043f1d6c 100644 --- a/tests/basic_cxx_qt/cpp/main.cpp +++ b/tests/basic_cxx_qt/cpp/main.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include "cxx-qt-gen/empty.cxxqt.h" #include "cxx-qt-gen/locking.cxxqt.h" #include "cxx-qt-gen/my_data.cxxqt.h" @@ -38,6 +40,8 @@ class CxxQtTest : public QObject Q_OBJECT private Q_SLOTS: + void initTestCase() { cxx_qt::init(); } + // CXX-Qt allows basic interaction between C++ (with Qt) and Rust void test_basic_interaction() { diff --git a/tests/basic_cxx_qt/rust/Cargo.toml b/tests/basic_cxx_qt/rust/Cargo.toml index 78551fd36..ade036a88 100644 --- a/tests/basic_cxx_qt/rust/Cargo.toml +++ b/tests/basic_cxx_qt/rust/Cargo.toml @@ -23,3 +23,6 @@ serde_json = "1.0" [build-dependencies] cxx-qt-build.workspace = true cxx-qt-lib-headers.workspace = true + +[features] +link_qt_object_files = [ "cxx-qt-build/link_qt_object_files" ] diff --git a/tests/qt_types_standalone/CMakeLists.txt b/tests/qt_types_standalone/CMakeLists.txt index db7b9bd70..86e84c7ba 100644 --- a/tests/qt_types_standalone/CMakeLists.txt +++ b/tests/qt_types_standalone/CMakeLists.txt @@ -39,8 +39,11 @@ corrosion_set_env_vars(${CRATE} "QMAKE=${QMAKE}" $<$:RUSTC_WRAPPER=${CMAKE_RUSTC_WRAPPER}> ) -target_include_directories(${CRATE} INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}") -target_link_libraries(${CRATE} INTERFACE + +add_library(${APP_NAME}_lib INTERFACE) +target_include_directories(${APP_NAME}_lib INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}") +target_link_libraries(${APP_NAME}_lib INTERFACE + ${CRATE} Qt::Core Qt::Gui Qt::Qml @@ -92,6 +95,6 @@ add_executable(${APP_NAME} target_include_directories(${APP_NAME} PRIVATE cpp) target_link_libraries(${APP_NAME} PRIVATE - ${CRATE} + ${APP_NAME}_lib Qt::Test ) diff --git a/tests/qt_types_standalone/cpp/main.cpp b/tests/qt_types_standalone/cpp/main.cpp index 04c42e465..1f8b890b7 100644 --- a/tests/qt_types_standalone/cpp/main.cpp +++ b/tests/qt_types_standalone/cpp/main.cpp @@ -7,6 +7,8 @@ #include #include +#include + #include "qbytearray.h" #include "qcolor.h" #include "qcoreapplication.h" @@ -50,6 +52,8 @@ int main(int argc, char* argv[]) { + cxx_qt::init(); + int status = 0; auto runTest = [&status, argc, argv](QScopedPointer obj) { if (status == 0) { diff --git a/tests/qt_types_standalone/rust/Cargo.toml b/tests/qt_types_standalone/rust/Cargo.toml index f6d70338f..62e036aff 100644 --- a/tests/qt_types_standalone/rust/Cargo.toml +++ b/tests/qt_types_standalone/rust/Cargo.toml @@ -21,3 +21,6 @@ cxx-qt-lib.workspace = true [build-dependencies] cxx-qt-build.workspace = true cxx-qt-lib-headers.workspace = true + +[features] +link_qt_object_files = [ "cxx-qt-build/link_qt_object_files" ]