fn generate_compile_commands()

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))
    }