Skip to content

Commit a1e9d6f

Browse files
authored
Handle archived dylibs on AIX (#2442)
In recent Rust versions, the dylib format for AIX has changed to reflect that shared libraries on AIX are normal archived, in the Big archive format. See rust-lang/rust#132362. However, Python wheels on the platforms still use un-archived shared objects, so this change updates module_writer to unarchive the archived dylib before we copy it over to the wheel.
1 parent 243b9f5 commit a1e9d6f

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

src/module_writer.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,28 @@ fn handle_cffi_call_result(
793793
}
794794
}
795795

796+
// Extract the shared object from a AIX big library archive
797+
fn unpack_big_archive(target: &Target, artifact: &Path, temp_dir_path: &Path) -> Result<PathBuf> {
798+
// Newer rust generates archived dylibs on AIX, as shared
799+
// libraries are typically archived on the platform.
800+
if target.cross_compiling() {
801+
bail!("can't unpack big archive format while cross_compiling")
802+
}
803+
debug!("Unpacking archive {}", artifact.display());
804+
let mut ar_command = Command::new("ar");
805+
ar_command
806+
.current_dir(temp_dir_path)
807+
.arg("-X64")
808+
.arg("x")
809+
.arg(artifact);
810+
let status = ar_command.status().expect("Failed to run ar");
811+
if !status.success() {
812+
bail!(r#"ar finished with "{}": `{:?}`"#, status, ar_command,)
813+
}
814+
let unpacked_artifact = temp_dir_path.join(artifact.with_extension("so").file_name().unwrap());
815+
Ok(unpacked_artifact)
816+
}
817+
796818
/// Copies the shared library into the module, which is the only extra file needed with bindings
797819
#[allow(clippy::too_many_arguments)]
798820
#[instrument(skip_all)]
@@ -825,6 +847,28 @@ pub fn write_bindings_module(
825847
python_interpreter.get_library_name(ext_name)
826848
};
827849

850+
let artifact_is_big_ar =
851+
target.is_aix() && artifact.extension().unwrap_or(OsStr::new(" ")) == OsStr::new("a");
852+
let temp_dir = if artifact_is_big_ar {
853+
Some(tempfile::tempdir()?)
854+
} else {
855+
None
856+
};
857+
let artifact_buff = if artifact_is_big_ar {
858+
Some(unpack_big_archive(
859+
target,
860+
artifact,
861+
temp_dir.as_ref().unwrap().path(),
862+
)?)
863+
} else {
864+
None
865+
};
866+
let artifact = if artifact_is_big_ar {
867+
artifact_buff.as_ref().unwrap()
868+
} else {
869+
artifact
870+
};
871+
828872
if !editable {
829873
write_python_part(writer, project_layout, pyproject_toml)
830874
.context("Failed to add the python module to the package")?;

src/target.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,12 @@ impl Target {
616616
self.os == Os::Hurd
617617
}
618618

619+
/// Returns true if we're building a binary for AIX
620+
#[inline]
621+
pub fn is_aix(&self) -> bool {
622+
self.os == Os::Aix
623+
}
624+
619625
/// Returns true if the current platform's target env is Musl
620626
#[inline]
621627
pub fn is_musl_libc(&self) -> bool {

0 commit comments

Comments
 (0)