From feb75f165ce9ee408b9208f453153e6ef2cf9b73 Mon Sep 17 00:00:00 2001 From: Daniel Wagner-Hall Date: Wed, 30 Aug 2023 16:48:56 +0100 Subject: [PATCH] crate_universe: Allow platform-specific build script env vars (#2139) My use-case here is needing to point at different paths for libclang.so when using bindgen on different platforms. This allows specifying build script env vars in annotations like: ```starlark build_script_env = { "BORING_BSSL_PATH": "$(execpath @//third_party/boringssl:gen_dir)", "LIBCLANG_PATH": { "x86_64-unknown-linux-gnu": "$(execpath @libclang_linux_x86_64//file:libclang.so)", }, }, ``` which will unconditionally set `$BORING_BSSL_PATH`, but will only set `$LIBCLANG_PATH` on x86-64 Linux. We could in theory support this kind of construct for all annotation fields, but I've only added it where I happened to need it for now. --- crate_universe/src/config.rs | 12 +- crate_universe/src/context/crate_context.rs | 21 ++- crate_universe/src/context/platforms.rs | 103 ++++++++---- crate_universe/src/utils/starlark/select.rs | 173 ++++++++++++++++++++ 4 files changed, 276 insertions(+), 33 deletions(-) diff --git a/crate_universe/src/config.rs b/crate_universe/src/config.rs index 7e4d838495..430fce0c64 100644 --- a/crate_universe/src/config.rs +++ b/crate_universe/src/config.rs @@ -142,6 +142,14 @@ impl From for Commitish { } } } +/// A value which may either be a plain String, or a dict of platform triples +/// (or other cfg expressions understood by `crate::context::platforms::resolve_cfg_platforms`) to Strings. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(untagged)] +pub enum StringOrSelect { + Value(String), + Select(BTreeMap), +} /// Information representing deterministic identifiers for some remote asset. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] @@ -234,7 +242,7 @@ pub struct CrateAnnotations { /// Additional environment variables to pass to a build script's /// [build_script_env](https://bazelbuild.github.io/rules_rust/cargo.html#cargo_build_script-rustc_env) attribute. - pub build_script_env: Option>, + pub build_script_env: Option>, /// Additional rustc_env flags to pass to a build script's /// [rustc_env](https://bazelbuild.github.io/rules_rust/cargo.html#cargo_build_script-rustc_env) attribute. @@ -361,7 +369,7 @@ pub struct AnnotationsProvidedByPackage { pub rustc_env: Option>, pub rustc_env_files: Option>, pub rustc_flags: Option>, - pub build_script_env: Option>, + pub build_script_env: Option>, pub build_script_rustc_env: Option>, pub additive_build_file_content: Option, pub extra_aliased_targets: Option>, diff --git a/crate_universe/src/context/crate_context.rs b/crate_universe/src/context/crate_context.rs index b20350c0ee..f1747b313d 100644 --- a/crate_universe/src/context/crate_context.rs +++ b/crate_universe/src/context/crate_context.rs @@ -5,7 +5,7 @@ use std::collections::{BTreeMap, BTreeSet}; use cargo_metadata::{Node, Package, PackageId}; use serde::{Deserialize, Serialize}; -use crate::config::{CrateId, GenBinaries}; +use crate::config::{CrateId, GenBinaries, StringOrSelect}; use crate::metadata::{CrateAnnotation, Dependency, PairredExtras, SourceAnnotation}; use crate::utils::sanitize_module_name; use crate::utils::starlark::{Glob, SelectList, SelectMap, SelectStringDict, SelectStringList}; @@ -601,7 +601,24 @@ impl CrateContext { // Build script env if let Some(extra) = &crate_extra.build_script_env { - attrs.build_script_env.extend(extra.clone(), None); + for (key, value) in extra { + match value { + StringOrSelect::Value(value) => { + attrs + .build_script_env + .insert(key.clone(), value.clone(), None); + } + StringOrSelect::Select(select) => { + for (select_key, value) in select { + attrs.build_script_env.insert( + key.clone(), + value.clone(), + Some(select_key.clone()), + ); + } + } + } + } } } diff --git a/crate_universe/src/context/platforms.rs b/crate_universe/src/context/platforms.rs index 9aade30c94..bfe98c8701 100644 --- a/crate_universe/src/context/platforms.rs +++ b/crate_universe/src/context/platforms.rs @@ -9,6 +9,7 @@ use crate::utils::starlark::Select; /// Walk through all dependencies in a [CrateContext] list for all configuration specific /// dependencies to produce a mapping of configuration to compatible platform triples. +/// Also adds mappings for all known platform triples. pub fn resolve_cfg_platforms( crates: Vec<&CrateContext>, supported_platform_triples: &BTreeSet, @@ -99,6 +100,10 @@ pub fn resolve_cfg_platforms( Ok((cfg, triples)) }) + .chain(supported_platform_triples.iter().filter_map(|triple| { + let target = get_builtin_target_by_triple(triple); + target.map(|target| Ok((triple.clone(), [target.triple.to_string()].into()))) + })) .collect() } @@ -114,26 +119,7 @@ mod test { fn supported_platform_triples() -> BTreeSet { BTreeSet::from([ "aarch64-apple-darwin".to_owned(), - "aarch64-apple-ios".to_owned(), - "aarch64-linux-android".to_owned(), - "aarch64-pc-windows-msvc".to_owned(), - "aarch64-unknown-linux-gnu".to_owned(), - "arm-unknown-linux-gnueabi".to_owned(), - "armv7-unknown-linux-gnueabi".to_owned(), "i686-apple-darwin".to_owned(), - "i686-linux-android".to_owned(), - "i686-pc-windows-msvc".to_owned(), - "i686-unknown-freebsd".to_owned(), - "i686-unknown-linux-gnu".to_owned(), - "powerpc-unknown-linux-gnu".to_owned(), - "s390x-unknown-linux-gnu".to_owned(), - "wasm32-unknown-unknown".to_owned(), - "wasm32-wasi".to_owned(), - "x86_64-apple-darwin".to_owned(), - "x86_64-apple-ios".to_owned(), - "x86_64-linux-android".to_owned(), - "x86_64-pc-windows-msvc".to_owned(), - "x86_64-unknown-freebsd".to_owned(), "x86_64-unknown-linux-gnu".to_owned(), ]) } @@ -163,7 +149,24 @@ mod test { let configurations = resolve_cfg_platforms(vec![&context], &supported_platform_triples()).unwrap(); - assert_eq!(configurations, BTreeMap::new(),) + assert_eq!( + configurations, + BTreeMap::from([ + // All known triples. + ( + "aarch64-apple-darwin".to_owned(), + BTreeSet::from(["aarch64-apple-darwin".to_owned()]), + ), + ( + "i686-apple-darwin".to_owned(), + BTreeSet::from(["i686-apple-darwin".to_owned()]), + ), + ( + "x86_64-unknown-linux-gnu".to_owned(), + BTreeSet::from(["x86_64-unknown-linux-gnu".to_owned()]), + ), + ]) + ) } fn mock_resolve_context(configuration: String) -> CrateContext { @@ -199,10 +202,7 @@ mod test { r#"cfg(any(target_os = "macos", target_os = "ios"))"#.to_owned(), BTreeSet::from([ "aarch64-apple-darwin".to_owned(), - "aarch64-apple-ios".to_owned(), "i686-apple-darwin".to_owned(), - "x86_64-apple-darwin".to_owned(), - "x86_64-apple-ios".to_owned(), ]), ), ]); @@ -215,7 +215,22 @@ mod test { assert_eq!( configurations, - BTreeMap::from([(configuration, expectation,)]) + BTreeMap::from([ + (configuration, expectation,), + // All known triples. + ( + "aarch64-apple-darwin".to_owned(), + BTreeSet::from(["aarch64-apple-darwin".to_owned()]), + ), + ( + "i686-apple-darwin".to_owned(), + BTreeSet::from(["i686-apple-darwin".to_owned()]), + ), + ( + "x86_64-unknown-linux-gnu".to_owned(), + BTreeSet::from(["x86_64-unknown-linux-gnu".to_owned()]), + ), + ]) ); }) } @@ -248,10 +263,25 @@ mod test { assert_eq!( configurations, - BTreeMap::from([( - configuration, - BTreeSet::from(["x86_64-unknown-linux-gnu".to_owned()]) - )]) + BTreeMap::from([ + ( + configuration, + BTreeSet::from(["x86_64-unknown-linux-gnu".to_owned()]) + ), + // All known triples. + ( + "aarch64-apple-darwin".to_owned(), + BTreeSet::from(["aarch64-apple-darwin".to_owned()]), + ), + ( + "i686-apple-darwin".to_owned(), + BTreeSet::from(["i686-apple-darwin".to_owned()]), + ), + ( + "x86_64-unknown-linux-gnu".to_owned(), + BTreeSet::from(["x86_64-unknown-linux-gnu".to_owned()]), + ), + ]) ); } @@ -283,7 +313,22 @@ mod test { assert_eq!( configurations, - BTreeMap::from([(configuration, BTreeSet::new())]) + BTreeMap::from([ + (configuration, BTreeSet::new()), + // All known triples. + ( + "aarch64-apple-darwin".to_owned(), + BTreeSet::from(["aarch64-apple-darwin".to_owned()]), + ), + ( + "i686-apple-darwin".to_owned(), + BTreeSet::from(["i686-apple-darwin".to_owned()]), + ), + ( + "x86_64-unknown-linux-gnu".to_owned(), + BTreeSet::from(["x86_64-unknown-linux-gnu".to_owned()]), + ), + ]) ); } } diff --git a/crate_universe/src/utils/starlark/select.rs b/crate_universe/src/utils/starlark/select.rs index f01acb03d9..091057a055 100644 --- a/crate_universe/src/utils/starlark/select.rs +++ b/crate_universe/src/utils/starlark/select.rs @@ -550,6 +550,179 @@ mod test { use indoc::indoc; + #[test] + fn empty_select_list() { + let select_list: SelectList = SelectList::default(); + + let expected_starlark = indoc! {r#" + [] + "#}; + + assert_eq!( + select_list + .serialize_starlark(serde_starlark::Serializer) + .unwrap(), + expected_starlark, + ); + } + + #[test] + fn no_platform_specific_select_list() { + let mut select_list = SelectList::default(); + select_list.insert("Hello".to_owned(), None); + + let expected_starlark = indoc! {r#" + [ + "Hello", + ] + "#}; + + assert_eq!( + select_list + .serialize_starlark(serde_starlark::Serializer) + .unwrap(), + expected_starlark, + ); + } + + #[test] + fn only_platform_specific_select_list() { + let mut select_list = SelectList::default(); + select_list.insert("Hello".to_owned(), Some("platform".to_owned())); + + let expected_starlark = indoc! {r#" + select({ + "platform": [ + "Hello", + ], + "//conditions:default": [], + }) + "#}; + + assert_eq!( + select_list + .serialize_starlark(serde_starlark::Serializer) + .unwrap(), + expected_starlark, + ); + } + + #[test] + fn mixed_select_list() { + let mut select_list = SelectList::default(); + select_list.insert("Hello".to_owned(), Some("platform".to_owned())); + select_list.insert("Goodbye".to_owned(), None); + + let expected_starlark = indoc! {r#" + [ + "Goodbye", + ] + select({ + "platform": [ + "Hello", + ], + "//conditions:default": [], + }) + "#}; + + assert_eq!( + select_list + .serialize_starlark(serde_starlark::Serializer) + .unwrap(), + expected_starlark, + ); + } + + #[test] + fn empty_select_dict() { + let select_dict: SelectDict = SelectDict::default(); + + let expected_starlark = indoc! {r#" + {} + "#}; + + assert_eq!( + select_dict + .serialize_starlark(serde_starlark::Serializer) + .unwrap(), + expected_starlark, + ); + } + + #[test] + fn no_platform_specific_select_dict() { + let mut select_dict = SelectDict::default(); + select_dict.insert("Greeting".to_owned(), "Hello".to_owned(), None); + + let expected_starlark = indoc! {r#" + { + "Greeting": "Hello", + } + "#}; + + assert_eq!( + select_dict + .serialize_starlark(serde_starlark::Serializer) + .unwrap(), + expected_starlark, + ); + } + + #[test] + fn only_platform_specific_select_dict() { + let mut select_dict = SelectDict::default(); + select_dict.insert( + "Greeting".to_owned(), + "Hello".to_owned(), + Some("platform".to_owned()), + ); + + let expected_starlark = indoc! {r#" + select({ + "platform": { + "Greeting": "Hello", + }, + "//conditions:default": {}, + }) + "#}; + + assert_eq!( + select_dict + .serialize_starlark(serde_starlark::Serializer) + .unwrap(), + expected_starlark, + ); + } + + #[test] + fn mixed_select_dict() { + let mut select_dict = SelectDict::default(); + select_dict.insert( + "Greeting".to_owned(), + "Hello".to_owned(), + Some("platform".to_owned()), + ); + select_dict.insert("Message".to_owned(), "Goodbye".to_owned(), None); + + let expected_starlark = indoc! {r#" + select({ + "platform": { + "Greeting": "Hello", + "Message": "Goodbye", + }, + "//conditions:default": { + "Message": "Goodbye", + }, + }) + "#}; + + assert_eq!( + select_dict + .serialize_starlark(serde_starlark::Serializer) + .unwrap(), + expected_starlark, + ); + } + #[test] fn remap_select_list_configurations() { let mut select_list = SelectList::default();