Skip to content

Commit

Permalink
Handle archived dylibs on AIX (#2442)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
daltenty authored Jan 20, 2025
1 parent 243b9f5 commit a1e9d6f
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 0 deletions.
44 changes: 44 additions & 0 deletions src/module_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,28 @@ fn handle_cffi_call_result(
}
}

// Extract the shared object from a AIX big library archive
fn unpack_big_archive(target: &Target, artifact: &Path, temp_dir_path: &Path) -> Result<PathBuf> {
// Newer rust generates archived dylibs on AIX, as shared
// libraries are typically archived on the platform.
if target.cross_compiling() {
bail!("can't unpack big archive format while cross_compiling")
}
debug!("Unpacking archive {}", artifact.display());
let mut ar_command = Command::new("ar");
ar_command
.current_dir(temp_dir_path)
.arg("-X64")
.arg("x")
.arg(artifact);
let status = ar_command.status().expect("Failed to run ar");
if !status.success() {
bail!(r#"ar finished with "{}": `{:?}`"#, status, ar_command,)
}
let unpacked_artifact = temp_dir_path.join(artifact.with_extension("so").file_name().unwrap());
Ok(unpacked_artifact)
}

/// Copies the shared library into the module, which is the only extra file needed with bindings
#[allow(clippy::too_many_arguments)]
#[instrument(skip_all)]
Expand Down Expand Up @@ -825,6 +847,28 @@ pub fn write_bindings_module(
python_interpreter.get_library_name(ext_name)
};

let artifact_is_big_ar =
target.is_aix() && artifact.extension().unwrap_or(OsStr::new(" ")) == OsStr::new("a");
let temp_dir = if artifact_is_big_ar {
Some(tempfile::tempdir()?)
} else {
None
};
let artifact_buff = if artifact_is_big_ar {
Some(unpack_big_archive(
target,
artifact,
temp_dir.as_ref().unwrap().path(),
)?)
} else {
None
};
let artifact = if artifact_is_big_ar {
artifact_buff.as_ref().unwrap()
} else {
artifact
};

if !editable {
write_python_part(writer, project_layout, pyproject_toml)
.context("Failed to add the python module to the package")?;
Expand Down
6 changes: 6 additions & 0 deletions src/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,12 @@ impl Target {
self.os == Os::Hurd
}

/// Returns true if we're building a binary for AIX
#[inline]
pub fn is_aix(&self) -> bool {
self.os == Os::Aix
}

/// Returns true if the current platform's target env is Musl
#[inline]
pub fn is_musl_libc(&self) -> bool {
Expand Down

0 comments on commit a1e9d6f

Please sign in to comment.