From 3b2fef80f5d6eb74c46b0ac94808a7fc252243f2 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Fri, 3 Oct 2025 12:31:36 +0100 Subject: [PATCH] qt-build-utils: add a helper for generating cfg --- Cargo.lock | 1 - crates/cxx-qt-build/Cargo.toml | 1 - crates/cxx-qt-build/src/lib.rs | 75 ++---------------- crates/qt-build-utils/src/cfg.rs | 126 +++++++++++++++++++++++++++++++ crates/qt-build-utils/src/lib.rs | 3 + 5 files changed, 137 insertions(+), 69 deletions(-) create mode 100644 crates/qt-build-utils/src/cfg.rs diff --git a/Cargo.lock b/Cargo.lock index 8b013fc8a..8fdeab63b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -394,7 +394,6 @@ dependencies = [ "proc-macro2", "qt-build-utils", "quote", - "semver", "serde", "serde_json", ] diff --git a/crates/cxx-qt-build/Cargo.toml b/crates/cxx-qt-build/Cargo.toml index 5f4afbbb2..0ade733f2 100644 --- a/crates/cxx-qt-build/Cargo.toml +++ b/crates/cxx-qt-build/Cargo.toml @@ -23,7 +23,6 @@ qt-build-utils = { workspace = true, features = ["serde"] } codespan-reporting = "0.11" serde.workspace = true serde_json = "1.0" -semver.workspace = true [features] link_qt_object_files = ["qt-build-utils/link_qt_object_files"] diff --git a/crates/cxx-qt-build/src/lib.rs b/crates/cxx-qt-build/src/lib.rs index 02783901a..95983f7a4 100644 --- a/crates/cxx-qt-build/src/lib.rs +++ b/crates/cxx-qt-build/src/lib.rs @@ -36,7 +36,6 @@ pub use qml_modules::QmlModule; pub use qt_build_utils::MocArguments; use quote::ToTokens; -use semver::Version; use std::{ collections::HashSet, env, @@ -608,71 +607,6 @@ impl CxxQtBuilder { self } - fn define_cfg_variable(key: String, value: Option<&str>) { - if let Some(value) = value { - println!("cargo::rustc-cfg={key}=\"{value}\""); - } else { - println!("cargo::rustc-cfg={key}"); - } - let variable_cargo = format!("CARGO_CFG_{key}"); - env::set_var(variable_cargo, value.unwrap_or("true")); - } - - fn define_cfg_check_variable(key: String, values: Option>) { - if let Some(values) = values { - let values = values - .iter() - // Escape and add quotes - .map(|value| format!("\"{}\"", value.escape_default())) - .collect::>() - .join(", "); - println!("cargo::rustc-check-cfg=cfg({key}, values({values}))"); - } else { - println!("cargo::rustc-check-cfg=cfg({key})"); - } - } - - fn define_qt_version_cfg_variables(version: Version) { - // Allow for Qt 5 or Qt 6 as valid values - CxxQtBuilder::define_cfg_check_variable( - "cxxqt_qt_version_major".to_owned(), - Some(vec!["5", "6"]), - ); - // Find the Qt version and tell the Rust compiler - // this allows us to have conditional Rust code - CxxQtBuilder::define_cfg_variable( - "cxxqt_qt_version_major".to_owned(), - Some(version.major.to_string().as_str()), - ); - - // Seed all values from Qt 5.0 through to Qt 7.99 - for major in 5..=7 { - CxxQtBuilder::define_cfg_check_variable( - format!("cxxqt_qt_version_at_least_{major}"), - None, - ); - - for minor in 0..=99 { - CxxQtBuilder::define_cfg_check_variable( - format!("cxxqt_qt_version_at_least_{major}_{minor}"), - None, - ); - } - } - - for minor in 0..=version.minor { - let qt_version_at_least = - format!("cxxqt_qt_version_at_least_{}_{}", version.major, minor); - CxxQtBuilder::define_cfg_variable(qt_version_at_least, None); - } - - // We don't support Qt < 5 - for major in 5..=version.major { - let at_least_qt_major_version = format!("cxxqt_qt_version_at_least_{major}"); - CxxQtBuilder::define_cfg_variable(at_least_qt_major_version, None); - } - } - fn write_common_headers() { let header_root = dir::header_root(); // Write cxx headers @@ -1103,7 +1037,14 @@ extern "C" bool {init_fun}() {{ let mut qtbuild = qt_build_utils::QtBuild::new(qt_modules.iter().cloned().collect()) .expect("Could not find Qt installation"); qtbuild.cargo_link_libraries(&mut self.cc_builder); - Self::define_qt_version_cfg_variables(qtbuild.version()); + + // Define the Qt cfg to cargo + // + // TODO: do we have this as a helper on QtBuild too? + qt_build_utils::CfgGenerator::new(qtbuild.version()) + .prefix("cxxqt_") + .range_major(5..=7) + .build(); // Ensure that Qt modules and apple framework are linked and searched correctly let mut include_paths = qtbuild.include_paths(); diff --git a/crates/qt-build-utils/src/cfg.rs b/crates/qt-build-utils/src/cfg.rs new file mode 100644 index 000000000..602b098cb --- /dev/null +++ b/crates/qt-build-utils/src/cfg.rs @@ -0,0 +1,126 @@ +// SPDX-FileCopyrightText: 2025 Klarälvdalens Datakonsult AB, a KDAB Group company +// SPDX-FileContributor: Andrew Hayzen +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use semver::Version; +use std::ops::RangeInclusive; + +/// Helper for generating cargo cfg for a version range +pub struct CfgGenerator { + prefix: Option, + range_major: RangeInclusive, + range_minor: RangeInclusive, + version: Version, +} + +impl CfgGenerator { + /// Construct a new [CfgGenerator] + pub fn new(version: Version) -> Self { + Self { + range_major: (0..=99), + range_minor: (0..=99), + prefix: None, + version, + } + } + + /// Specify a prefix for the [CfgGenerator] + pub fn prefix(mut self, prefix: impl Into) -> Self { + self.prefix = Some(prefix.into()); + self + } + + /// Specify a major range for the [CfgGenerator] + pub fn range_major(mut self, range: RangeInclusive) -> Self { + self.range_major = range; + self + } + + /// Specify a minor range for the [CfgGenerator] + pub fn range_minor(mut self, range: RangeInclusive) -> Self { + self.range_minor = range; + self + } + + /// Generate cargo cfg with any given prefix and ranges for the version + pub fn build(self) { + // Define the major version + self.define_cfg_check_variable( + "qt_version_major".to_string(), + Some( + self.range_major + .clone() + .map(|major| major.to_string()) + .collect(), + ), + ); + self.define_cfg_variable( + "qt_version_major".to_string(), + Some(self.version.major.to_string()), + ); + + // Tell cargo about all the possible cfg variables + for major in self.range_major.clone() { + self.define_cfg_check_variable(format!("qt_version_at_least_{major}"), None); + + for minor in self.range_minor.clone() { + self.define_cfg_check_variable( + format!("qt_version_at_least_{major}_{minor}"), + None, + ); + } + } + + // Tell cargo which major versions have been reached + for major in *self.range_major.start()..=self.version.major { + self.define_cfg_variable(format!("qt_version_at_least_{major}"), None); + } + + // Tell cargo which minor versions with the major have been reached + for minor in *self.range_minor.start()..=self.version.minor { + let major = self.version.major; + self.define_cfg_variable(format!("qt_version_at_least_{major}_{minor}"), None); + } + } +} + +impl CfgGenerator { + fn define_cfg_check_variable(&self, key: String, values: Option>) { + let key = self.key_with_prefix(key); + + if let Some(values) = values { + let values = values + .iter() + // Escape and add quotes + .map(|value| format!("\"{}\"", value.escape_default())) + .collect::>() + .join(", "); + + println!("cargo::rustc-check-cfg=cfg({key}, values({values}))"); + } else { + println!("cargo::rustc-check-cfg=cfg({key})"); + } + } + + fn define_cfg_variable(&self, key: String, value: Option) { + let key = self.key_with_prefix(key); + + if let Some(value) = &value { + println!("cargo::rustc-cfg={key}=\"{}\"", value.escape_default()); + } else { + println!("cargo::rustc-cfg={key}"); + } + + let variable_cargo = format!("CARGO_CFG_{key}"); + std::env::set_var(variable_cargo, value.unwrap_or("true".to_string())); + } + + fn key_with_prefix(&self, key: String) -> String { + if let Some(prefix) = &self.prefix { + format!("{prefix}{key}") + } else { + key + } + } +} diff --git a/crates/qt-build-utils/src/lib.rs b/crates/qt-build-utils/src/lib.rs index fffec4f9e..693d7abe5 100644 --- a/crates/qt-build-utils/src/lib.rs +++ b/crates/qt-build-utils/src/lib.rs @@ -15,6 +15,9 @@ #![allow(clippy::too_many_arguments)] +mod cfg; +pub use cfg::CfgGenerator; + mod error; pub use error::QtBuildError;