mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 21:35: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:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
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"
|
- name: "Create Pull Request"
|
||||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
|
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
|
||||||
with:
|
with:
|
||||||
commit-message: "Sync latest Python releases"
|
commit-message: "Sync latest Python releases"
|
||||||
add-paths: |
|
add-paths: |
|
||||||
crates/uv-python/download-metadata.json
|
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"
|
branch: "sync-python-releases"
|
||||||
title: "Sync latest Python releases"
|
title: "Sync latest Python releases"
|
||||||
body: "Automated update for Python releases."
|
body: "Automated update for Python releases."
|
||||||
|
|
21
Cargo.lock
generated
21
Cargo.lock
generated
|
@ -3627,6 +3627,19 @@ dependencies = [
|
||||||
"serde",
|
"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]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.10.9"
|
version = "0.10.9"
|
||||||
|
@ -4528,6 +4541,12 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unsafe-libyaml"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unscanny"
|
name = "unscanny"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -5049,10 +5068,12 @@ dependencies = [
|
||||||
"owo-colors",
|
"owo-colors",
|
||||||
"poloto",
|
"poloto",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
|
"reqwest",
|
||||||
"resvg",
|
"resvg",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"serde_yaml",
|
||||||
"tagu",
|
"tagu",
|
||||||
"textwrap",
|
"textwrap",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|
|
@ -44,10 +44,12 @@ markdown = { version = "1.0.0" }
|
||||||
owo-colors = { workspace = true }
|
owo-colors = { workspace = true }
|
||||||
poloto = { version = "19.1.2", optional = true }
|
poloto = { version = "19.1.2", optional = true }
|
||||||
pretty_assertions = { version = "1.4.1" }
|
pretty_assertions = { version = "1.4.1" }
|
||||||
|
reqwest = { workspace = true }
|
||||||
resvg = { version = "0.29.0", optional = true }
|
resvg = { version = "0.29.0", optional = true }
|
||||||
schemars = { workspace = true }
|
schemars = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
serde_yaml = { version = "0.9.34" }
|
||||||
tagu = { version = "0.1.6", optional = true }
|
tagu = { version = "0.1.6", optional = true }
|
||||||
textwrap = { workspace = true }
|
textwrap = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
|
|
|
@ -4,7 +4,7 @@ use anyhow::Result;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
generate_cli_reference, generate_env_vars_reference, generate_json_schema,
|
generate_cli_reference, generate_env_vars_reference, generate_json_schema,
|
||||||
generate_options_reference,
|
generate_options_reference, generate_sysconfig_mappings,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(clap::Args)]
|
#[derive(clap::Args)]
|
||||||
|
@ -26,10 +26,12 @@ pub(crate) enum Mode {
|
||||||
DryRun,
|
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_json_schema::main(&generate_json_schema::Args { mode: args.mode })?;
|
||||||
generate_options_reference::main(&generate_options_reference::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_cli_reference::main(&generate_cli_reference::Args { mode: args.mode })?;
|
||||||
generate_env_vars_reference::main(&generate_env_vars_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(())
|
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_env_vars_reference::Args as GenerateEnvVarsReferenceArgs;
|
||||||
use crate::generate_json_schema::Args as GenerateJsonSchemaArgs;
|
use crate::generate_json_schema::Args as GenerateJsonSchemaArgs;
|
||||||
use crate::generate_options_reference::Args as GenerateOptionsReferenceArgs;
|
use crate::generate_options_reference::Args as GenerateOptionsReferenceArgs;
|
||||||
|
use crate::generate_sysconfig_mappings::Args as GenerateSysconfigMetadataArgs;
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
use crate::render_benchmarks::RenderBenchmarksArgs;
|
use crate::render_benchmarks::RenderBenchmarksArgs;
|
||||||
use crate::wheel_metadata::WheelMetadataArgs;
|
use crate::wheel_metadata::WheelMetadataArgs;
|
||||||
|
@ -22,6 +23,7 @@ mod generate_cli_reference;
|
||||||
mod generate_env_vars_reference;
|
mod generate_env_vars_reference;
|
||||||
mod generate_json_schema;
|
mod generate_json_schema;
|
||||||
mod generate_options_reference;
|
mod generate_options_reference;
|
||||||
|
mod generate_sysconfig_mappings;
|
||||||
mod render_benchmarks;
|
mod render_benchmarks;
|
||||||
mod wheel_metadata;
|
mod wheel_metadata;
|
||||||
|
|
||||||
|
@ -45,6 +47,8 @@ enum Cli {
|
||||||
GenerateCliReference(GenerateCliReferenceArgs),
|
GenerateCliReference(GenerateCliReferenceArgs),
|
||||||
/// Generate the environment variables reference for the documentation.
|
/// Generate the environment variables reference for the documentation.
|
||||||
GenerateEnvVarsReference(GenerateEnvVarsReferenceArgs),
|
GenerateEnvVarsReference(GenerateEnvVarsReferenceArgs),
|
||||||
|
/// Generate the sysconfig metadata from derived targets.
|
||||||
|
GenerateSysconfigMetadata(GenerateSysconfigMetadataArgs),
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
/// Render the benchmarks.
|
/// Render the benchmarks.
|
||||||
RenderBenchmarks(RenderBenchmarksArgs),
|
RenderBenchmarks(RenderBenchmarksArgs),
|
||||||
|
@ -57,11 +61,12 @@ pub async fn run() -> Result<()> {
|
||||||
Cli::WheelMetadata(args) => wheel_metadata::wheel_metadata(args).await?,
|
Cli::WheelMetadata(args) => wheel_metadata::wheel_metadata(args).await?,
|
||||||
Cli::Compile(args) => compile::compile(args).await?,
|
Cli::Compile(args) => compile::compile(args).await?,
|
||||||
Cli::ClearCompile(args) => clear_compile::clear_compile(&args)?,
|
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::GenerateJSONSchema(args) => generate_json_schema::main(&args)?,
|
||||||
Cli::GenerateOptionsReference(args) => generate_options_reference::main(&args)?,
|
Cli::GenerateOptionsReference(args) => generate_options_reference::main(&args)?,
|
||||||
Cli::GenerateCliReference(args) => generate_cli_reference::main(&args)?,
|
Cli::GenerateCliReference(args) => generate_cli_reference::main(&args)?,
|
||||||
Cli::GenerateEnvVarsReference(args) => generate_env_vars_reference::main(&args)?,
|
Cli::GenerateEnvVarsReference(args) => generate_env_vars_reference::main(&args)?,
|
||||||
|
Cli::GenerateSysconfigMetadata(args) => generate_sysconfig_mappings::main(&args).await?,
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
Cli::RenderBenchmarks(args) => render_benchmarks::render_benchmarks(&args)?,
|
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::borrow::Cow;
|
||||||
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 itertools::{Either, Itertools};
|
use itertools::{Either, Itertools};
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
|
use crate::sysconfig::generated_mappings::DEFAULT_VARIABLE_UPDATES;
|
||||||
use crate::sysconfig::parser::{Error as ParseError, SysconfigData, Value};
|
use crate::sysconfig::parser::{Error as ParseError, SysconfigData, Value};
|
||||||
|
|
||||||
mod cursor;
|
mod cursor;
|
||||||
|
mod generated_mappings;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
mod replacements;
|
||||||
/// 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(),
|
|
||||||
}],
|
|
||||||
),
|
|
||||||
])
|
|
||||||
});
|
|
||||||
|
|
||||||
/// Update the `sysconfig` data in a Python installation.
|
/// Update the `sysconfig` data in a Python installation.
|
||||||
pub(crate) fn update_sysconfig(
|
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