Skip to content

Commit

Permalink
Patch pkg-config files to be relocatable
Browse files Browse the repository at this point in the history
Previously, we patched pkg-config .pc files to have the absolute path to
the directory where we unpack a python-build-standalone release.  As
discussed in astral-sh#11028, we can use ${pcfiledir} in a .pc file to indicate
paths relative to the location of the file itself.

This change was implemented in astral-sh/python-build-standalone#507,
so for newer python-build-standalone releases, we don't need to do any
patching. Optimize this case by only modifying the .pc file if an actual
change is needed (which might be helpful down the line with hard links
or something). For older releases, change uv's patch to match what
python-build-standalone now does.
  • Loading branch information
geofft committed Feb 6, 2025
1 parent cfd1e67 commit f13fe17
Showing 1 changed file with 29 additions and 19 deletions.
48 changes: 29 additions & 19 deletions crates/uv-python/src/sysconfig/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,16 +172,16 @@ pub(crate) fn update_sysconfig(

// Update the `pkgconfig` file in-memory.
let contents = fs_err::read_to_string(&pkgconfig)?;
let contents = patch_pkgconfig(&contents, &real_prefix);

// Write the updated `pkgconfig` file.
let mut file = fs_err::OpenOptions::new()
.write(true)
.truncate(true)
.create(true)
.open(&pkgconfig)?;
file.write_all(contents.as_bytes())?;
file.sync_data()?;
if let Some(new_contents) = patch_pkgconfig(&contents) {
// Write the updated `pkgconfig` file.
let mut file = fs_err::OpenOptions::new()
.write(true)
.truncate(true)
.create(true)
.open(&pkgconfig)?;
file.write_all(new_contents.as_bytes())?;
file.sync_data()?;
}
}

Ok(())
Expand Down Expand Up @@ -327,12 +327,17 @@ fn find_pkgconfigs(

/// Patch the given `pkgconfig` contents.
///
/// Returns the updated contents.
fn patch_pkgconfig(contents: &str, real_prefix: &Path) -> String {
contents
/// Returns the updated contents, if an update is needed.
fn patch_pkgconfig(contents: &str) -> Option<String> {
let mut changed = false;
let new_contents = contents
.lines()
.map(|line| {
// Given, e.g., `prefix=/install`, replace with `prefix=/real/prefix`.
// python-build-standalone is compiled with a prefix of
// /install. Replace lines like `prefix=/install` with
// `prefix=${pcfiledir}/../..` (since the .pc file is in
// lib/pkgconfig/). Newer versions of python-build-standalone
// already have this change.
let Some((prefix, suffix)) = line.split_once('=') else {
return Cow::Borrowed(line);
};
Expand All @@ -347,9 +352,15 @@ fn patch_pkgconfig(contents: &str, real_prefix: &Path) -> String {
return Cow::Borrowed(line);
}

Cow::Owned(format!("{}={}", prefix, real_prefix.display()))
changed = true;
Cow::Owned(format!("{prefix}=${{pcfiledir}}/../.."))
})
.join("\n")
.join("\n");
if changed {
Some(new_contents)
} else {
None
}
}

#[derive(thiserror::Error, Debug)]
Expand Down Expand Up @@ -479,12 +490,11 @@ mod tests {
"
};

let real_prefix = Path::new("/real/prefix");
let pkgconfig = patch_pkgconfig(pkgconfig, real_prefix);
let pkgconfig = patch_pkgconfig(pkgconfig).unwrap();

insta::assert_snapshot!(pkgconfig, @r###"
# See: man pkg-config
prefix=/real/prefix
prefix=${pcfiledir}/../..
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Expand Down

0 comments on commit f13fe17

Please sign in to comment.