use super::types::{CacheableLink, LinkerFamily, ParsedLinkerInvocation};
use crate::core::NormalizedPath;
const OBJECT_EXTENSIONS: &[&str] = &["o", "obj", "a", "lib", "lo", "so", "dylib", "dll"];
fn is_linker_input(path: &str) -> bool {
if let Some(ext) = std::path::Path::new(path)
.extension()
.and_then(|e| e.to_str())
{
OBJECT_EXTENSIONS.contains(&ext)
} else {
false
}
}
pub(super) fn parse_compiler_driver_link(tool: &str, args: Vec<String>) -> ParsedLinkerInvocation {
if args.is_empty() {
return ParsedLinkerInvocation::NonCacheable {
reason: "no arguments".to_string(),
};
}
let mut has_compile_only = false;
let mut output_file: Option<NormalizedPath> = None;
let mut input_files: Vec<NormalizedPath> = Vec::new();
let mut cache_relevant_flags: Vec<String> = Vec::new();
let mut has_build_id_uuid = false;
let mut secondary_outputs: Vec<NormalizedPath> = Vec::new();
let mut i = 0;
while i < args.len() {
let arg = &args[i];
if arg == "-shared" || arg == "--shared" {
cache_relevant_flags.push(arg.clone());
i += 1;
continue;
}
if arg == "-c" {
has_compile_only = true;
i += 1;
continue;
}
if arg == "-o" {
i += 1;
if i < args.len() {
output_file = Some(NormalizedPath::new(&args[i]));
}
i += 1;
continue;
}
if arg.starts_with("-Wl,") {
for part in arg.split(',') {
if part == "--build-id=uuid" {
has_build_id_uuid = true;
}
if let Some(implib) = part.strip_prefix("--out-implib=") {
secondary_outputs.push(NormalizedPath::new(implib));
}
}
cache_relevant_flags.push(arg.clone());
i += 1;
continue;
}
if arg == "-L" {
cache_relevant_flags.push(arg.clone());
i += 1;
if i < args.len() {
cache_relevant_flags.push(args[i].clone());
}
i += 1;
continue;
}
if arg.starts_with("-L") {
cache_relevant_flags.push(arg.clone());
i += 1;
continue;
}
if arg.starts_with("-l") {
cache_relevant_flags.push(arg.clone());
i += 1;
continue;
}
if arg == "-target" || arg == "--target" || arg == "-isysroot" {
cache_relevant_flags.push(arg.clone());
i += 1;
if i < args.len() {
cache_relevant_flags.push(args[i].clone());
}
i += 1;
continue;
}
if arg.starts_with('-') {
cache_relevant_flags.push(arg.clone());
i += 1;
continue;
}
if is_linker_input(arg) {
input_files.push(NormalizedPath::new(arg));
}
i += 1;
}
if has_compile_only {
return ParsedLinkerInvocation::NonCacheable {
reason: "-c flag present (compilation, not linking)".to_string(),
};
}
let output_file = match output_file {
Some(f) => f,
None => {
return ParsedLinkerInvocation::NonCacheable {
reason: "no output file specified (-o)".to_string(),
};
}
};
if input_files.is_empty() {
return ParsedLinkerInvocation::NonCacheable {
reason: "no input files specified".to_string(),
};
}
ParsedLinkerInvocation::Cacheable(CacheableLink {
tool: NormalizedPath::new(tool),
family: LinkerFamily::CompilerDriver,
input_files,
output_file,
secondary_outputs,
cache_relevant_flags,
original_args: args,
non_deterministic: has_build_id_uuid,
})
}