Skip to content
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
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ flate2 = "1.0.18"
goblin = "0.9.0"
platform-info = "2.0.2"
regex = "1.7.0"
rustflags = "0.1.6"
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.114"
sha2 = "0.10.3"
Expand Down
111 changes: 110 additions & 1 deletion src/auditwheel/audit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ pub fn get_policy_and_libs(
artifact: &BuildArtifact,
platform_tag: Option<PlatformTag>,
target: &Target,
manifest_path: &Path,
allow_linking_libpython: bool,
) -> Result<(Policy, Vec<Library>)> {
let (policy, should_repair) =
Expand All @@ -487,7 +488,13 @@ pub fn get_policy_and_libs(
)?;
let external_libs = if should_repair {
let sysroot = get_sysroot_path(target).unwrap_or_else(|_| PathBuf::from("/"));
let ld_paths = artifact.linked_paths.iter().map(PathBuf::from).collect();
let mut ld_paths: Vec<PathBuf> = artifact.linked_paths.iter().map(PathBuf::from).collect();

// Add library search paths from RUSTFLAGS
if let Some(rustflags_paths) = extract_rustflags_library_paths(manifest_path, target) {
ld_paths.extend(rustflags_paths);
}

let external_libs = find_external_libs(&artifact.path, &policy, sysroot, ld_paths)
.with_context(|| {
if let Some(platform_tag) = platform_tag {
Expand All @@ -510,6 +517,30 @@ pub fn get_policy_and_libs(
Ok((policy, external_libs))
}

/// Extract library search paths from RUSTFLAGS configuration
#[cfg_attr(test, allow(dead_code))]
fn extract_rustflags_library_paths(manifest_path: &Path, target: &Target) -> Option<Vec<PathBuf>> {
let manifest_dir = manifest_path.parent()?;
let config = cargo_config2::Config::load_with_cwd(manifest_dir).ok()?;
let rustflags = config.rustflags(target.target_triple()).ok()??;

// Encode the rustflags for parsing with the rustflags crate
let encoded = rustflags.encode().ok()?;

let mut library_paths = Vec::new();
for flag in rustflags::from_encoded(encoded.as_ref()) {
if let rustflags::Flag::LibrarySearchPath { kind: _, path } = flag {
library_paths.push(path);
}
}

if library_paths.is_empty() {
None
} else {
Some(library_paths)
}
}

pub fn relpath(to: &Path, from: &Path) -> PathBuf {
let mut suffix_pos = 0;
for (f, t) in from.components().zip(to.components()) {
Expand All @@ -534,6 +565,7 @@ pub fn relpath(to: &Path, from: &Path) -> PathBuf {
#[cfg(test)]
mod test {
use crate::auditwheel::audit::relpath;
use crate::Target;
use pretty_assertions::assert_eq;
use std::path::Path;

Expand All @@ -551,4 +583,81 @@ mod test {
assert_eq!(result, Path::new(expected));
}
}

#[test]
fn test_extract_rustflags_library_paths() {
// Create a temporary directory with a Cargo.toml and .cargo/config.toml
let temp_dir = tempfile::tempdir().unwrap();
let manifest_path = temp_dir.path().join("Cargo.toml");
let cargo_dir = temp_dir.path().join(".cargo");
let config_path = cargo_dir.join("config.toml");

// Create the directories
fs_err::create_dir_all(&cargo_dir).unwrap();

// Create a minimal Cargo.toml
fs_err::write(
&manifest_path,
r#"
[package]
name = "test-package"
version = "0.1.0"
edition = "2021"
"#,
)
.unwrap();

// Create a config.toml with rustflags containing -L options
fs_err::write(
&config_path,
r#"
[build]
rustflags = ["-L", "dependency=/usr/local/lib", "-L", "/some/other/path", "-C", "opt-level=3"]
"#,
)
.unwrap();

// Test the function
let target = Target::from_target_triple(None).unwrap();
let paths = super::extract_rustflags_library_paths(&manifest_path, &target);

if let Some(paths) = paths {
assert_eq!(paths.len(), 2);
assert!(paths
.iter()
.any(|p| p.to_string_lossy() == "/usr/local/lib"));
assert!(paths
.iter()
.any(|p| p.to_string_lossy() == "/some/other/path"));
} else {
// It's possible that rustflags parsing fails in some environments,
// so we just verify the function doesn't panic
println!("No rustflags library paths found, which is acceptable");
}
}

#[test]
fn test_extract_rustflags_library_paths_no_config() {
// Test with a directory that has no cargo config
let temp_dir = tempfile::tempdir().unwrap();
let manifest_path = temp_dir.path().join("Cargo.toml");

// Create a minimal Cargo.toml
fs_err::write(
&manifest_path,
r#"
[package]
name = "test-package"
version = "0.1.0"
edition = "2021"
"#,
)
.unwrap();

let target = Target::from_target_triple(None).unwrap();
let paths = super::extract_rustflags_library_paths(&manifest_path, &target);

// Should return None when there's no cargo config with rustflags
assert!(paths.is_none());
}
}
9 changes: 8 additions & 1 deletion src/build_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,12 +345,19 @@ impl BuildContext {
artifact,
Some(musllinux[0]),
&self.target,
&self.manifest_path,
allow_linking_libpython,
);
}

let tag = others.first().or_else(|| musllinux.first()).copied();
get_policy_and_libs(artifact, tag, &self.target, allow_linking_libpython)
get_policy_and_libs(
artifact,
tag,
&self.target,
&self.manifest_path,
allow_linking_libpython,
)
}

/// Add library search paths in Cargo target directory rpath when building in editable mode
Expand Down
Loading