Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for repairing cross compiled linux wheels #754

Merged
merged 4 commits into from
Dec 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 12 additions & 21 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ ignore = "0.4.18"
dialoguer = "0.9.0"
console = "0.15.0"
minijinja = "0.8.2"
lddtree = "0.1.4"
lddtree = "0.2.0"
cc = "1.0.72"

[dev-dependencies]
indoc = "1.0.3"
Expand Down
2 changes: 2 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

* Add support for repairing cross compiled linux wheels in [#754](https://github.com/PyO3/maturin/pull/754)

## [0.12.5] - 2021-12-20

* Fix docs for `new` and `init` commands in `maturin --help` in [#734](https://github.com/PyO3/maturin/pull/734)
Expand Down
25 changes: 7 additions & 18 deletions src/auditwheel/audit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,6 @@ pub fn auditwheel_rs(
if !target.is_linux() || platform_tag == Some(PlatformTag::Linux) {
return Ok((Policy::default(), false));
}
let cross_compiling = target.cross_compiling();
let arch = target.target_arch().to_string();
let mut file = File::open(path).map_err(AuditWheelError::IoError)?;
let mut buffer = Vec::new();
Expand Down Expand Up @@ -300,15 +299,10 @@ pub fn auditwheel_rs(
should_repair = false;
break;
}
Err(err @ AuditWheelError::LinksForbiddenLibrariesError(..)) => {
// TODO: support repair for cross compiled wheels
if !cross_compiling {
highest_policy = Some(policy.clone());
should_repair = true;
break;
} else {
return Err(err);
}
Err(AuditWheelError::LinksForbiddenLibrariesError(..)) => {
highest_policy = Some(policy.clone());
should_repair = true;
break;
}
Err(AuditWheelError::VersionedSymbolTooNewError(..))
| Err(AuditWheelError::BlackListedSymbolsError(..))
Expand Down Expand Up @@ -340,14 +334,9 @@ pub fn auditwheel_rs(
should_repair = false;
Ok(policy)
}
Err(err @ AuditWheelError::LinksForbiddenLibrariesError(..)) => {
// TODO: support repair for cross compiled wheels
if !cross_compiling {
should_repair = true;
Ok(policy)
} else {
Err(err)
}
Err(AuditWheelError::LinksForbiddenLibrariesError(..)) => {
should_repair = true;
Ok(policy)
}
Err(err) => Err(err),
}
Expand Down
2 changes: 1 addition & 1 deletion src/auditwheel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ mod repair;
pub use audit::*;
pub use platform_tag::PlatformTag;
pub use policy::{Policy, MANYLINUX_POLICIES, MUSLLINUX_POLICIES};
pub use repair::{get_external_libs, hash_file};
pub use repair::{find_external_libs, hash_file};
7 changes: 4 additions & 3 deletions src/auditwheel/repair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ use fs_err as fs;
use lddtree::DependencyAnalyzer;
use sha2::{Digest, Sha256};
use std::io;
use std::path::Path;
use std::path::{Path, PathBuf};

pub fn get_external_libs(
pub fn find_external_libs(
artifact: impl AsRef<Path>,
policy: &Policy,
sysroot: PathBuf,
) -> Result<Vec<lddtree::Library>, AuditWheelError> {
let dep_analyzer = DependencyAnalyzer::new();
let dep_analyzer = DependencyAnalyzer::new(sysroot);
let deps = dep_analyzer.analyze(artifact).unwrap();
let mut ext_libs = Vec::new();
for (name, lib) in deps.libraries {
Expand Down
50 changes: 48 additions & 2 deletions src/build_context.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::auditwheel::{
auditwheel_rs, get_external_libs, hash_file, patchelf, PlatformTag, Policy,
auditwheel_rs, find_external_libs, hash_file, patchelf, PlatformTag, Policy,
};
use crate::compile::warn_missing_py_init;
use crate::module_writer::{
Expand All @@ -15,6 +15,7 @@ use lddtree::Library;
use std::borrow::Cow;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

/// The way the rust code is used in the wheel
#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -272,7 +273,8 @@ impl BuildContext {
}
})?;
let external_libs = if should_repair && !self.editable {
get_external_libs(&artifact, &policy).with_context(|| {
let sysroot = get_sysroot_path(&self.target)?;
find_external_libs(&artifact, &policy, sysroot).with_context(|| {
if let Some(platform_tag) = platform_tag {
format!("Error repairing wheel for {} compliance", platform_tag)
} else {
Expand Down Expand Up @@ -685,6 +687,50 @@ fn relpath(to: &Path, from: &Path) -> PathBuf {
result
}

/// Get sysroot path from target C compiler
///
/// Currently only gcc is supported, clang doesn't have a `--print-sysroot` option
/// TODO: allow specify sysroot from environment variable?
fn get_sysroot_path(target: &Target) -> Result<PathBuf> {
use crate::target::get_host_target;

let host_triple = get_host_target()?;
let target_triple = target.target_triple();
if host_triple != target_triple {
let mut build = cc::Build::new();
build
// Suppress cargo metadata for example env vars printing
.cargo_metadata(false)
// opt_level, host and target are required
.opt_level(0)
.host(&host_triple)
.target(target_triple);
let compiler = build
.try_get_compiler()
.with_context(|| format!("Failed to get compiler for {}", target_triple))?;
let path = compiler.path();
let out = Command::new(path)
.arg("--print-sysroot")
.stdout(Stdio::piped())
.stderr(Stdio::null())
.output()
.with_context(|| format!("Failed to run `{} --print-sysroot`", path.display()))?;
if out.status.success() {
let sysroot = String::from_utf8(out.stdout)
.context("Failed to read the sysroot path")?
.trim()
.to_owned();
return Ok(PathBuf::from(sysroot));
} else {
bail!(
"Failed to get the sysroot path: {}",
String::from_utf8(out.stderr)?
);
}
}
Ok(PathBuf::from("/"))
}

#[cfg(test)]
mod test {
use super::relpath;
Expand Down