in cargo/cargo_build_script_runner/bin.rs [26:172]
fn run_buildrs() -> Result<(), String> {
// We use exec_root.join rather than std::fs::canonicalize, to avoid resolving symlinks, as
// some execution strategies and remote execution environments may use symlinks in ways which
// canonicalizing them may break them, e.g. by having input files be symlinks into a /cas
// directory - resolving these may cause tools which inspect $0, or try to resolve files
// relative to themselves, to fail.
let exec_root = env::current_dir().expect("Failed to get current directory");
let manifest_dir_env = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR was not set");
let rustc_env = env::var("RUSTC").expect("RUSTC was not set");
let manifest_dir = exec_root.join(&manifest_dir_env);
let rustc = exec_root.join(&rustc_env);
let Options {
progname,
crate_links,
out_dir,
env_file,
compile_flags_file,
link_flags_file,
output_dep_env_path,
stdout_path,
stderr_path,
input_dep_env_paths,
} = parse_args()?;
let out_dir_abs = exec_root.join(&out_dir);
// For some reason Google's RBE does not create the output directory, force create it.
create_dir_all(&out_dir_abs)
.unwrap_or_else(|_| panic!("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)
.envs(target_env_vars)
.env("OUT_DIR", out_dir_abs)
.env("CARGO_MANIFEST_DIR", manifest_dir)
.env("RUSTC", rustc)
.env("RUST_BACKTRACE", "full");
for dep_env_path in input_dep_env_paths.iter() {
if let Ok(contents) = read_to_string(dep_env_path) {
for line in contents.split('\n') {
// split on empty contents will still produce a single empty string in iterable.
if line.is_empty() {
continue;
}
let mut key_val = line.splitn(2, '=');
match (key_val.next(), key_val.next()) {
(Some(key), Some(value)) => {
command.env(key, value.replace("${pwd}", &exec_root.to_string_lossy()));
}
_ => {
return Err(
"error: Wrong environment file format, should not happen".to_owned()
)
}
}
}
} else {
return Err("error: Dependency environment file unreadable".to_owned());
}
}
for compiler_env_var in &["CC", "CXX"] {
if let Some(compiler_path) = env::var_os(compiler_env_var) {
let mut compiler_path = exec_root.join(compiler_path).into_os_string();
if let Some(sysroot_path) = env::var_os("SYSROOT") {
compiler_path.push(" --sysroot=");
compiler_path.push(&exec_root.join(sysroot_path));
}
command.env(compiler_env_var, compiler_path);
}
}
if let Some(ar_path) = env::var_os("AR") {
// The default OSX toolchain uses libtool as ar_executable not ar.
// This doesn't work when used as $AR, so simply don't set it - tools will probably fall back to
// /usr/bin/ar which is probably good enough.
if Path::new(&ar_path).file_name() == Some("libtool".as_ref()) {
command.env_remove("AR");
} else {
command.env("AR", exec_root.join(ar_path));
}
}
if let Some(ld_path) = env::var_os("LD") {
command.env("LD", exec_root.join(ld_path));
}
// replace env vars with a ${pwd} prefix with the exec_root
for (key, value) in env::vars() {
let exec_root_str = exec_root.to_str().expect("exec_root not in utf8");
if value.contains("${pwd}") {
env::set_var(key, value.replace("${pwd}", exec_root_str));
}
}
let (buildrs_outputs, process_output) = BuildScriptOutput::outputs_from_command(&mut command)
.map_err(|process_output| {
format!(
"Build script process failed{}\n--stdout:\n{}\n--stderr:\n{}",
if let Some(exit_code) = process_output.status.code() {
format!(" with exit code {}", exit_code)
} else {
String::new()
},
String::from_utf8(process_output.stdout)
.expect("Failed to parse stdout of child process"),
String::from_utf8(process_output.stderr)
.expect("Failed to parse stdout of child process"),
)
})?;
write(
&env_file,
BuildScriptOutput::outputs_to_env(&buildrs_outputs, &exec_root.to_string_lossy())
.as_bytes(),
)
.unwrap_or_else(|_| panic!("Unable to write file {:?}", env_file));
write(
&output_dep_env_path,
BuildScriptOutput::outputs_to_dep_env(
&buildrs_outputs,
&crate_links,
&exec_root.to_string_lossy(),
)
.as_bytes(),
)
.unwrap_or_else(|_| panic!("Unable to write file {:?}", output_dep_env_path));
write(&stdout_path, process_output.stdout)
.unwrap_or_else(|_| panic!("Unable to write file {:?}", stdout_path));
write(&stderr_path, process_output.stderr)
.unwrap_or_else(|_| panic!("Unable to write file {:?}", stderr_path));
let CompileAndLinkFlags {
compile_flags,
link_flags,
} = BuildScriptOutput::outputs_to_flags(&buildrs_outputs, &exec_root.to_string_lossy());
write(&compile_flags_file, compile_flags.as_bytes())
.unwrap_or_else(|_| panic!("Unable to write file {:?}", compile_flags_file));
write(&link_flags_file, link_flags.as_bytes())
.unwrap_or_else(|_| panic!("Unable to write file {:?}", link_flags_file));
Ok(())
}