Skip to content

Commit

Permalink
Merge pull request #629 from messense/detect-musl-libc
Browse files Browse the repository at this point in the history
Detect musl libc
  • Loading branch information
messense authored Sep 19, 2021
2 parents 59622cb + a6d8307 commit 971f0de
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 25 deletions.
2 changes: 2 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

* Autodetect PyPy executables in [#617](https://github.com/PyO3/maturin/pull/617)
* auditwheel: add `libz.so.1` to whitelisted libraries in [#625](https://github.com/PyO3/maturin/pull/625)
* auditwheel: detect musl libc in [#629](https://github.com/PyO3/maturin/pull/629)

## [0.11.3] - 2021-08-25

Expand Down
63 changes: 38 additions & 25 deletions src/auditwheel/audit.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::musllinux::{find_musl_libc, get_musl_version};
use super::policy::{Policy, MANYLINUX_POLICIES, MUSLLINUX_POLICIES};
use crate::auditwheel::PlatformTag;
use crate::target::{Arch, Target};
use crate::target::Target;
use anyhow::Result;
use fs_err::File;
use goblin::elf::{sym::STT_FUNC, Elf};
Expand Down Expand Up @@ -195,6 +196,22 @@ fn policy_is_satisfied(
}
}

fn get_default_platform_policies() -> Vec<Policy> {
if let Ok(Some(musl_libc)) = find_musl_libc() {
if let Ok(Some((major, minor))) = get_musl_version(&musl_libc) {
return MUSLLINUX_POLICIES
.iter()
.filter(|policy| {
policy.name == "linux"
|| policy.name == format!("musllinux_{}_{}", major, minor)
})
.cloned()
.collect();
}
}
MANYLINUX_POLICIES.clone()
}

/// An reimplementation of auditwheel, which checks elf files for
/// manylinux/musllinux compliance.
///
Expand Down Expand Up @@ -225,30 +242,26 @@ pub fn auditwheel_rs(

// Find the highest possible policy, if any
let platform_policies = match platform_tag {
Some(PlatformTag::Manylinux { .. }) | None => MANYLINUX_POLICIES.clone(),
Some(PlatformTag::Musllinux { .. }) => {
MUSLLINUX_POLICIES
.clone()
.into_iter()
.map(|mut policy| {
// Fixup musl libc lib_whitelist
if policy.lib_whitelist.remove("libc.so") {
let new_soname = match target.target_arch() {
Arch::Aarch64 => "libc.musl-aarch64.so.1",
Arch::Armv7L => "libc.musl-armv7.so.1",
Arch::Powerpc64Le => "libc.musl-ppc64le.so.1",
Arch::Powerpc64 => "", // musllinux doesn't support ppc64
Arch::X86 => "libc.musl-x86.so.1",
Arch::X86_64 => "libc.musl-x86_64.so.1",
Arch::S390X => "libc.musl-s390x.so.1",
};
if !new_soname.is_empty() {
policy.lib_whitelist.insert(new_soname.to_string());
}
}
policy
})
.collect()
Some(PlatformTag::Manylinux { .. }) => MANYLINUX_POLICIES.clone(),
Some(PlatformTag::Musllinux { x, y }) => MUSLLINUX_POLICIES
.clone()
.into_iter()
.filter(|policy| {
policy.name == "linux" || policy.name == format!("musllinux_{}_{}", x, y)
})
.map(|mut policy| {
policy.fixup_musl_libc_so_name(target.target_arch());
policy
})
.collect(),
None => {
let mut policies = get_default_platform_policies();
for policy in &mut policies {
if policy.name.starts_with("musllinux") {
policy.fixup_musl_libc_so_name(target.target_arch());
}
}
policies
}
Some(PlatformTag::Linux) => unreachable!(),
};
Expand Down
1 change: 1 addition & 0 deletions src/auditwheel/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod audit;
mod musllinux;
mod platform_tag;
mod policy;

Expand Down
47 changes: 47 additions & 0 deletions src/auditwheel/musllinux.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use anyhow::{Context, Result};
use goblin::elf::Elf;
use regex::Regex;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

/// Find musl libc path from executable's ELF header
pub fn find_musl_libc() -> Result<Option<PathBuf>> {
let buffer = fs::read("/bin/ls")?;
let elf = Elf::parse(&buffer)?;
Ok(elf.interpreter.map(PathBuf::from))
}

/// Read the musl version from libc library's output
///
/// The libc library should output something like this to stderr::
///
/// musl libc (x86_64)
/// Version 1.2.2
/// Dynamic Program Loader
pub fn get_musl_version(ld_path: impl AsRef<Path>) -> Result<Option<(u16, u16)>> {
let ld_path = ld_path.as_ref();
let output = Command::new(&ld_path)
.stdout(Stdio::null())
.stderr(Stdio::piped())
.output()?;
let stderr = std::str::from_utf8(&output.stderr)?;
let expr = Regex::new(r"Version (\d+)\.(\d+)")?;
if let Some(capture) = expr.captures(stderr) {
let context = "Expected a digit";
let major = capture
.get(1)
.unwrap()
.as_str()
.parse::<u16>()
.context(context)?;
let minor = capture
.get(2)
.unwrap()
.as_str()
.parse::<u16>()
.context(context)?;
return Ok(Some((major, minor)));
}
Ok(None)
}
19 changes: 19 additions & 0 deletions src/auditwheel/policy.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::auditwheel::PlatformTag;
use crate::target::Arch;
use once_cell::sync::Lazy;
use serde::Deserialize;
use std::cmp::{Ordering, PartialOrd};
Expand Down Expand Up @@ -100,6 +101,24 @@ impl Policy {
.find(|p| p.name == name || p.aliases.iter().any(|alias| alias == name))
.cloned()
}

pub(crate) fn fixup_musl_libc_so_name(&mut self, target_arch: Arch) {
// Fixup musl libc lib_whitelist
if self.lib_whitelist.remove("libc.so") {
let new_soname = match target_arch {
Arch::Aarch64 => "libc.musl-aarch64.so.1",
Arch::Armv7L => "libc.musl-armv7.so.1",
Arch::Powerpc64Le => "libc.musl-ppc64le.so.1",
Arch::Powerpc64 => "", // musllinux doesn't support ppc64
Arch::X86 => "libc.musl-x86.so.1",
Arch::X86_64 => "libc.musl-x86_64.so.1",
Arch::S390X => "libc.musl-s390x.so.1",
};
if !new_soname.is_empty() {
self.lib_whitelist.insert(new_soname.to_string());
}
}
}
}

#[cfg(test)]
Expand Down

0 comments on commit 971f0de

Please sign in to comment.