diff --git a/cargo/cargo_build_script.bzl b/cargo/cargo_build_script.bzl index e47a12253b..3e2a8ccbc6 100644 --- a/cargo/cargo_build_script.bzl +++ b/cargo/cargo_build_script.bzl @@ -31,7 +31,6 @@ def _cargo_build_script_run(ctx, script): cc_toolchain = find_cpp_toolchain(ctx) env = { - "CARGO_CFG_TARGET_ARCH": toolchain.target_arch, "CARGO_MANIFEST_DIR": manifest_dir, "CARGO_PKG_NAME": crate_name, "HOST": toolchain.exec_triple, diff --git a/cargo/cargo_build_script_runner/bin.rs b/cargo/cargo_build_script_runner/bin.rs index 24ee2103e0..629bccad5f 100644 --- a/cargo/cargo_build_script_runner/bin.rs +++ b/cargo/cargo_build_script_runner/bin.rs @@ -17,6 +17,7 @@ extern crate cargo_build_script_output_parser; use cargo_build_script_output_parser::{BuildScriptOutput, CompileAndLinkFlags}; +use std::collections::BTreeMap; use std::env; use std::ffi::OsString; use std::fs::{create_dir_all, read_to_string, write}; @@ -43,9 +44,12 @@ fn main() -> Result<(), String> { // For some reason Google's RBE does not create the output directory, force create it. create_dir_all(&out_dir_abs).expect(&format!("Failed to make output directory: {:?}", out_dir_abs)); + let target_env_vars = get_target_env_vars(&rustc_env).expect("Error getting target env vars from rustc"); + let mut command = Command::new(exec_root.join(&progname)); command .current_dir(manifest_dir.clone()) + .envs(target_env_vars) .env("OUT_DIR", out_dir_abs) .env("CARGO_MANIFEST_DIR", manifest_dir) .env("RUSTC", rustc) @@ -99,7 +103,7 @@ fn main() -> Result<(), String> { ) })?; - write(&envfile, BuildScriptOutput::to_env(&output).as_bytes()) + write(&envfile, BuildScriptOutput::to_env(&output, &exec_root.to_string_lossy()).as_bytes()) .expect(&format!("Unable to write file {:?}", envfile)); write(&depenvfile, BuildScriptOutput::to_dep_env(&output, &crate_name).as_bytes()) .expect(&format!("Unable to write file {:?}", depenvfile)); @@ -118,6 +122,44 @@ fn main() -> Result<(), String> { } } +fn get_target_env_vars>(rustc: &P) -> Result, String> { + // As done by Cargo when constructing a cargo::core::compiler::build_context::target_info::TargetInfo. + let output = Command::new(rustc.as_ref()) + .arg("--print=cfg") + .output() + .map_err(|err| format!("Error running rustc to get target information: {}", err))?; + if !output.status.success() { + return Err(format!( + "Error running rustc to get target information: {:?}", + output + )); + } + let stdout = std::str::from_utf8(&output.stdout) + .map_err(|err| format!("Non-UTF8 stdout from rustc: {:?}", err))?; + + let mut values = BTreeMap::new(); + + for line in stdout.lines() { + if line.starts_with("target_") && line.contains('=') { + let mut parts = line.splitn(2, '='); + // UNWRAP: Verified that line contains = and split into exactly 2 parts. + let key = parts.next().unwrap(); + let value = parts.next().unwrap(); + if value.starts_with('"') && value.ends_with('"') && value.len() >= 2 { + values + .entry(key) + .or_insert(vec![]) + .push(value[1..(value.len() - 1)].to_owned()); + } + } + } + + Ok(values + .into_iter() + .map(|(key, value)| (format!("CARGO_CFG_{}", key.to_uppercase()), value.join(","))) + .collect()) +} + fn absolutify(root: &Path, maybe_relative: OsString) -> OsString { let path = Path::new(&maybe_relative); if path.is_relative() { diff --git a/cargo/cargo_build_script_runner/lib.rs b/cargo/cargo_build_script_runner/lib.rs index 92b8d9ed29..5543e52135 100644 --- a/cargo/cargo_build_script_runner/lib.rs +++ b/cargo/cargo_build_script_runner/lib.rs @@ -59,7 +59,7 @@ impl BuildScriptOutput { if key_split.len() <= 1 || key_split[0] != "cargo" { // Not a cargo directive. print!("{}", line); - return None + return None; } match key_split[1] { "rustc-link-lib" => Some(BuildScriptOutput::LinkLib(param)), @@ -68,21 +68,30 @@ impl BuildScriptOutput { "rustc-flags" => Some(BuildScriptOutput::Flags(param)), "rustc-env" => Some(BuildScriptOutput::Env(param)), "rerun-if-changed" | "rerun-if-env-changed" => - // Ignored because Bazel will re-run if those change all the time. - None, + // Ignored because Bazel will re-run if those change all the time. + { + None + } "warning" => { eprintln!("Build Script Warning: {}", split[1]); None - }, + } "rustc-cdylib-link-arg" => { // cargo:rustc-cdylib-link-arg=FLAG — Passes custom flags to a linker for cdylib crates. - eprintln!("Warning: build script returned unsupported directive `{}`", split[0]); + eprintln!( + "Warning: build script returned unsupported directive `{}`", + split[0] + ); None - }, + } _ => { // cargo:KEY=VALUE — Metadata, used by links scripts. - Some(BuildScriptOutput::DepEnv(format!("{}={}", key_split[1].to_uppercase(), param))) - }, + Some(BuildScriptOutput::DepEnv(format!( + "{}={}", + key_split[1].to_uppercase(), + param + ))) + } } } @@ -101,29 +110,26 @@ impl BuildScriptOutput { /// Take a [Command], execute it and converts its input into a vector of [BuildScriptOutput] pub fn from_command(cmd: &mut Command) -> Result, Option> { - let mut child = cmd.stdout(Stdio::piped()).spawn().expect("Unable to start binary"); + let mut child = cmd + .stdout(Stdio::piped()) + .spawn() + .expect("Unable to start binary"); let ecode = child.wait().expect("failed to wait on child"); - let reader = BufReader::new( - child - .stdout - .as_mut() - .expect("Failed to open stdout"), - ); + let reader = BufReader::new(child.stdout.as_mut().expect("Failed to open stdout")); let output = Self::from_reader(reader); if ecode.success() { Ok(output) } else { Err(ecode.code()) } - } /// Convert a vector of [BuildScriptOutput] into a list of environment variables. - pub fn to_env(v: &Vec) -> String { + pub fn to_env(v: &Vec, exec_root: &str) -> String { v.iter() .filter_map(|x| { if let BuildScriptOutput::Env(env) = x { - Some(env.to_owned()) + Some(Self::redact_exec_root(env, exec_root)) } else { None } @@ -137,7 +143,9 @@ impl BuildScriptOutput { // TODO: make use of `strip_suffix`. const SYS_CRATE_SUFFIX: &str = "-sys"; let name = if crate_name.ends_with(SYS_CRATE_SUFFIX) { - crate_name.split_at(crate_name.rfind(SYS_CRATE_SUFFIX).unwrap()).0 + crate_name + .split_at(crate_name.rfind(SYS_CRATE_SUFFIX).unwrap()) + .0 } else { crate_name }; @@ -165,14 +173,18 @@ impl BuildScriptOutput { BuildScriptOutput::Flags(e) => compile_flags.push(e.to_owned()), BuildScriptOutput::LinkLib(e) => link_flags.push(format!("-l{}", e)), BuildScriptOutput::LinkSearch(e) => link_flags.push(format!("-L{}", e)), - _ => { }, + _ => {} } } CompileAndLinkFlags { compile_flags: compile_flags.join("\n"), - link_flags: link_flags.join("\n").replace(exec_root, "${pwd}"), + link_flags: Self::redact_exec_root(&link_flags.join("\n"), exec_root), } } + + fn redact_exec_root(value: &str, exec_root: &str) -> String { + value.replace(exec_root, "${pwd}") + } } #[cfg(test)] @@ -193,30 +205,44 @@ cargo:rerun-if-changed=ignored cargo:rustc-cfg=feature=awesome cargo:version=123 cargo:version_number=1010107f +cargo:rustc-env=SOME_PATH=/some/absolute/path/beep ", ); let reader = BufReader::new(buff); let result = BuildScriptOutput::from_reader(reader); - assert_eq!(result.len(), 8); + assert_eq!(result.len(), 9); assert_eq!(result[0], BuildScriptOutput::LinkLib("sdfsdf".to_owned())); assert_eq!(result[1], BuildScriptOutput::Env("FOO=BAR".to_owned())); - assert_eq!(result[2], BuildScriptOutput::LinkSearch("/some/absolute/path/bleh".to_owned())); + assert_eq!( + result[2], + BuildScriptOutput::LinkSearch("/some/absolute/path/bleh".to_owned()) + ); assert_eq!(result[3], BuildScriptOutput::Env("BAR=FOO".to_owned())); assert_eq!(result[4], BuildScriptOutput::Flags("-Lblah".to_owned())); assert_eq!( result[5], BuildScriptOutput::Cfg("feature=awesome".to_owned()) ); - assert_eq!(result[6], BuildScriptOutput::DepEnv("VERSION=123".to_owned())); - assert_eq!(result[7], BuildScriptOutput::DepEnv("VERSION_NUMBER=1010107f".to_owned())); + assert_eq!( + result[6], + BuildScriptOutput::DepEnv("VERSION=123".to_owned()) + ); + assert_eq!( + result[7], + BuildScriptOutput::DepEnv("VERSION_NUMBER=1010107f".to_owned()) + ); + assert_eq!( + result[8], + BuildScriptOutput::Env("SOME_PATH=/some/absolute/path/beep".to_owned()) + ); assert_eq!( BuildScriptOutput::to_dep_env(&result, "my-crate-sys"), "DEP_MY_CRATE_VERSION=123\nDEP_MY_CRATE_VERSION_NUMBER=1010107f".to_owned() ); assert_eq!( - BuildScriptOutput::to_env(&result), - "FOO=BAR\nBAR=FOO".to_owned() + BuildScriptOutput::to_env(&result, "/some/absolute/path"), + "FOO=BAR\nBAR=FOO\nSOME_PATH=${pwd}/beep".to_owned() ); assert_eq!( BuildScriptOutput::to_flags(&result, "/some/absolute/path"), @@ -228,5 +254,4 @@ cargo:version_number=1010107f } ); } - }