Skip to content

Commit e64700d

Browse files
authored
Assorted cargo build script fixes (#422)
* Rustfmt * Derive CARGO_CFG env vars from rustc This is what Cargo does - it means we'll automatically populate all (most) of the values cargo would. This fixes up a couple of things: 1. CARGO_CFG_TARGET_OS mismatches - Rustc treats macos as "macos" whereas the current code derives "darwin" from the target triple. 2. This sets additional env vars, such as CARGO_CFG_TARGET_ENV, CARGO_CFG_TARGET_FAMILY, etc. * Do exec_root replacement on rustc env vars Some crates, such as typenum, set rustc env vars to the paths where they generated output in $OUT_DIR, and use things like: ```rust include!(env!(...)) ``` to read them. This supports that use-case.
1 parent 169476f commit e64700d

File tree

3 files changed

+96
-30
lines changed

3 files changed

+96
-30
lines changed

cargo/cargo_build_script.bzl

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ def _cargo_build_script_run(ctx, script):
3131
cc_toolchain = find_cpp_toolchain(ctx)
3232

3333
env = {
34-
"CARGO_CFG_TARGET_ARCH": toolchain.target_arch,
3534
"CARGO_MANIFEST_DIR": manifest_dir,
3635
"CARGO_PKG_NAME": crate_name,
3736
"HOST": toolchain.exec_triple,

cargo/cargo_build_script_runner/bin.rs

+43-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
extern crate cargo_build_script_output_parser;
1818

1919
use cargo_build_script_output_parser::{BuildScriptOutput, CompileAndLinkFlags};
20+
use std::collections::BTreeMap;
2021
use std::env;
2122
use std::ffi::OsString;
2223
use std::fs::{create_dir_all, read_to_string, write};
@@ -43,9 +44,12 @@ fn main() -> Result<(), String> {
4344
// For some reason Google's RBE does not create the output directory, force create it.
4445
create_dir_all(&out_dir_abs).expect(&format!("Failed to make output directory: {:?}", out_dir_abs));
4546

47+
let target_env_vars = get_target_env_vars(&rustc_env).expect("Error getting target env vars from rustc");
48+
4649
let mut command = Command::new(exec_root.join(&progname));
4750
command
4851
.current_dir(manifest_dir.clone())
52+
.envs(target_env_vars)
4953
.env("OUT_DIR", out_dir_abs)
5054
.env("CARGO_MANIFEST_DIR", manifest_dir)
5155
.env("RUSTC", rustc)
@@ -99,7 +103,7 @@ fn main() -> Result<(), String> {
99103
)
100104
})?;
101105

102-
write(&envfile, BuildScriptOutput::to_env(&output).as_bytes())
106+
write(&envfile, BuildScriptOutput::to_env(&output, &exec_root.to_string_lossy()).as_bytes())
103107
.expect(&format!("Unable to write file {:?}", envfile));
104108
write(&depenvfile, BuildScriptOutput::to_dep_env(&output, &crate_name).as_bytes())
105109
.expect(&format!("Unable to write file {:?}", depenvfile));
@@ -118,6 +122,44 @@ fn main() -> Result<(), String> {
118122
}
119123
}
120124

