feat: add dynamically generated sysconfig replacement mappings (#13441)

## Summary

Implementation referenced in
https://github.com/astral-sh/uv/pull/12239#issuecomment-2744880003

Closes #12919 #12901

This makes the sysconfig replacements mappings dynamically generated
from
https://github.com/astral-sh/python-build-standalone/blob/main/cpython-unix/targets.yml

## Test Plan

cargo dev tests, and tested scenario from
https://github.com/astral-sh/uv/issues/12901#issuecomment-2822107454
This commit is contained in:
samypr100 2025-06-02 11:58:30 -04:00 committed by GitHub
parent 73eb2dfb1f
commit d65c146b21
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 387 additions and 117 deletions

View file

@ -0,0 +1,100 @@
//! DO NOT EDIT
//!
//! Generated with `cargo run dev generate-sysconfig-metadata`
//! Targets from <https://github.com/astral-sh/python-build-standalone/blob/20250529/cpython-unix/targets.yml>
//!
#![allow(clippy::all)]
#![cfg_attr(any(), rustfmt::skip)]
use std::collections::BTreeMap;
use std::sync::LazyLock;
use crate::sysconfig::replacements::{ReplacementEntry, ReplacementMode};
/// Mapping for sysconfig keys to lookup and replace with the appropriate entry.
pub(crate) static DEFAULT_VARIABLE_UPDATES: LazyLock<BTreeMap<String, Vec<ReplacementEntry>>> = LazyLock::new(|| {
BTreeMap::from_iter([
("BLDSHARED".to_string(), vec![
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/aarch64-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/arm-linux-gnueabi-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/arm-linux-gnueabihf-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/mips-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/mipsel-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/powerpc64le-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/riscv64-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/s390x-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/x86_64-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "clang".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "musl-clang".to_string() }, to: "cc".to_string() },
]),
("CC".to_string(), vec![
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/aarch64-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/arm-linux-gnueabi-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/arm-linux-gnueabihf-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/mips-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/mipsel-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/powerpc64le-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/riscv64-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/s390x-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/x86_64-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "clang".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "musl-clang".to_string() }, to: "cc".to_string() },
]),
("CXX".to_string(), vec![
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/aarch64-linux-gnu-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/arm-linux-gnueabi-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/arm-linux-gnueabihf-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/mips-linux-gnu-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/mipsel-linux-gnu-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/powerpc64le-linux-gnu-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/riscv64-linux-gnu-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/s390x-linux-gnu-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/x86_64-linux-gnu-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "clang++".to_string() }, to: "c++".to_string() },
]),
("LDCXXSHARED".to_string(), vec![
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/aarch64-linux-gnu-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/arm-linux-gnueabi-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/arm-linux-gnueabihf-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/mips-linux-gnu-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/mipsel-linux-gnu-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/powerpc64le-linux-gnu-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/riscv64-linux-gnu-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/s390x-linux-gnu-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/x86_64-linux-gnu-g++".to_string() }, to: "c++".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "clang++".to_string() }, to: "c++".to_string() },
]),
("LDSHARED".to_string(), vec![
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/aarch64-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/arm-linux-gnueabi-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/arm-linux-gnueabihf-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/mips-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/mipsel-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/powerpc64le-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/riscv64-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/s390x-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/x86_64-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "clang".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "musl-clang".to_string() }, to: "cc".to_string() },
]),
("LINKCC".to_string(), vec![
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/aarch64-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/arm-linux-gnueabi-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/arm-linux-gnueabihf-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/mips-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/mipsel-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/powerpc64le-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/riscv64-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/s390x-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "/usr/bin/x86_64-linux-gnu-gcc".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "clang".to_string() }, to: "cc".to_string() },
ReplacementEntry { mode: ReplacementMode::Partial { from: "musl-clang".to_string() }, to: "cc".to_string() },
]),
("AR".to_string(), vec![
ReplacementEntry {
mode: ReplacementMode::Full,
to: "ar".to_string(),
},
]),
])
});

