Skip to content

Commit

Permalink
feat: move rpath_allowlist and relocate_paths to GlobVec (#542)
Browse files Browse the repository at this point in the history
  • Loading branch information
wolfv authored Jan 25, 2024
1 parent b847458 commit 51280f7
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 69 deletions.
37 changes: 24 additions & 13 deletions src/linux/link.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Relink shared objects to use an relative path prefix
use globset::GlobMatcher;
use globset::GlobSet;
use goblin::elf::{Dyn, Elf};
use goblin::elf64::header::ELFMAG;
use goblin::strtab::Strtab;
Expand Down Expand Up @@ -92,7 +92,7 @@ impl SharedObject {
prefix: &Path,
encoded_prefix: &Path,
custom_rpaths: &[String],
rpath_allowlist: &[GlobMatcher],
rpath_allowlist: Option<&GlobSet>,
) -> Result<(), RelinkError> {
if !self.has_dynamic {
tracing::debug!("{} is not dynamically linked", self.path.display());
Expand Down Expand Up @@ -134,7 +134,10 @@ impl SharedObject {
"$ORIGIN/{}",
relative_path.to_string_lossy()
)));
} else if rpath_allowlist.iter().any(|glob| glob.is_match(rpath)) {
} else if rpath_allowlist
.map(|glob| glob.is_match(rpath))
.unwrap_or(false)
{
tracing::info!("rpath ({:?}) for {:?} found in allowlist", rpath, self.path);
final_rpath.push(rpath.clone());
} else {
Expand Down Expand Up @@ -339,6 +342,7 @@ fn relink(elf_path: &Path, new_rpath: &[PathBuf]) -> Result<(), RelinkError> {
#[cfg(test)]
mod test {
use super::*;
use globset::{Glob, GlobSetBuilder};
use std::{fs, path::Path};
use tempfile::tempdir_in;

Expand All @@ -350,27 +354,30 @@ mod test {
// prefix: "test-data/binary_files"
// new rpath: $ORIGIN/../lib
#[test]
#[cfg(target_os = "linux")]
fn relink_patchelf() -> Result<(), RelinkError> {
use globset::Glob;
if which::which("patchelf").is_err() {
tracing::warn!("patchelf not found, skipping test");
return Ok(());
}

// copy binary to a temporary directory
let prefix = Path::new(env!("CARGO_MANIFEST_DIR")).join("test-data/binary_files");
let tmp_dir = tempdir_in(&prefix)?.into_path();
let binary_path = tmp_dir.join("zlink");
fs::copy(prefix.join("zlink"), &binary_path)?;

let globset = GlobSetBuilder::new()
.add(Glob::new("/usr/lib/custom**").unwrap())
.build()
.unwrap();

// default rpaths of the test binary are:
// - /rattler-build_zlink/host_env_placehold/lib
// - /rattler-build_zlink/build_env/lib
// so we are expecting it to keep the host prefix and discard the build prefix
let encoded_prefix = Path::new("/rattler-build_zlink/host_env_placehold");
let object = SharedObject::new(&binary_path)?;
object.relink(
&prefix,
encoded_prefix,
&[],
&[Glob::new("/usr/lib/custom**").unwrap().compile_matcher()],
)?;
object.relink(&prefix, encoded_prefix, &[], Some(&globset))?;
let object = SharedObject::new(&binary_path)?;
assert_eq!(
vec!["$ORIGIN/../lib", "/usr/lib/custom_lib"],
Expand All @@ -394,8 +401,12 @@ mod test {
// prefix: "test-data/binary_files"
// new rpath: $ORIGIN/../lib
#[test]
#[cfg(target_os = "linux")]
fn relink_add_rpath() -> Result<(), RelinkError> {
if which::which("patchelf").is_err() {
tracing::warn!("patchelf not found, skipping test");
return Ok(());
}

// copy binary to a temporary directory
let prefix = Path::new(env!("CARGO_MANIFEST_DIR")).join("test-data/binary_files");
let tmp_dir = tempdir_in(&prefix)?.into_path();
Expand All @@ -404,7 +415,7 @@ mod test {

let encoded_prefix = Path::new("/rattler-build_zlink/host_env_placehold");
let object = SharedObject::new(&binary_path)?;
object.relink(&prefix, encoded_prefix, &[String::from("lib/")], &[])?;
object.relink(&prefix, encoded_prefix, &[String::from("lib/")], None)?;
let object = SharedObject::new(&binary_path)?;
assert_eq!(
vec!["$ORIGIN/../lib"],
Expand Down
16 changes: 7 additions & 9 deletions src/packaging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -899,27 +899,25 @@ pub fn package_conda(

let dynamic_linking = output.recipe.build().dynamic_linking();
let relocation_config = dynamic_linking
.clone()
.and_then(|v| v.binary_relocation())
.unwrap_or_default();

if output.build_configuration.target_platform != Platform::NoArch
&& !relocation_config.no_relocation()
{
let rpath_allowlist = match dynamic_linking {
Some(v) => v.rpath_allowlist()?,
None => Vec::new(),
};
let rpath_allowlist = dynamic_linking.and_then(|dl| dl.rpath_allowlist());
let mut binaries = tmp_files.clone();
if let Some(paths) = relocation_config.relocate_paths()? {
binaries.retain(|v| paths.iter().any(|glob| glob.is_match(v)));
if let Some(globs) = relocation_config.relocate_paths() {
binaries.retain(|v| globs.is_match(v));
}

post::relink(
&binaries,
tmp_dir_path,
prefix,
&output.build_configuration.target_platform,
&dynamic_linking.clone().unwrap_or_default().rpaths(),
&rpath_allowlist,
&dynamic_linking.map(|dl| dl.rpaths()).unwrap_or_default(),
rpath_allowlist,
)?;
}

Expand Down
4 changes: 2 additions & 2 deletions src/post.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::{
path::{Path, PathBuf},
};

use globset::GlobMatcher;
use globset::GlobSet;
use rattler_conda_types::{PackageName, Platform};

use crate::{linux::link::SharedObject, macos::link::Dylib, packaging::PackagingError};
Expand Down Expand Up @@ -53,7 +53,7 @@ pub fn relink(
encoded_prefix: &Path,
target_platform: &Platform,
rpaths: &[String],
rpath_allowlist: &[GlobMatcher],
rpath_allowlist: Option<&GlobSet>,
) -> Result<(), RelinkError> {
for p in paths {
let metadata = fs::symlink_metadata(p)?;
Expand Down
41 changes: 13 additions & 28 deletions src/recipe/parser/build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::str::FromStr;

use globset::{Glob, GlobMatcher, GlobSet};
use globset::GlobSet;
use rattler_conda_types::{package::EntryPoint, NoArchType};
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -89,8 +89,8 @@ impl Build {
}

/// Settings for shared libraries and executables
pub const fn dynamic_linking(&self) -> &Option<DynamicLinking> {
&self.dynamic_linking
pub const fn dynamic_linking(&self) -> Option<&DynamicLinking> {
self.dynamic_linking.as_ref()
}

/// Check if the build should be skipped.
Expand Down Expand Up @@ -171,8 +171,8 @@ pub struct DynamicLinking {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub(super) rpaths: Vec<String>,
/// Allow runpath / rpath to point to these locations outside of the environment.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub(super) rpath_allowlist: Vec<String>,
#[serde(default, skip_serializing_if = "GlobVec::is_empty")]
pub(super) rpath_allowlist: GlobVec,
/// Whether to relocate binaries or not.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) binary_relocation: Option<BinaryRelocation>,
Expand All @@ -189,13 +189,8 @@ impl DynamicLinking {
}

/// Get the rpath allow list.
pub fn rpath_allowlist(&self) -> Result<Vec<GlobMatcher>, globset::Error> {
let mut matchers = Vec::new();
for glob in self.rpath_allowlist.iter() {
let glob = Glob::new(glob)?.compile_matcher();
matchers.push(glob);
}
Ok(matchers)
pub fn rpath_allowlist(&self) -> Option<&GlobSet> {
self.rpath_allowlist.globset()
}

// Get the binary relocation settings.
Expand Down Expand Up @@ -248,7 +243,7 @@ pub enum BinaryRelocation {
/// Relocate all binaries.
All(bool),
/// Relocate specific paths.
SpecificPaths(Vec<String>),
SpecificPaths(GlobVec),
}

impl Default for BinaryRelocation {
Expand All @@ -259,17 +254,10 @@ impl Default for BinaryRelocation {

impl BinaryRelocation {
/// Return the paths to relocate.
pub fn relocate_paths(&self) -> Result<Option<Vec<GlobMatcher>>, globset::Error> {
pub fn relocate_paths(&self) -> Option<&GlobSet> {
match self {
BinaryRelocation::All(_) => Ok(None),
BinaryRelocation::SpecificPaths(paths) => {
let mut matchers = Vec::new();
for glob in paths {
let glob = Glob::new(glob)?.compile_matcher();
matchers.push(glob);
}
Ok(Some(matchers))
}
BinaryRelocation::All(_) => None,
BinaryRelocation::SpecificPaths(paths) => paths.globset(),
}
}

Expand All @@ -296,11 +284,8 @@ impl TryConvertNode<BinaryRelocation> for RenderedNode {

impl TryConvertNode<BinaryRelocation> for RenderedSequenceNode {
fn try_convert(&self, name: &str) -> Result<BinaryRelocation, Vec<PartialParsingError>> {
let mut paths = Vec::with_capacity(self.len());
for item in self.iter() {
paths.push(item.try_convert(name)?)
}
Ok(BinaryRelocation::SpecificPaths(paths))
let globvec: GlobVec = self.try_convert(name)?;
Ok(BinaryRelocation::SpecificPaths(globvec))
}
}

Expand Down
20 changes: 19 additions & 1 deletion src/recipe/parser/glob_vec.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::fmt::{self, Debug, Formatter};

use globset::{Glob, GlobSet};

use serde::ser::SerializeSeq;
Expand All @@ -7,9 +9,17 @@ use crate::_partialerror;
use crate::recipe::custom_yaml::{HasSpan, RenderedNode, RenderedSequenceNode, TryConvertNode};
use crate::recipe::error::{ErrorKind, PartialParsingError};

#[derive(Default, Debug, Clone)]
#[derive(Default, Clone)]
pub struct GlobVec(Vec<Glob>, Option<GlobSet>);

impl PartialEq for GlobVec {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}

impl Eq for GlobVec {}

impl Serialize for GlobVec {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
Expand All @@ -20,6 +30,14 @@ impl Serialize for GlobVec {
}
}

impl Debug for GlobVec {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_list()
.entries(self.0.iter().map(|glob| glob.glob()))
.finish()
}
}

impl<'de> Deserialize<'de> for GlobVec {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,8 @@ Recipe {
),
},
),
always_copy_files: GlobVec(
[],
None,
),
always_include_files: GlobVec(
[],
None,
),
always_copy_files: [],
always_include_files: [],
},
requirements: Requirements {
build: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,8 @@ Recipe {
),
},
),
always_copy_files: GlobVec(
[],
None,
),
always_include_files: GlobVec(
[],
None,
),
always_copy_files: [],
always_include_files: [],
},
requirements: Requirements {
build: [
Expand Down

0 comments on commit 51280f7

Please sign in to comment.