125+
fn get_target_env_vars<P: AsRef<Path>>(rustc: &P) -> Result<BTreeMap<String, String>, String> {
126+
// As done by Cargo when constructing a cargo::core::compiler::build_context::target_info::TargetInfo.
127+
let output = Command::new(rustc.as_ref())
128+
.arg("--print=cfg")
129+
.output()
130+
.map_err(|err| format!("Error running rustc to get target information: {}", err))?;
131+
if !output.status.success() {
132+
return Err(format!(
133+
"Error running rustc to get target information: {:?}",
134+
output
135+
));
136+
}
137+
let stdout = std::str::from_utf8(&output.stdout)
138+
.map_err(|err| format!("Non-UTF8 stdout from rustc: {:?}", err))?;
139+
140+
let mut values = BTreeMap::new();
141+
142+
for line in stdout.lines() {
143+
if line.starts_with("target_") && line.contains('=') {
144+
let mut parts = line.splitn(2, '=');
145+
// UNWRAP: Verified that line contains = and split into exactly 2 parts.
146+
let key = parts.next().unwrap();
147+
let value = parts.next().unwrap();
148+
if value.starts_with('"') && value.ends_with('"') && value.len() >= 2 {
149+
values
150+
.entry(key)
151+
.or_insert(vec![])
152+
.push(value[1..(value.len() - 1)].to_owned());
153+
}
154+
}
155+
}
156+
157+
Ok(values
158+
.into_iter()
159+
.map(|(key, value)| (format!("CARGO_CFG_{}", key.to_uppercase()), value.join(",")))
160+
.collect())
161+
}
162+
121163
fn absolutify(root: &Path, maybe_relative: OsString) -> OsString {
122164
let path = Path::new(&maybe_relative);
123165
if path.is_relative() {

cargo/cargo_build_script_runner/lib.rs

+53-28
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl BuildScriptOutput {
5959
if key_split.len() <= 1 || key_split[0] != "cargo" {
6060
// Not a cargo directive.
6161
print!("{}", line);
62-
return None
62+
return None;
6363
}
6464
match key_split[1] {
6565
"rustc-link-lib" => Some(BuildScriptOutput::LinkLib(param)),
@@ -68,21 +68,30 @@ impl BuildScriptOutput {
6868
"rustc-flags" => Some(BuildScriptOutput::Flags(param)),
6969
"rustc-env" => Some(BuildScriptOutput::Env(param)),
7070
"rerun-if-changed" | "rerun-if-env-changed" =>
71-
// Ignored because Bazel will re-run if those change all the time.
72-
None,
71+
// Ignored because Bazel will re-run if those change all the time.
72+
{
73+
None
74+
}
7375
"warning" => {
7476
eprintln!("Build Script Warning: {}", split[1]);
7577
None
76-
},
78+
}
7779
"rustc-cdylib-link-arg" => {
7880
// cargo:rustc-cdylib-link-arg=FLAG — Passes custom flags to a linker for cdylib crates.
79-
eprintln!("Warning: build script returned unsupported directive `{}`", split[0]);
81+
eprintln!(
82+
"Warning: build script returned unsupported directive `{}`",
83+
split[0]
84+
);
8085
None
81-
},
86+
}
8287
_ => {
8388
// cargo:KEY=VALUE — Metadata, used by links scripts.
84-
Some(BuildScriptOutput::DepEnv(format!("{}={}", key_split[1].to_uppercase(), param)))
85-
},
89+
Some(BuildScriptOutput::DepEnv(format!(
90+
"{}={}",
91+
key_split[1].to_uppercase(),
92+
param
93+
)))
94+
}
8695
}
8796
}
8897

