From 12fa9a6ad0699cb665224e040a6c36064bcd8f48 Mon Sep 17 00:00:00 2001 From: Armando Montanez Date: Sun, 2 Nov 2025 14:58:06 -0800 Subject: [PATCH 1/3] Initial libtool support Introduces initial support for linking static archives via macOS's libtool to support cases where AR is explicitly set to libtool or llvm-libtool-darwin. --- src/lib.rs | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 93a3b2c0..0ea25fef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -242,7 +242,6 @@ use std::borrow::Cow; use std::collections::HashMap; -use std::env; use std::ffi::{OsStr, OsString}; use std::fmt::{self, Display}; use std::fs; @@ -253,6 +252,7 @@ use std::sync::{ atomic::{AtomicU8, Ordering::Relaxed}, Arc, RwLock, }; +use std::{env, vec}; use shlex::Shlex; @@ -2657,15 +2657,17 @@ impl Build { } }; } else { - // Non-msvc targets (those using `ar`) need a separate step to add - // the symbol table to archives since our construction command of - // `cq` doesn't add it for us. + // Targets using `ar` need a separate step to add the symbol table + // to archives since our construction command of `cq` doesn't add it + // for us. let mut ar = self.try_get_archiver()?; - // NOTE: We add `s` even if flags were passed using $ARFLAGS/ar_flag, because `s` - // here represents a _mode_, not an arbitrary flag. Further discussion of this choice - // can be seen in https://github.com/rust-lang/cc-rs/pull/763. - run(ar.arg("s").arg(dst), &self.cargo_output)?; + if !ar.get_program().to_string_lossy().contains("libtool") { + // NOTE: We add `s` even if flags were passed using $ARFLAGS/ar_flag, because `s` + // here represents a _mode_, not an arbitrary flag. Further discussion of this choice + // can be seen in https://github.com/rust-lang/cc-rs/pull/763. + run(ar.arg("s").arg(dst), &self.cargo_output)?; + } } Ok(()) @@ -2693,6 +2695,29 @@ impl Build { } cmd.args(objs); run(&mut cmd, &self.cargo_output)?; + } else if program.to_string_lossy().contains("libtool") { + // Build up the basics of the required command line invocation: + // -static: Enables static linking mode. + // -D: Similar to ZERO_AR_DATE, makes the produced archives more deterministic. + // -o: Indicates the following path is the intended output file path. + cmd.arg("-static").arg("-D").arg("-o").arg(dst); + // libtool does not support incrementally updating a static library, so just do + // the obvious alternative and re-merge an archive with itself incrementally. + if fs::exists(dst)? { + let tmp_archive = dst.with_file_name( + dst.file_name() + .expect("Archive file name is invalid") + .to_str() + .unwrap() + .to_owned() + + ".tmp.a", + ); + fs::rename(dst, &tmp_archive)?; + run(cmd.arg(&tmp_archive).args(objs), &self.cargo_output)?; + fs::remove_file(&tmp_archive)?; + } else { + run(cmd.args(objs), &self.cargo_output)?; + } } else { // Set an environment variable to tell the OSX archiver to ensure // that all dates listed in the archive are zero, improving From ca7bb988f0463bee98ede4db63265a214d0501f2 Mon Sep 17 00:00:00 2001 From: Armando Montanez Date: Tue, 25 Nov 2025 17:43:02 -0800 Subject: [PATCH 2/3] Apply cr suggestions --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 0ea25fef..c4bc76b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2703,7 +2703,7 @@ impl Build { cmd.arg("-static").arg("-D").arg("-o").arg(dst); // libtool does not support incrementally updating a static library, so just do // the obvious alternative and re-merge an archive with itself incrementally. - if fs::exists(dst)? { + if dst.exists()? { let tmp_archive = dst.with_file_name( dst.file_name() .expect("Archive file name is invalid") From cc518f42edde39ca414328ce36c76eb713ae8eca Mon Sep 17 00:00:00 2001 From: Armando Montanez Date: Tue, 25 Nov 2025 17:46:50 -0800 Subject: [PATCH 3/3] Fix compile error --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index c4bc76b6..97931235 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2703,7 +2703,7 @@ impl Build { cmd.arg("-static").arg("-D").arg("-o").arg(dst); // libtool does not support incrementally updating a static library, so just do // the obvious alternative and re-merge an archive with itself incrementally. - if dst.exists()? { + if dst.exists() { let tmp_archive = dst.with_file_name( dst.file_name() .expect("Archive file name is invalid")