in src/compiler/rust.rs [1683:1829]
fn generate_compile_commands(
&self,
path_transformer: &mut dist::PathTransformer,
_rewrite_includes_only: bool,
) -> Result<(
Box<dyn CompileCommand<T>>,
Option<dist::CompileCommand>,
Cacheable,
)> {
let RustCompilation {
ref executable,
ref arguments,
ref crate_name,
ref cwd,
ref env_vars,
ref host,
ref sysroot,
..
} = *self;
// Ignore unused variables
#[cfg(not(feature = "dist-client"))]
{
let _ = path_transformer;
let _ = host;
let _ = sysroot;
}
trace!("[{}]: compile", crate_name);
let command = SingleCompileCommand {
executable: executable.to_owned(),
arguments: arguments
.iter()
.flat_map(|arg| arg.iter_os_strings())
.collect(),
env_vars: env_vars.to_owned(),
cwd: cwd.to_owned(),
};
#[cfg(not(feature = "dist-client"))]
let dist_command = None;
#[cfg(feature = "dist-client")]
let dist_command = (|| {
macro_rules! try_string_arg {
($e:expr) => {
match $e {
Ok(s) => s,
Err(e) => {
debug!("Conversion failed for distributed compile argument: {}", e);
return None;
}
}
};
}
let mut dist_arguments = vec![];
let mut saw_target = false;
// flat_map would be nice but the lifetimes don't work out
for argument in arguments.iter() {
let path_transformer_fn = &mut |p: &Path| path_transformer.as_dist(p);
if let Argument::Raw(input_path) = argument {
// Need to explicitly handle the input argument as it's not parsed as a path
let input_path = Path::new(input_path).to_owned();
dist_arguments.push(try_string_arg!(
input_path.into_arg_string(path_transformer_fn)
))
} else {
if let Some(Target(_)) = argument.get_data() {
saw_target = true
}
for string_arg in argument.iter_strings(path_transformer_fn) {
dist_arguments.push(try_string_arg!(string_arg))
}
}
}
// We can't rely on the packaged toolchain necessarily having the same default target triple
// as us (typically host triple), so make sure to always explicitly specify a target.
if !saw_target {
dist_arguments.push(format!("--target={}", host))
}
// Convert the paths of some important environment variables
let mut env_vars = dist::osstring_tuples_to_strings(env_vars)?;
let mut changed_out_dir: Option<PathBuf> = None;
for (k, v) in env_vars.iter_mut() {
match k.as_str() {
// We round-tripped from path to string and back to path, but it should be lossless
"OUT_DIR" => {
let dist_out_dir = path_transformer.as_dist(Path::new(v))?;
if dist_out_dir != *v {
changed_out_dir = Some(v.to_owned().into());
}
*v = dist_out_dir
}
"TMPDIR" => {
// The server will need to find its own tempdir.
*v = "".to_string();
}
"CARGO" | "CARGO_MANIFEST_DIR" => {
*v = path_transformer.as_dist(Path::new(v))?
}
_ => (),
}
}
// OUT_DIR was changed during transformation, check if this compilation is relying on anything
// inside it - if so, disallow distributed compilation (there are sometimes hardcoded paths present)
if let Some(out_dir) = changed_out_dir {
if self.inputs.iter().any(|input| input.starts_with(&out_dir)) {
return None;
}
}
// Add any necessary path transforms - although we haven't packaged up inputs yet, we've
// probably seen all drives (e.g. on Windows), so let's just transform those rather than
// trying to do every single path.
let mut remapped_disks = HashSet::new();
for (local_path, dist_path) in get_path_mappings(path_transformer) {
let local_path = local_path.to_str()?;
// "The from=to parameter is scanned from right to left, so from may contain '=', but to may not."
if local_path.contains('=') {
return None;
}
if remapped_disks.contains(&dist_path) {
continue;
}
dist_arguments.push(format!("--remap-path-prefix={}={}", &dist_path, local_path));
remapped_disks.insert(dist_path);
}
let sysroot_executable = sysroot
.join(BINS_DIR)
.join("rustc")
.with_extension(EXE_EXTENSION);
Some(dist::CompileCommand {
executable: path_transformer.as_dist(&sysroot_executable)?,
arguments: dist_arguments,
env_vars,
cwd: path_transformer.as_dist_abs(cwd)?,
})
})();
Ok((CCompileCommand::new(command), dist_command, Cacheable::Yes))
}