@@ -101,29 +110,26 @@ impl BuildScriptOutput {
101110

102111
/// Take a [Command], execute it and converts its input into a vector of [BuildScriptOutput]
103112
pub fn from_command(cmd: &mut Command) -> Result<Vec<BuildScriptOutput>, Option<i32>> {
104-
let mut child = cmd.stdout(Stdio::piped()).spawn().expect("Unable to start binary");
113+
let mut child = cmd
114+
.stdout(Stdio::piped())
115+
.spawn()
116+
.expect("Unable to start binary");
105117
let ecode = child.wait().expect("failed to wait on child");
106-
let reader = BufReader::new(
107-
child
108-
.stdout
109-
.as_mut()
110-
.expect("Failed to open stdout"),
111-
);
118+
let reader = BufReader::new(child.stdout.as_mut().expect("Failed to open stdout"));
112119
let output = Self::from_reader(reader);
113120
if ecode.success() {
114121
Ok(output)
115122
} else {
116123
Err(ecode.code())
117124
}
118-
119125
}
120126

121127
/// Convert a vector of [BuildScriptOutput] into a list of environment variables.
122-
pub fn to_env(v: &Vec<BuildScriptOutput>) -> String {
128+
pub fn to_env(v: &Vec<BuildScriptOutput>, exec_root: &str) -> String {
123129
v.iter()
124130
.filter_map(|x| {
125131
if let BuildScriptOutput::Env(env) = x {
126-
Some(env.to_owned())
132+
Some(Self::redact_exec_root(env, exec_root))
127133
} else {
128134
None
129135
}
@@ -137,7 +143,9 @@ impl BuildScriptOutput {
137143
// TODO: make use of `strip_suffix`.
138144
const SYS_CRATE_SUFFIX: &str = "-sys";
139145
let name = if crate_name.ends_with(SYS_CRATE_SUFFIX) {
140-
crate_name.split_at(crate_name.rfind(SYS_CRATE_SUFFIX).unwrap()).0
146+
crate_name
147+
.split_at(crate_name.rfind(SYS_CRATE_SUFFIX).unwrap())
148+
.0
141149
} else {
142150
crate_name
143151
};
@@ -165,14 +173,18 @@ impl BuildScriptOutput {
165173
BuildScriptOutput::Flags(e) => compile_flags.push(e.to_owned()),
166174
BuildScriptOutput::LinkLib(e) => link_flags.push(format!("-l{}", e)),
167175
BuildScriptOutput::LinkSearch(e) => link_flags.push(format!("-L{}", e)),
168-
_ => { },
176+
_ => {}
169177
}
170178
}
171179
CompileAndLinkFlags {
172180
compile_flags: compile_flags.join("\n"),
173-
link_flags: link_flags.join("\n").replace(exec_root, "${pwd}"),
181+
link_flags: Self::redact_exec_root(&link_flags.join("\n"), exec_root),
174182
}
175183
}
184+
185+
fn redact_exec_root(value: &str, exec_root: &str) -> String {
186+
value.replace(exec_root, "${pwd}")
187+
}
176188
}
177189

178190
#[cfg(test)]
@@ -193,30 +205,44 @@ cargo:rerun-if-changed=ignored
193205
cargo:rustc-cfg=feature=awesome
194206
cargo:version=123
195207
cargo:version_number=1010107f
208+
cargo:rustc-env=SOME_PATH=/some/absolute/path/beep
196209
",
197210
);
198211
let reader = BufReader::new(buff);
199212
let result = BuildScriptOutput::from_reader(reader);
200-
assert_eq!(result.len(), 8);
213+
assert_eq!(result.len(), 9);
201214
assert_eq!(result[0], BuildScriptOutput::LinkLib("sdfsdf".to_owned()));
202215
assert_eq!(result[1], BuildScriptOutput::Env("FOO=BAR".to_owned()));
203-
assert_eq!(result[2], BuildScriptOutput::LinkSearch("/some/absolute/path/bleh".to_owned()));
216+
assert_eq!(
217+
result[2],
218+
BuildScriptOutput::LinkSearch("/some/absolute/path/bleh".to_owned())
219+
);
204220
assert_eq!(result[3], BuildScriptOutput::Env("BAR=FOO".to_owned()));
205221
assert_eq!(result[4], BuildScriptOutput::Flags("-Lblah".to_owned()));
206222
assert_eq!(
207223
result[5],
208224
BuildScriptOutput::Cfg("feature=awesome".to_owned())
209225
);
210-
assert_eq!(result[6], BuildScriptOutput::DepEnv("VERSION=123".to_owned()));
211-
assert_eq!(result[7], BuildScriptOutput::DepEnv("VERSION_NUMBER=1010107f".to_owned()));
226+
assert_eq!(
227+
result[6],
228+
BuildScriptOutput::DepEnv("VERSION=123".to_owned())
229+
);
230+
assert_eq!(
231+
result[7],
232+
BuildScriptOutput::DepEnv("VERSION_NUMBER=1010107f".to_owned())
233+
);
234+
assert_eq!(
235+
result[8],
236+
BuildScriptOutput::Env("SOME_PATH=/some/absolute/path/beep".to_owned())
237+
);
212238

213239
assert_eq!(
214240
BuildScriptOutput::to_dep_env(&result, "my-crate-sys"),
215241
"DEP_MY_CRATE_VERSION=123\nDEP_MY_CRATE_VERSION_NUMBER=1010107f".to_owned()
216242
);
217243
assert_eq!(
218-
BuildScriptOutput::to_env(&result),
219-
"FOO=BAR\nBAR=FOO".to_owned()
244+
BuildScriptOutput::to_env(&result, "/some/absolute/path"),
245+
"FOO=BAR\nBAR=FOO\nSOME_PATH=${pwd}/beep".to_owned()
220246
);
221247
assert_eq!(
222248
BuildScriptOutput::to_flags(&result, "/some/absolute/path"),
@@ -228,5 +254,4 @@ cargo:version_number=1010107f
228254
}
229255
);
230256
}
231-
232257
}

0 commit comments

Comments
 (0)