Skip to content

Commit 1d5086c

Browse files
committed
feat(uv-python): support patching additional sysconfig data
1 parent 9e2e9f2 commit 1d5086c

File tree

1 file changed

+132
-2
lines changed
  • crates/uv-python/src/sysconfig

1 file changed

+132
-2
lines changed

crates/uv-python/src/sysconfig/mod.rs

Lines changed: 132 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424
//! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2525
//! ```
2626
27+
use std::collections::BTreeMap;
2728
use std::io::Write;
2829
use std::path::{Path, PathBuf};
2930
use std::str::FromStr;
31+
use std::sync::LazyLock;
3032

3133
use tracing::trace;
3234

@@ -35,6 +37,102 @@ use crate::sysconfig::parser::{Error as ParseError, SysconfigData, Value};
3537
mod cursor;
3638
mod parser;
3739

40+
/// Replacement mode for sysconfig values.
41+
#[derive(Debug)]
42+
enum ReplacementMode {
43+
Partial { from: String },
44+
Full,
45+
}
46+
47+
/// A replacement entry to patch in sysconfig data.
48+
#[derive(Debug)]
49+
struct ReplacementEntry {
50+
mode: ReplacementMode,
51+
to: String,
52+
}
53+
54+
impl ReplacementEntry {
55+
/// Patches a sysconfig value either partially (replacing a specific word) or fully.
56+
fn patch(&self, entry: &str) -> String {
57+
match &self.mode {
58+
ReplacementMode::Partial { from } => entry
59+
.split_whitespace()
60+
.map(|word| if word == from { &self.to } else { word })
61+
.collect::<Vec<_>>()
62+
.join(" "),
63+
ReplacementMode::Full => self.to.clone(),
64+
}
65+
}
66+
}
67+
68+
/// Mapping for sysconfig keys to lookup and replace with the appropriate entry.
69+
static DEFAULT_VARIABLE_UPDATES: LazyLock<BTreeMap<String, ReplacementEntry>> =
70+
LazyLock::new(|| {
71+
BTreeMap::from_iter([
72+
(
73+
"CC".to_string(),
74+
ReplacementEntry {
75+
mode: ReplacementMode::Partial {
76+
from: "clang".to_string(),
77+
},
78+
to: "cc".to_string(),
79+
},
80+
),
81+
(
82+
"CXX".to_string(),
83+
ReplacementEntry {
84+
mode: ReplacementMode::Partial {
85+
from: "clang++".to_string(),
86+
},
87+
to: "c++".to_string(),
88+
},
89+
),
90+
(
91+
"BLDSHARED".to_string(),
92+
ReplacementEntry {
93+
mode: ReplacementMode::Partial {
94+
from: "clang".to_string(),
95+
},
96+
to: "cc".to_string(),
97+
},
98+
),
99+
(
100+
"LDSHARED".to_string(),
101+
ReplacementEntry {
102+
mode: ReplacementMode::Partial {
103+
from: "clang".to_string(),
104+
},
105+
to: "cc".to_string(),
106+
},
107+
),
108+
(
109+
"LDCXXSHARED".to_string(),
110+
ReplacementEntry {
111+
mode: ReplacementMode::Partial {
112+
from: "clang++".to_string(),
113+
},
114+
to: "c++".to_string(),
115+
},
116+
),
117+
(
118+
"LINKCC".to_string(),
119+
ReplacementEntry {
120+
mode: ReplacementMode::Partial {
121+
from: "clang".to_string(),
122+
},
123+
to: "cc".to_string(),
124+
},
125+
),
126+
(
127+
"AR".to_string(),
128+
ReplacementEntry {
129+
mode: ReplacementMode::Full,
130+
to: "ar".to_string(),
131+
},
132+
),
133+
])
134+
});
135+
38136
/// Update the `sysconfig` data in a Python installation.
39137
pub(crate) fn update_sysconfig(
40138
install_root: &Path,
@@ -157,7 +255,12 @@ fn patch_sysconfigdata(mut data: SysconfigData, real_prefix: &Path) -> Sysconfig
157255
continue;
158256
};
159257
let patched = update_prefix(value, real_prefix);
160-
let patched = remove_isysroot(&patched);
258+
let mut patched = remove_isysroot(&patched);
259+
260+
if let Some(replacement_entry) = DEFAULT_VARIABLE_UPDATES.get(key) {
261+
patched = replacement_entry.patch(&patched);
262+
}
263+
161264
if *value != patched {
162265
trace!("Updated `{key}` from `{value}` to `{patched}`");
163266
count += 1;
@@ -233,6 +336,33 @@ mod tests {
233336
Ok(())
234337
}
235338

339+
#[test]
340+
fn test_replacements() -> Result<(), Error> {
341+
let sysconfigdata = [
342+
("CC", "clang -pthread"),
343+
("CXX", "clang++ -pthread"),
344+
("AR", "/tools/llvm/bin/llvm-ar"),
345+
]
346+
.into_iter()
347+
.map(|(k, v)| (k.to_string(), Value::String(v.to_string())))
348+
.collect::<SysconfigData>();
349+
350+
let real_prefix = Path::new("/real/prefix");
351+
let data = patch_sysconfigdata(sysconfigdata, real_prefix);
352+
353+
insta::assert_snapshot!(data.to_string_pretty()?, @r###"
354+
# system configuration generated and used by the sysconfig module
355+
build_time_vars = {
356+
"AR": "ar",
357+
"CC": "cc -pthread",
358+
"CXX": "c++ -pthread",
359+
"PYTHON_BUILD_STANDALONE": 1
360+
}
361+
"###);
362+
363+
Ok(())
364+
}
365+
236366
#[test]
237367
fn remove_isysroot() -> Result<(), Error> {
238368
let sysconfigdata = [
@@ -248,7 +378,7 @@ mod tests {
248378
insta::assert_snapshot!(data.to_string_pretty()?, @r###"
249379
# system configuration generated and used by the sysconfig module
250380
build_time_vars = {
251-
"BLDSHARED": "clang -bundle -undefined dynamic_lookup -arch arm64",
381+
"BLDSHARED": "cc -bundle -undefined dynamic_lookup -arch arm64",
252382
"PYTHON_BUILD_STANDALONE": 1
253383
}
254384
"###);

0 commit comments

Comments
 (0)