mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
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:
parent
73eb2dfb1f
commit
d65c146b21
10 changed files with 387 additions and 117 deletions
8
.github/workflows/sync-python-releases.yml
vendored
8
.github/workflows/sync-python-releases.yml
vendored
|
@ -28,12 +28,20 @@ jobs:
|
|||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Sync Sysconfig Targets
|
||||
run: ${{ github.workspace }}/crates/uv-dev/sync_sysconfig_targets.sh
|
||||
working-directory: ./crates/uv-dev
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: "Create Pull Request"
|
||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
|
||||
with:
|
||||
commit-message: "Sync latest Python releases"
|
||||
add-paths: |
|
||||
crates/uv-python/download-metadata.json
|
||||
crates/uv-dev/src/generate_sysconfig_mappings.rs
|
||||
crates/uv-python/src/sysconfig/generated_mappings.rs
|
||||
branch: "sync-python-releases"
|
||||
title: "Sync latest Python releases"
|
||||
body: "Automated update for Python releases."
|
||||
|
|
21
Cargo.lock
generated
21
Cargo.lock
generated
|
@ -3627,6 +3627,19 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.34+deprecated"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
"unsafe-libyaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.9"
|
||||
|
@ -4528,6 +4541,12 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
||||
|
||||
[[package]]
|
||||
name = "unscanny"
|
||||
version = "0.1.0"
|
||||
|
@ -5049,10 +5068,12 @@ dependencies = [
|
|||
"owo-colors",
|
||||
"poloto",
|
||||
"pretty_assertions",
|
||||
"reqwest",
|
||||
"resvg",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"tagu",
|
||||
"textwrap",
|
||||
"tokio",
|
||||
|
|
|
@ -44,10 +44,12 @@ markdown = { version = "1.0.0" }
|
|||
owo-colors = { workspace = true }
|
||||
poloto = { version = "19.1.2", optional = true }
|
||||
pretty_assertions = { version = "1.4.1" }
|
||||
reqwest = { workspace = true }
|
||||
resvg = { version = "0.29.0", optional = true }
|
||||
schemars = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
serde_yaml = { version = "0.9.34" }
|
||||
tagu = { version = "0.1.6", optional = true }
|
||||
textwrap = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
|
|
@ -4,7 +4,7 @@ use anyhow::Result;
|
|||
|
||||
use crate::{
|
||||
generate_cli_reference, generate_env_vars_reference, generate_json_schema,
|
||||
generate_options_reference,
|
||||
generate_options_reference, generate_sysconfig_mappings,
|
||||
};
|
||||
|
||||
#[derive(clap::Args)]
|
||||
|
@ -26,10 +26,12 @@ pub(crate) enum Mode {
|
|||
DryRun,
|
||||
}
|
||||
|
||||
pub(crate) fn main(args: &Args) -> Result<()> {
|
||||
pub(crate) async fn main(args: &Args) -> Result<()> {
|
||||
generate_json_schema::main(&generate_json_schema::Args { mode: args.mode })?;
|
||||
generate_options_reference::main(&generate_options_reference::Args { mode: args.mode })?;
|
||||
generate_cli_reference::main(&generate_cli_reference::Args { mode: args.mode })?;
|
||||
generate_env_vars_reference::main(&generate_env_vars_reference::Args { mode: args.mode })?;
|
||||
generate_sysconfig_mappings::main(&generate_sysconfig_mappings::Args { mode: args.mode })
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
198
crates/uv-dev/src/generate_sysconfig_mappings.rs
Normal file
198
crates/uv-dev/src/generate_sysconfig_mappings.rs
Normal file
|
@ -0,0 +1,198 @@
|
|||
//! Generate sysconfig mappings for supported python-build-standalone *nix platforms.
|
||||
use anstream::println;
|
||||
use anyhow::{Result, bail};
|
||||
use pretty_assertions::StrComparison;
|
||||
use serde::Deserialize;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::ROOT_DIR;
|
||||
use crate::generate_all::Mode;
|
||||
|
||||
/// Contains current supported targets
|
||||
const TARGETS_YML_URL: &str = "https://raw.githubusercontent.com/astral-sh/python-build-standalone/refs/tags/20250529/cpython-unix/targets.yml";
|
||||
|
||||
#[derive(clap::Args)]
|
||||
pub(crate) struct Args {
|
||||
#[arg(long, default_value_t, value_enum)]
|
||||
pub(crate) mode: Mode,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct TargetConfig {
|
||||
host_cc: Option<String>,
|
||||
host_cxx: Option<String>,
|
||||
target_cc: Option<String>,
|
||||
target_cxx: Option<String>,
|
||||
}
|
||||
|
||||
pub(crate) async fn main(args: &Args) -> Result<()> {
|
||||
let reference_string = generate().await?;
|
||||
let filename = "generated_mappings.rs";
|
||||
let reference_path = PathBuf::from(ROOT_DIR)
|
||||
.join("crates")
|
||||
.join("uv-python")
|
||||
.join("src")
|
||||
.join("sysconfig")
|
||||
.join(filename);
|
||||
|
||||
match args.mode {
|
||||
Mode::DryRun => {
|
||||
println!("{reference_string}");
|
||||
}
|
||||
Mode::Check => match fs_err::read_to_string(reference_path) {
|
||||
Ok(current) => {
|
||||
if current == reference_string {
|
||||
println!("Up-to-date: {filename}");
|
||||
} else {
|
||||
let comparison = StrComparison::new(¤t, &reference_string);
|
||||
bail!(
|
||||
"{filename} changed, please run `cargo dev generate-sysconfig-metadata`:\n{comparison}"
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
|
||||
bail!("{filename} not found, please run `cargo dev generate-sysconfig-metadata`");
|
||||
}
|
||||
Err(err) => {
|
||||
bail!(
|
||||
"{filename} changed, please run `cargo dev generate-sysconfig-metadata`:\n{err}"
|
||||
);
|
||||
}
|
||||
},
|
||||
Mode::Write => match fs_err::read_to_string(&reference_path) {
|
||||
Ok(current) => {
|
||||
if current == reference_string {
|
||||
println!("Up-to-date: {filename}");
|
||||
} else {
|
||||
println!("Updating: {filename}");
|
||||
fs_err::write(reference_path, reference_string.as_bytes())?;
|
||||
}
|
||||
}
|
||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
|
||||
println!("Updating: {filename}");
|
||||
fs_err::write(reference_path, reference_string.as_bytes())?;
|
||||
}
|
||||
Err(err) => {
|
||||
bail!(
|
||||
"{filename} changed, please run `cargo dev generate-sysconfig-metadata`:\n{err}"
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn generate() -> Result<String> {
|
||||
println!("Downloading python-build-standalone cpython-unix/targets.yml ...");
|
||||
let body = reqwest::get(TARGETS_YML_URL).await?.text().await?;
|
||||
|
||||
let parsed: BTreeMap<String, TargetConfig> = serde_yaml::from_str(&body)?;
|
||||
|
||||
let mut replacements: BTreeMap<&str, BTreeMap<String, String>> = BTreeMap::new();
|
||||
|
||||
for targets_config in parsed.values() {
|
||||
for sysconfig_cc_entry in ["CC", "LDSHARED", "BLDSHARED", "LINKCC"] {
|
||||
if let Some(ref from_cc) = targets_config.host_cc {
|
||||
replacements
|
||||
.entry(sysconfig_cc_entry)
|
||||
.or_default()
|
||||
.insert(from_cc.to_string(), "cc".to_string());
|
||||
}
|
||||
if let Some(ref from_cc) = targets_config.target_cc {
|
||||
replacements
|
||||
.entry(sysconfig_cc_entry)
|
||||
.or_default()
|
||||
.insert(from_cc.to_string(), "cc".to_string());
|
||||
}
|
||||
}
|
||||
for sysconfig_cxx_entry in ["CXX", "LDCXXSHARED"] {
|
||||
if let Some(ref from_cxx) = targets_config.host_cxx {
|
||||
replacements
|
||||
.entry(sysconfig_cxx_entry)
|
||||
.or_default()
|
||||
.insert(from_cxx.to_string(), "c++".to_string());
|
||||
}
|
||||
if let Some(ref from_cxx) = targets_config.target_cxx {
|
||||
replacements
|
||||
.entry(sysconfig_cxx_entry)
|
||||
.or_default()
|
||||
.insert(from_cxx.to_string(), "c++".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut output = String::new();
|
||||
|
||||
// Opening statements
|
||||
output.push_str("//! DO NOT EDIT\n");
|
||||
output.push_str("//!\n");
|
||||
output.push_str("//! Generated with `cargo run dev generate-sysconfig-metadata`\n");
|
||||
output.push_str("//! Targets from <https://github.com/astral-sh/python-build-standalone/blob/20250529/cpython-unix/targets.yml>\n");
|
||||
output.push_str("//!\n");
|
||||
|
||||
// Disable clippy/fmt
|
||||
output.push_str("#![allow(clippy::all)]\n");
|
||||
output.push_str("#![cfg_attr(any(), rustfmt::skip)]\n\n");
|
||||
|
||||
// Begin main code
|
||||
output.push_str("use std::collections::BTreeMap;\n");
|
||||
output.push_str("use std::sync::LazyLock;\n\n");
|
||||
output.push_str("use crate::sysconfig::replacements::{ReplacementEntry, ReplacementMode};\n\n");
|
||||
|
||||
output.push_str(
|
||||
"/// Mapping for sysconfig keys to lookup and replace with the appropriate entry.\n",
|
||||
);
|
||||
output.push_str("pub(crate) static DEFAULT_VARIABLE_UPDATES: LazyLock<BTreeMap<String, Vec<ReplacementEntry>>> = LazyLock::new(|| {\n");
|
||||
output.push_str(" BTreeMap::from_iter([\n");
|
||||
|
||||
// Add Replacement Entries for CC, CXX, etc.
|
||||
for (key, entries) in &replacements {
|
||||
writeln!(output, " (\"{key}\".to_string(), vec![")?;
|
||||
for (from, to) in entries {
|
||||
writeln!(
|
||||
output,
|
||||
" ReplacementEntry {{ mode: ReplacementMode::Partial {{ from: \"{from}\".to_string() }}, to: \"{to}\".to_string() }},"
|
||||
)?;
|
||||
}
|
||||
writeln!(output, " ]),")?;
|
||||
}
|
||||
|
||||
// Add AR case last
|
||||
output.push_str(" (\"AR\".to_string(), vec![\n");
|
||||
output.push_str(" ReplacementEntry {\n");
|
||||
output.push_str(" mode: ReplacementMode::Full,\n");
|
||||
output.push_str(" to: \"ar\".to_string(),\n");
|
||||
output.push_str(" },\n");
|
||||
output.push_str(" ]),\n");
|
||||
|
||||
// Closing
|
||||
output.push_str(" ])\n});\n");
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::env;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use uv_static::EnvVars;
|
||||
|
||||
use crate::generate_all::Mode;
|
||||
|
||||
use super::{Args, main};
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_generate_sysconfig_mappings() -> Result<()> {
|
||||
let mode = if env::var(EnvVars::UV_UPDATE_SCHEMA).as_deref() == Ok("1") {
|
||||
Mode::Write
|
||||
} else {
|
||||
Mode::Check
|
||||
};
|
||||
main(&Args { mode }).await
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ use crate::generate_cli_reference::Args as GenerateCliReferenceArgs;
|
|||
use crate::generate_env_vars_reference::Args as GenerateEnvVarsReferenceArgs;
|
||||
use crate::generate_json_schema::Args as GenerateJsonSchemaArgs;
|
||||
use crate::generate_options_reference::Args as GenerateOptionsReferenceArgs;
|
||||
use crate::generate_sysconfig_mappings::Args as GenerateSysconfigMetadataArgs;
|
||||
#[cfg(feature = "render")]
|
||||
use crate::render_benchmarks::RenderBenchmarksArgs;
|
||||
use crate::wheel_metadata::WheelMetadataArgs;
|
||||
|
@ -22,6 +23,7 @@ mod generate_cli_reference;
|
|||
mod generate_env_vars_reference;
|
||||
mod generate_json_schema;
|
||||
mod generate_options_reference;
|
||||
mod generate_sysconfig_mappings;
|
||||
mod render_benchmarks;
|
||||
mod wheel_metadata;
|
||||
|
||||
|
@ -45,6 +47,8 @@ enum Cli {
|
|||
GenerateCliReference(GenerateCliReferenceArgs),
|
||||
/// Generate the environment variables reference for the documentation.
|
||||
GenerateEnvVarsReference(GenerateEnvVarsReferenceArgs),
|
||||
/// Generate the sysconfig metadata from derived targets.
|
||||
GenerateSysconfigMetadata(GenerateSysconfigMetadataArgs),
|
||||
#[cfg(feature = "render")]
|
||||
/// Render the benchmarks.
|
||||
RenderBenchmarks(RenderBenchmarksArgs),
|
||||
|
@ -57,11 +61,12 @@ pub async fn run() -> Result<()> {
|
|||
Cli::WheelMetadata(args) => wheel_metadata::wheel_metadata(args).await?,
|
||||
Cli::Compile(args) => compile::compile(args).await?,
|
||||
Cli::ClearCompile(args) => clear_compile::clear_compile(&args)?,
|
||||
Cli::GenerateAll(args) => generate_all::main(&args)?,
|
||||
Cli::GenerateAll(args) => generate_all::main(&args).await?,
|
||||
Cli::GenerateJSONSchema(args) => generate_json_schema::main(&args)?,
|
||||
Cli::GenerateOptionsReference(args) => generate_options_reference::main(&args)?,
|
||||
Cli::GenerateCliReference(args) => generate_cli_reference::main(&args)?,
|
||||
Cli::GenerateEnvVarsReference(args) => generate_env_vars_reference::main(&args)?,
|
||||
Cli::GenerateSysconfigMetadata(args) => generate_sysconfig_mappings::main(&args).await?,
|
||||
#[cfg(feature = "render")]
|
||||
Cli::RenderBenchmarks(args) => render_benchmarks::render_benchmarks(&args)?,
|
||||
}
|
||||
|
|
18
crates/uv-dev/sync_sysconfig_targets.sh
Executable file
18
crates/uv-dev/sync_sysconfig_targets.sh
Executable file
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Fetch latest python-build-standalone tag
|
||||
latest_tag=$(curl -fsSL -H "Accept: application/json" https://github.com/astral-sh/python-build-standalone/releases/latest | jq -r .tag_name)
|
||||
|
||||
# Validate we got a tag name back
|
||||
if [[ -z "${latest_tag}" ]]; then
|
||||
echo "Error: Failed to fetch the latest tag from astral-sh/python-build-standalone." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Edit the sysconfig mapping endpoints
|
||||
sed -i.bak "s|refs/tags/[^/]\+/cpython-unix|refs/tags/${latest_tag}/cpython-unix|g" src/generate_sysconfig_mappings.rs && rm -f src/generate_sysconfig_mappings.rs.bak
|
||||
sed -i.bak "s|blob/[^/]\+/cpython-unix|blob/${latest_tag}/cpython-unix|g" src/generate_sysconfig_mappings.rs && rm -f src/generate_sysconfig_mappings.rs.bak
|
||||
|
||||
# Regenerate mappings in case there's any changes
|
||||
cargo dev generate-sysconfig-metadata
|
100
crates/uv-python/src/sysconfig/generated_mappings.rs
Normal file
100
crates/uv-python/src/sysconfig/generated_mappings.rs
Normal 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(),
|
||||
},
|
||||
]),
|
||||
])
|
||||
});
|
|
@ -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(
|
||||
|
|
27
crates/uv-python/src/sysconfig/replacements.rs
Normal file
27
crates/uv-python/src/sysconfig/replacements.rs
Normal 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(),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue