use std::env;
fn extract_lib_from_filename<'a>(target: &str, filename: &'a str) -> Option<&'a str> {
fn test_suffixes<'b>(filename: &'b str, suffixes: &[&str]) -> Option<&'b str> {
for suffix in suffixes {
if let Some(lib_basename) = filename.strip_suffix(suffix) {
return Some(lib_basename);
}
}
None
}
let prefix = "lib";
#[allow(clippy::collapsible_else_if)]
if target.contains("msvc") {
test_suffixes(filename, &[".lib"])
} else if target.contains("windows") && target.contains("gnu") {
if let Some(filename) = filename.strip_prefix(prefix) {
test_suffixes(filename, &[".dll.a", ".dll", ".lib", ".a"])
} else {
test_suffixes(filename, &[".dll.a", ".dll", ".lib"])
}
} else if target.contains("apple") {
if let Some(filename) = filename.strip_prefix(prefix) {
test_suffixes(filename, &[".a", ".so", ".dylib"])
} else {
None
}
} else {
if let Some(filename) = filename.strip_prefix(prefix) {
test_suffixes(filename, &[".a", ".so"])
} else {
None
}
}
}
fn split_flags(link_args: &[u8]) -> Vec<String> {
let mut word = Vec::new();
let mut words = Vec::new();
let mut escaped = false;
for &b in link_args {
match b {
_ if escaped => {
escaped = false;
word.push(b);
}
b'\\' => escaped = true,
b'\t' | b'\n' | b'\r' | b' ' => {
if !word.is_empty() {
words.push(String::from_utf8(word).unwrap());
word = Vec::new();
}
}
_ => word.push(b),
}
}
if !word.is_empty() {
words.push(String::from_utf8(word).unwrap());
}
words
}
pub(crate) fn parse_libs_cflags(name: &str, link_args: &[u8]) {
let mut is_msvc = false;
let target = env::var("TARGET");
if let Ok(target) = &target {
if target.contains("msvc") {
is_msvc = true;
}
}
let words = split_flags(link_args);
let parts = words
.iter()
.filter(|l| l.len() > 2)
.map(|arg| (&arg[0..2], &arg[2..]));
for (flag, val) in parts {
match flag {
"-L" => {
println!("cargo:rustc-link-search=native={}", val);
}
"-F" => {
println!("cargo:rustc-link-search=framework={}", val);
}
"-I" => (),
"-l" => {
if is_msvc && ["m", "c", "pthread"].contains(&val) {
continue;
}
println!("cargo:rustc-link-lib={}", val);
}
"-D" => (),
_ => {}
}
}
let mut iter = words.iter().flat_map(|arg| {
if let Some(arg) = arg.strip_prefix("-Wl,") {
arg.split(',').collect()
} else {
vec![arg.as_ref()]
}
});
while let Some(part) = iter.next() {
match part {
"-framework" => {
if let Some(lib) = iter.next() {
println!("cargo:rustc-link-lib=framework={}", lib);
}
}
"-isystem" | "-iquote" | "-idirafter" => {}
_ => {
let path = std::path::Path::new(part);
if path.is_file() {
if let (Some(dir), Some(file_name), Ok(target)) =
(path.parent(), path.file_name(), &target)
{
match extract_lib_from_filename(target, &file_name.to_string_lossy()) {
Some(lib_basename) => {
println!("cargo:rustc-link-search={}", dir.display());
println!("cargo:rustc-link-lib={}", lib_basename);
}
None => {
println!("cargo:warning=File path {} found in .prl file for {}, but could not extract library base name to pass to linker command line", path.display(), name);
}
}
}
}
}
}
}
let linker_options = words.iter().filter(|arg| arg.starts_with("-Wl,"));
for option in linker_options {
let mut pop = false;
let mut ld_option = vec![];
for subopt in option[4..].split(',') {
if pop {
pop = false;
continue;
}
if subopt == "-framework" {
pop = true;
continue;
}
ld_option.push(subopt);
}
println!("cargo:rustc-link-arg=-Wl,{}", ld_option.join(","));
}
}