View file

@ -25,131 +25,20 @@
//! ```
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::sync::LazyLock;
use itertools::{Either, Itertools};
use tracing::trace;
use crate::sysconfig::generated_mappings::DEFAULT_VARIABLE_UPDATES;
use crate::sysconfig::parser::{Error as ParseError, SysconfigData, Value};
mod cursor;
mod generated_mappings;
mod parser;
/// Replacement mode for sysconfig values.
#[derive(Debug)]
enum ReplacementMode {
Partial { from: String },
Full,
}
/// A replacement entry to patch in sysconfig data.
#[derive(Debug)]
struct ReplacementEntry {
mode: ReplacementMode,
to: String,
}
impl ReplacementEntry {
/// Patches a sysconfig value either partially (replacing a specific word) or fully.
fn patch(&self, entry: &str) -> String {
match &self.mode {
ReplacementMode::Partial { from } => entry
.split_whitespace()
.map(|word| if word == from { &self.to } else { word })
.collect::<Vec<_>>()
.join(" "),
ReplacementMode::Full => self.to.clone(),
}
}
}
/// Mapping for sysconfig keys to lookup and replace with the appropriate entry.
static DEFAULT_VARIABLE_UPDATES: LazyLock<BTreeMap<String, Vec<ReplacementEntry>>> =
LazyLock::new(|| {
BTreeMap::from_iter([
(
"CC".to_string(),
vec![
ReplacementEntry {
mode: ReplacementMode::Partial {
from: "clang".to_string(),
},
to: "cc".to_string(),
},
ReplacementEntry {
mode: ReplacementMode::Partial {
from: "/usr/bin/aarch64-linux-gnu-gcc".to_string(),
},
to: "cc".to_string(),
},
],
),
(
"CXX".to_string(),
vec![
ReplacementEntry {
mode: ReplacementMode::Partial {
from: "clang++".to_string(),
},
to: "c++".to_string(),
},
ReplacementEntry {
mode: ReplacementMode::Partial {
from: "/usr/bin/x86_64-linux-gnu-g++".to_string(),
},
to: "c++".to_string(),
},
],
),
(
"BLDSHARED".to_string(),
vec![ReplacementEntry {
mode: ReplacementMode::Partial {
from: "clang".to_string(),
},
to: "cc".to_string(),
}],
),
(
"LDSHARED".to_string(),
vec![ReplacementEntry {
mode: ReplacementMode::Partial {
from: "clang".to_string(),
},
to: "cc".to_string(),
}],
),
(
"LDCXXSHARED".to_string(),
vec![ReplacementEntry {
mode: ReplacementMode::Partial {
from: "clang++".to_string(),
},
to: "c++".to_string(),
}],
),
(
"LINKCC".to_string(),
vec![ReplacementEntry {
mode: ReplacementMode::Partial {
from: "clang".to_string(),
},
to: "cc".to_string(),
}],
),
(
"AR".to_string(),
vec![ReplacementEntry {
mode: ReplacementMode::Full,
to: "ar".to_string(),
}],
),
])
});
mod replacements;
/// Update the `sysconfig` data in a Python installation.
pub(crate) fn update_sysconfig(

View file

@ -0,0 +1,27 @@
/// Replacement mode for sysconfig values.
#[derive(Debug)]
pub(crate) enum ReplacementMode {
Partial { from: String },
Full,
}
/// A replacement entry to patch in sysconfig data.
#[derive(Debug)]
pub(crate) struct ReplacementEntry {
pub(crate) mode: ReplacementMode,
pub(crate) to: String,
}
impl ReplacementEntry {
/// Patches a sysconfig value either partially (replacing a specific word) or fully.
pub(crate) fn patch(&self, entry: &str) -> String {
match &self.mode {
ReplacementMode::Partial { from } => entry
.split_whitespace()
.map(|word| if word == from { &self.to } else { word })
.collect::<Vec<_>>()
.join(" "),
ReplacementMode::Full => self.to.clone(),
}
}
}