diff --git a/CHANGELOG.md b/CHANGELOG.md index dc20c5fa6..9beb51fc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added +- #782 - added `build-std` config option, which builds the rust standard library from source if enabled. - #775 - forward Cargo exit code to host - #772 - added `CROSS_CONTAINER_OPTS` environment variable to replace `DOCKER_OPTS`. - #767, #788 - added the `cross-util` and `xtask` commands. diff --git a/docs/cross_toml.md b/docs/cross_toml.md index 662c541af..16f306886 100644 --- a/docs/cross_toml.md +++ b/docs/cross_toml.md @@ -6,6 +6,7 @@ The `build` key allows you to set global variables, e.g.: ```toml [build] xargo = true +build-std = true default-target = "x86_64-unknown-linux-gnu" ``` @@ -26,6 +27,7 @@ The `target` key allows you to specify parameters for specific compilation targe ```toml [target.aarch64-unknown-linux-gnu] xargo = false +build-std = false image = "test-image" runner = "custom-runner" ``` @@ -38,4 +40,4 @@ This is similar to `build.env`, but allows you to be more specific per target. [target.x86_64-unknown-linux-gnu.env] volumes = ["VOL1_ARG", "VOL2_ARG"] passthrough = ["IMPORTANT_ENV_VARIABLES"] -``` \ No newline at end of file +``` diff --git a/src/config.rs b/src/config.rs index 70c967979..b7a3ddf77 100644 --- a/src/config.rs +++ b/src/config.rs @@ -41,7 +41,11 @@ impl Environment { } fn build_path(key: &str) -> String { - format!("BUILD_{key}") + if !key.starts_with("BUILD_") { + format!("BUILD_{key}") + } else { + key.to_string() + } } fn get_build_var(&self, key: &str) -> Option { @@ -56,6 +60,10 @@ impl Environment { self.get_values_for("XARGO", target, bool_from_envvar) } + fn build_std(&self, target: &Target) -> (Option, Option) { + self.get_values_for("BUILD_STD", target, bool_from_envvar) + } + fn image(&self, target: &Target) -> Option { self.get_target_var(target, "IMAGE") } @@ -191,6 +199,10 @@ impl Config { self.bool_from_config(target, Environment::xargo, CrossToml::xargo) } + pub fn build_std(&self, target: &Target) -> Option { + self.bool_from_config(target, Environment::build_std, CrossToml::build_std) + } + pub fn image(&self, target: &Target) -> Result> { self.string_from_config(target, Environment::image, CrossToml::image) } @@ -270,9 +282,11 @@ mod tests { pub fn parse_error_in_env() { let mut map = std::collections::HashMap::new(); map.insert("CROSS_BUILD_XARGO", "tru"); + map.insert("CROSS_BUILD_STD", "false"); let env = Environment::new(Some(map)); assert_eq!(env.xargo(&target()), (Some(true), None)); + assert_eq!(env.build_std(&target()), (Some(false), None)); } #[test] @@ -346,10 +360,12 @@ mod tests { pub fn env_target_and_toml_target_xargo_target_then_use_env() -> Result<()> { let mut map = HashMap::new(); map.insert("CROSS_TARGET_AARCH64_UNKNOWN_LINUX_GNU_XARGO", "true"); + map.insert("CROSS_TARGET_AARCH64_UNKNOWN_LINUX_GNU_BUILD_STD", "true"); let env = Environment::new(Some(map)); let config = Config::new_with(Some(toml(TOML_TARGET_XARGO_FALSE)?), env); assert!(matches!(config.xargo(&target()), Some(true))); + assert!(matches!(config.build_std(&target()), Some(true))); Ok(()) } diff --git a/src/cross_toml.rs b/src/cross_toml.rs index af05d0d4b..1c125b505 100644 --- a/src/cross_toml.rs +++ b/src/cross_toml.rs @@ -21,13 +21,16 @@ pub struct CrossBuildConfig { #[serde(default)] env: CrossEnvConfig, xargo: Option, + build_std: Option, default_target: Option, } /// Target configuration #[derive(Debug, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "kebab-case")] pub struct CrossTargetConfig { xargo: Option, + build_std: Option, image: Option, runner: Option, #[serde(default)] @@ -79,6 +82,11 @@ impl CrossToml { self.get_bool(target, |b| b.xargo, |t| t.xargo) } + /// Returns the `build.build-std` or the `target.{}.build-std` part of `Cross.toml` + pub fn build_std(&self, target: &Target) -> (Option, Option) { + self.get_bool(target, |b| b.build_std, |t| t.build_std) + } + /// Returns the list of environment variables to pass through for `build`, pub fn env_passthrough_build(&self) -> &[String] { &self.build.env.passthrough @@ -165,6 +173,7 @@ mod tests { passthrough: vec!["VAR1".to_string(), "VAR2".to_string()], }, xargo: Some(true), + build_std: None, default_target: None, }, }; @@ -198,6 +207,7 @@ mod tests { volumes: vec!["VOL1_ARG".to_string(), "VOL2_ARG".to_string()], }, xargo: Some(false), + build_std: Some(true), image: Some("test-image".to_string()), runner: None, }, @@ -214,6 +224,7 @@ mod tests { passthrough = ["VAR1", "VAR2"] [target.aarch64-unknown-linux-gnu] xargo = false + build-std = true image = "test-image" "#; let (parsed_cfg, unused) = CrossToml::parse(test_str)?; diff --git a/src/lib.rs b/src/lib.rs index 1a6c1fc94..c55026de1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -349,10 +349,18 @@ pub fn run() -> Result { is_nightly = channel == Channel::Nightly; } + // build-std overrides xargo, but only use it if it's a built-in + // tool but not an available target or doesn't have rust-std. let available_targets = rustup::available_targets(&toolchain, verbose)?; - let uses_xargo = config - .xargo(&target) - .unwrap_or_else(|| !target.is_builtin() || !available_targets.contains(&target)); + let uses_build_std = config.build_std(&target).unwrap_or(false); + let uses_xargo = + !uses_build_std && config.xargo(&target).unwrap_or(!target.is_builtin()); + if !is_nightly && uses_build_std { + eyre::bail!( + "no rust-std component available for {}: must use nightly", + target.triple() + ); + } if !uses_xargo && !available_targets.is_installed(&target) @@ -410,6 +418,9 @@ pub fn run() -> Result { if is_test && args.enable_doctests && is_nightly { filtered_args.push("-Zdoctest-xcompile".to_string()); } + if uses_build_std { + filtered_args.push("-Zbuild-std".to_string()); + } if target.needs_docker() && args.subcommand.map(|sc| sc.needs_docker()).unwrap_or(false) {