use super::types::{CacheableLink, LinkOutputKind, LinkerFamily, ParsedLinkerInvocation};
use crate::core::NormalizedPath;
pub(super) fn parse_dsymutil(tool: &str, args: Vec<String>) -> ParsedLinkerInvocation {
if args.iter().any(|arg| {
matches!(
arg.as_str(),
"--codesign"
| "--flat"
| "-f"
| "--no-output"
| "--dump-debug-map"
| "--symtab"
| "-s"
| "-S"
| "--update"
| "-u"
| "--gen-reproducer"
) || arg.starts_with("--codesign=")
|| arg.starts_with("--reproducer")
|| arg.starts_with("--use-reproducer")
|| arg.starts_with("--embed-resource")
}) {
return ParsedLinkerInvocation::NonCacheable {
reason: "dsymutil mode requires signed, mutable, flat, or opaque outputs".to_string(),
};
}
let mut input_files = Vec::new();
let mut output_file = None;
let mut cache_relevant_flags = Vec::new();
let mut index = 0;
while index < args.len() {
let arg = &args[index];
if matches!(arg.as_str(), "-o" | "--out") {
index += 1;
let Some(path) = args.get(index) else {
return ParsedLinkerInvocation::NonCacheable {
reason: "dsymutil output option is missing its path".to_string(),
};
};
output_file = Some(NormalizedPath::new(path));
index += 1;
continue;
}
if let Some(path) = arg.strip_prefix("--out=") {
output_file = Some(NormalizedPath::new(path));
index += 1;
continue;
}
if option_takes_value(arg) {
cache_relevant_flags.push(arg.clone());
index += 1;
let Some(value) = args.get(index) else {
return ParsedLinkerInvocation::NonCacheable {
reason: format!("dsymutil option {arg} is missing its value"),
};
};
cache_relevant_flags.push(value.clone());
index += 1;
continue;
}
if arg.starts_with('-') {
cache_relevant_flags.push(arg.clone());
} else {
input_files.push(NormalizedPath::new(arg));
}
index += 1;
}
if input_files.len() != 1 {
return ParsedLinkerInvocation::NonCacheable {
reason: "dsymutil caching requires exactly one input image".to_string(),
};
}
let output_file = output_file.unwrap_or_else(|| {
NormalizedPath::new(format!("{}.dSYM", input_files[0].to_string_lossy()))
});
ParsedLinkerInvocation::Cacheable(CacheableLink {
tool: NormalizedPath::new(tool),
family: LinkerFamily::Dsymutil,
input_files,
output_file,
output_kind: LinkOutputKind::DirectoryBundle,
secondary_outputs: Vec::new(),
cache_relevant_flags,
original_args: args,
non_deterministic: false,
})
}
fn option_takes_value(option: &str) -> bool {
matches!(
option,
"--accelerator"
| "--allow"
| "--arch"
| "-arch"
| "--build-variant-suffix"
| "-D"
| "--disallow"
| "-j"
| "--num-threads"
| "--object-prefix-map"
| "--oso-prepend-path"
| "--remarks-output-format"
| "--remarks-prepend-path"
| "--toolchain"
)
}