use psoc_devices::{DICE, Feature, FeatureValue, VALID_FEATURES, build_feature_versions};
use std::collections::{BTreeSet, HashSet};
macro_rules! error {
($($arg:tt)*) => {{
println!("cargo::error={}", format!($($arg)*).replace('\n', "\\n"));
std::process::exit(0);
}};
}
fn main() {
let feature_versions = build_feature_versions(VALID_FEATURES);
for (Feature(feature), values) in &feature_versions {
match values
.iter()
.next()
.unwrap_or_else(|| panic!("{feature} has no valid values"))
{
FeatureValue::Flag => {
println!("cargo:rustc-check-cfg=cfg({feature})");
}
FeatureValue::Version(_) => {
println!("cargo:rustc-check-cfg=cfg({feature})");
let versions: String = values
.iter()
.flat_map(|v| ["\"", v.contents().unwrap(), "\","])
.collect();
println!("cargo:rustc-check-cfg=cfg({feature}_version, values({versions}))");
}
FeatureValue::Property(_) => {
let values: String = values
.iter()
.flat_map(|v| ["\"", v.contents().unwrap(), "\","])
.collect();
println!("cargo:rustc-check-cfg=cfg({feature}, values({values}))");
}
}
}
let cfg_die_values: String = DICE
.iter()
.flat_map(|die| ["\"", die.name, "\","])
.collect();
println!("cargo:rustc-check-cfg=cfg(die, values({cfg_die_values}))");
let all_cores: BTreeSet<&str> = DICE
.iter()
.flat_map(|die| die.cores().iter().copied())
.collect();
let cfg_core_values: String = all_cores
.iter()
.flat_map(|core| ["\"", core, "\","])
.collect();
println!("cargo:rustc-check-cfg=cfg(core, values({cfg_core_values}))");
println!("cargo:rustc-check-cfg=cfg(secure)");
println!("cargo:rustc-check-cfg=cfg(nonsecure)");
let mut configured_die: Option<String> = None;
let mut configured_core: Option<String> = None;
for (name, _) in std::env::vars() {
if let Some(name) = name.strip_prefix("CARGO_FEATURE_DIE_") {
if let Some(existing) = configured_die {
error!(
"'die-' features are mutually exclusive (found 'die-{}' and 'die-{}')",
existing.to_lowercase(),
name.to_lowercase()
);
};
configured_die = Some(name.to_lowercase());
} else if let Some(name) = name.strip_prefix("CARGO_FEATURE_CORE_") {
if let Some(existing) = configured_core {
error!(
"'core-' features are mutually exclusive (found 'core-{}' and 'core-{}')",
existing.to_lowercase(),
name.to_lowercase()
);
};
configured_core = Some(name.to_lowercase());
}
}
let configured_die = configured_die.unwrap_or_else(|| error!(concat!(
"Must configure a die",
" (help: ensure you are depending on `psoc` with the appropriate feature selected for your part number)"
)));
let mut seen_die_names = HashSet::with_capacity(DICE.len());
let mut die = None;
for d in DICE {
assert!(
seen_die_names.insert(d.name.to_lowercase()),
"Duplicate die name {}",
d.name
);
if d.name.eq_ignore_ascii_case(&configured_die) {
die = Some(d);
}
}
let die = die.unwrap();
let features = die.features(&feature_versions);
println!("cargo:rustc-cfg=die=\"{}\"", die.name);
for (Feature(feature), value) in &features {
match value {
FeatureValue::Flag => println!("cargo:rustc-cfg={feature}"),
FeatureValue::Property(value) => {
println!("cargo:rustc-cfg={feature}=\"{value}\"")
}
FeatureValue::Version(version) => {
println!("cargo:rustc-cfg={feature}");
println!("cargo:rustc-cfg={feature}_version=\"{version}\"");
}
}
}
let configured_core = configured_core
.as_deref()
.unwrap_or(die.cores().first().unwrap());
println!("cargo:rustc-cfg=core=\"{}\"", configured_core);
let is_secure = configured_core.ends_with("_s");
let is_nonsecure = configured_core.ends_with("_ns");
if features.contains_key(&Feature("trustzone")) {
assert!(is_secure ^ is_nonsecure);
println!(
"cargo:rustc-cfg={}",
if is_secure { "secure" } else { "nonsecure" }
);
} else {
assert!(!is_secure && !is_nonsecure);
}
let expected_target = psoc_devices::target_for_core(configured_core);
let actual_target = std::env::var("TARGET").unwrap();
if expected_target != actual_target {
error!(
"The selected core '{}' requires the target '{}', but the selected target is '{}'",
configured_core, expected_target, actual_target
);
}
}