fn remap_generated_filenames()

in src/compiler/nvcc.rs [1117:1217]


fn remap_generated_filenames(
    args: &[String],
    old_to_new: &mut HashMap<String, String>,
    ext_counts: &mut HashMap<String, i32>,
) -> Vec<String> {
    args.iter()
        .map(|arg| {
            // Special case for MSVC's preprocess output file name flag
            let arg_is_msvc_preprocessor_output = arg.starts_with("-Fi");

            let arg = if arg_is_msvc_preprocessor_output {
                arg.trim_start_matches("-Fi").to_owned()
            } else {
                arg.to_owned()
            };

            // If the argument doesn't start with `-` and is a file that
            // ends in one of the below extensions, rename the file to an
            // auto-incrementing stable name
            let maybe_extension = (!arg.starts_with('-'))
                .then(|| {
                    [
                        ".cpp1.ii",
                        ".cpp4.ii",
                        ".cudafe1.c",
                        ".cudafe1.cpp",
                        ".cudafe1.stub.c",
                    ]
                    .iter()
                    .find(|ext| arg.ends_with(*ext))
                    .copied()
                })
                .unwrap_or(None);

            // If the argument is a file that ends in one of the above extensions:
            // * If it's our first time seeing this file, create a unique name for it
            // * If we've seen this file before, lookup its unique name in the hash map
            //
            // This ensures stable names are in cudafe++ output and #include directives,
            // eliminating one source of false-positive cache misses.
            let arg = match maybe_extension {
                Some(extension) => {
                    old_to_new
                        .entry(arg)
                        .or_insert_with_key(|arg| {
                            // Initialize or update the number of files with a given extension:
                            // compute_70.cudafe1.stub.c -> x_0.cudafe1.stub.c
                            // compute_60.cudafe1.stub.c -> x_1.cudafe1.stub.c
                            // etc.
                            let count = ext_counts
                                .entry(extension.into())
                                .and_modify(|c| *c += 1)
                                .or_insert(0)
                                .to_string();
                            // Return `/tmp/dir/x_{count}.{ext}` as the new name, i.e. `/tmp/dir/x_0.cudafe1.stub.c`
                            PathBuf::from(arg)
                                .parent()
                                .unwrap_or(Path::new(""))
                                // Don't use the count as the first character of the file name, because the file name
                                // may be used as an identifier (via the __FILE__ macro) and identifiers with leading
                                // digits are not valid in C/C++, i.e. `x_0.cudafe1.cpp` instead of `0.cudafe1.cpp`.
                                .join("x_".to_owned() + &count + extension)
                                .to_string_lossy()
                                .to_string()
                        })
                        .to_owned()
                }
                None => {
                    // If the argument isn't a file name with one of our extensions,
                    // it may _reference_ files we've renamed. Go through and replace
                    // all old names with their new stable names.
                    //
                    // Sort by string length descending so we don't accidentally replace
                    // `zzz.cudafe1.cpp` with the new name for `zzz.cudafe1.c`.
                    //
                    // For example, if we have these renames:
                    //
                    //   compute_70.cudafe1.cpp -> x_0.cudafe1.cpp
                    //   compute_70.cudafe1.c   -> x_2.cudafe1.c
                    //
                    // `compute_70.cudafe1.cpp` should be replaced with `x_0.cudafe1.cpp`, not `x_2.cudafe1.c`
                    //
                    let mut arg = arg.clone();
                    for (old, new) in old_to_new
                        .iter()
                        .sorted_by(|a, b| b.0.len().cmp(&a.0.len()))
                    {
                        arg = arg.replace(old, new);
                    }
                    arg
                }
            };

            if arg_is_msvc_preprocessor_output {
                format!("-Fi{}", arg)
            } else {
                arg
            }
        })
        .collect::<Vec<_>>()
}