mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-29 06:54:10 +00:00
Patch pkgconfig files after Python install (#10189)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / lint (push) Waiting to run
CI / cargo clippy | ubuntu (push) Blocked by required conditions
CI / cargo clippy | windows (push) Blocked by required conditions
CI / cargo dev generate-all (push) Blocked by required conditions
CI / cargo shear (push) Waiting to run
CI / check windows trampoline | i686 (push) Blocked by required conditions
CI / cargo test | ubuntu (push) Blocked by required conditions
CI / cargo test | macos (push) Blocked by required conditions
CI / cargo test | windows (push) Blocked by required conditions
CI / check windows trampoline | aarch64 (push) Blocked by required conditions
CI / check windows trampoline | x86_64 (push) Blocked by required conditions
CI / test windows trampoline | i686 (push) Blocked by required conditions
CI / test windows trampoline | x86_64 (push) Blocked by required conditions
CI / typos (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / build binary | linux (push) Blocked by required conditions
CI / build binary | macos aarch64 (push) Blocked by required conditions
CI / build binary | macos x86_64 (push) Blocked by required conditions
CI / build binary | windows (push) Blocked by required conditions
CI / cargo build (msrv) (push) Blocked by required conditions
CI / build binary | freebsd (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / integration test | conda on ubuntu (push) Blocked by required conditions
CI / integration test | free-threaded on linux (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | pypy on ubuntu (push) Blocked by required conditions
CI / integration test | pypy on windows (push) Blocked by required conditions
CI / integration test | graalpy on ubuntu (push) Blocked by required conditions
CI / integration test | graalpy on windows (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | determine publish changes (push) Blocked by required conditions
CI / integration test | uv publish (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on opensuse (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | alpine (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86_64 (push) Blocked by required conditions
CI / check system | python3.10 on windows (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on linux (push) Blocked by required conditions
CI / check system | conda3.8 on linux (push) Blocked by required conditions
CI / check system | conda3.11 on macos (push) Blocked by required conditions
CI / check system | conda3.8 on macos (push) Blocked by required conditions
CI / check system | conda3.11 on windows (push) Blocked by required conditions
CI / check system | conda3.8 on windows (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / lint (push) Waiting to run
CI / cargo clippy | ubuntu (push) Blocked by required conditions
CI / cargo clippy | windows (push) Blocked by required conditions
CI / cargo dev generate-all (push) Blocked by required conditions
CI / cargo shear (push) Waiting to run
CI / check windows trampoline | i686 (push) Blocked by required conditions
CI / cargo test | ubuntu (push) Blocked by required conditions
CI / cargo test | macos (push) Blocked by required conditions
CI / cargo test | windows (push) Blocked by required conditions
CI / check windows trampoline | aarch64 (push) Blocked by required conditions
CI / check windows trampoline | x86_64 (push) Blocked by required conditions
CI / test windows trampoline | i686 (push) Blocked by required conditions
CI / test windows trampoline | x86_64 (push) Blocked by required conditions
CI / typos (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / build binary | linux (push) Blocked by required conditions
CI / build binary | macos aarch64 (push) Blocked by required conditions
CI / build binary | macos x86_64 (push) Blocked by required conditions
CI / build binary | windows (push) Blocked by required conditions
CI / cargo build (msrv) (push) Blocked by required conditions
CI / build binary | freebsd (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / integration test | conda on ubuntu (push) Blocked by required conditions
CI / integration test | free-threaded on linux (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | pypy on ubuntu (push) Blocked by required conditions
CI / integration test | pypy on windows (push) Blocked by required conditions
CI / integration test | graalpy on ubuntu (push) Blocked by required conditions
CI / integration test | graalpy on windows (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | determine publish changes (push) Blocked by required conditions
CI / integration test | uv publish (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on opensuse (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | alpine (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86_64 (push) Blocked by required conditions
CI / check system | python3.10 on windows (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on linux (push) Blocked by required conditions
CI / check system | conda3.8 on linux (push) Blocked by required conditions
CI / check system | conda3.11 on macos (push) Blocked by required conditions
CI / check system | conda3.8 on macos (push) Blocked by required conditions
CI / check system | conda3.11 on windows (push) Blocked by required conditions
CI / check system | conda3.8 on windows (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
## Summary Closes https://github.com/astral-sh/uv/issues/10185. ## Test Plan Ran `cargo run python install 3.10.15 --reinstall`; verified that `python3.pc` contained: ``` # See: man pkg-config prefix=/Users/crmarsh/.local/share/uv/python/cpython-3.10.15-macos-aarch64-none exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include Name: Python Description: Build a C extension for Python Requires: Version: 3.10 Libs.private: -ldl -framework CoreFoundation Libs: Cflags: -I${includedir}/python3.10 ```
This commit is contained in:
parent
4c49683f7b
commit
0bc33e87b8
1 changed files with 113 additions and 0 deletions
|
@ -24,12 +24,14 @@
|
||||||
//! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
//! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
|
use itertools::{Either, Itertools};
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
use crate::sysconfig::parser::{Error as ParseError, SysconfigData, Value};
|
use crate::sysconfig::parser::{Error as ParseError, SysconfigData, Value};
|
||||||
|
@ -163,6 +165,25 @@ pub(crate) fn update_sysconfig(
|
||||||
file.write_all(contents.as_bytes())?;
|
file.write_all(contents.as_bytes())?;
|
||||||
file.sync_data()?;
|
file.sync_data()?;
|
||||||
|
|
||||||
|
// Find the `pkgconfig` files in the Python installation.
|
||||||
|
for pkgconfig in find_pkgconfigs(&real_prefix)? {
|
||||||
|
let pkgconfig = pkgconfig?;
|
||||||
|
trace!("Discovered `pkgconfig` data at: {}", pkgconfig.display());
|
||||||
|
|
||||||
|
// 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()?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,6 +301,57 @@ fn patch_sysconfigdata(mut data: SysconfigData, real_prefix: &Path) -> Sysconfig
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find the location of all `pkg-config` files in a Python installation.
|
||||||
|
///
|
||||||
|
/// Specifically, searches for files under `lib/pkgconfig` with the `.pc` extension.
|
||||||
|
fn find_pkgconfigs(
|
||||||
|
install_root: &Path,
|
||||||
|
) -> Result<impl Iterator<Item = Result<PathBuf, std::io::Error>>, std::io::Error> {
|
||||||
|
let pkgconfig = install_root.join("lib").join("pkgconfig");
|
||||||
|
|
||||||
|
let read_dir = match pkgconfig.read_dir() {
|
||||||
|
Ok(read_dir) => read_dir,
|
||||||
|
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
|
||||||
|
return Ok(Either::Left(std::iter::empty()));
|
||||||
|
}
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Either::Right(
|
||||||
|
read_dir
|
||||||
|
.filter_ok(|entry| entry.path().extension().is_some_and(|ext| ext == "pc"))
|
||||||
|
.filter_ok(|entry| entry.file_type().is_ok_and(|file_type| file_type.is_file()))
|
||||||
|
.map_ok(|entry| entry.path()),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Patch the given `pkgconfig` contents.
|
||||||
|
///
|
||||||
|
/// Returns the updated contents.
|
||||||
|
fn patch_pkgconfig(contents: &str, real_prefix: &Path) -> String {
|
||||||
|
contents
|
||||||
|
.lines()
|
||||||
|
.map(|line| {
|
||||||
|
// Given, e.g., `prefix=/install`, replace with `prefix=/real/prefix`.
|
||||||
|
let Some((prefix, suffix)) = line.split_once('=') else {
|
||||||
|
return Cow::Borrowed(line);
|
||||||
|
};
|
||||||
|
|
||||||
|
// The content before the `=` must be an ASCII alphabetic string.
|
||||||
|
if !prefix.chars().all(|c| c.is_ascii_alphabetic()) {
|
||||||
|
return Cow::Borrowed(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The content after the `=` must be equal to the expected prefix.
|
||||||
|
if suffix != "/install" {
|
||||||
|
return Cow::Borrowed(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cow::Owned(format!("{}={}", prefix, real_prefix.display()))
|
||||||
|
})
|
||||||
|
.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
@ -298,6 +370,7 @@ pub enum Error {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use indoc::indoc;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn update_real_prefix() -> Result<(), Error> {
|
fn update_real_prefix() -> Result<(), Error> {
|
||||||
|
@ -385,4 +458,44 @@ mod tests {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn update_pkgconfig() {
|
||||||
|
let pkgconfig = indoc! {
|
||||||
|
r"
|
||||||
|
# See: man pkg-config
|
||||||
|
prefix=/install
|
||||||
|
exec_prefix=${prefix}
|
||||||
|
libdir=${exec_prefix}/lib
|
||||||
|
includedir=${prefix}/include
|
||||||
|
|
||||||
|
Name: Python
|
||||||
|
Description: Build a C extension for Python
|
||||||
|
Requires:
|
||||||
|
Version: 3.10
|
||||||
|
Libs.private: -ldl -framework CoreFoundation
|
||||||
|
Libs:
|
||||||
|
Cflags: -I${includedir}/python3.10
|
||||||
|
"
|
||||||
|
};
|
||||||
|
|
||||||
|
let real_prefix = Path::new("/real/prefix");
|
||||||
|
let pkgconfig = patch_pkgconfig(pkgconfig, real_prefix);
|
||||||
|
|
||||||
|
insta::assert_snapshot!(pkgconfig, @r###"
|
||||||
|
# See: man pkg-config
|
||||||
|
prefix=/real/prefix
|
||||||
|
exec_prefix=${prefix}
|
||||||
|
libdir=${exec_prefix}/lib
|
||||||
|
includedir=${prefix}/include
|
||||||
|
|
||||||
|
Name: Python
|
||||||
|
Description: Build a C extension for Python
|
||||||
|
Requires:
|
||||||
|
Version: 3.10
|
||||||
|
Libs.private: -ldl -framework CoreFoundation
|
||||||
|
Libs:
|
||||||
|
Cflags: -I${includedir}/python3.10
|
||||||
|
"###);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue