24
24
//! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
25
//! ```
26
26
27
+ use std:: collections:: BTreeMap ;
27
28
use std:: io:: Write ;
28
29
use std:: path:: { Path , PathBuf } ;
29
30
use std:: str:: FromStr ;
31
+ use std:: sync:: LazyLock ;
30
32
31
33
use tracing:: trace;
32
34
@@ -35,6 +37,102 @@ use crate::sysconfig::parser::{Error as ParseError, SysconfigData, Value};
35
37
mod cursor;
36
38
mod parser;
37
39
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
+
38
136
/// Update the `sysconfig` data in a Python installation.
39
137
pub ( crate ) fn update_sysconfig (
40
138
install_root : & Path ,
@@ -157,7 +255,12 @@ fn patch_sysconfigdata(mut data: SysconfigData, real_prefix: &Path) -> Sysconfig
157
255
continue ;
158
256
} ;
159
257
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
+
161
264
if * value != patched {
162
265
trace ! ( "Updated `{key}` from `{value}` to `{patched}`" ) ;
163
266
count += 1 ;
@@ -233,6 +336,33 @@ mod tests {
233
336
Ok ( ( ) )
234
337
}
235
338
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
+
236
366
#[ test]
237
367
fn remove_isysroot ( ) -> Result < ( ) , Error > {
238
368
let sysconfigdata = [
@@ -248,7 +378,7 @@ mod tests {
248
378
insta:: assert_snapshot!( data. to_string_pretty( ) ?, @r###"
249
379
# system configuration generated and used by the sysconfig module
250
380
build_time_vars = {
251
- "BLDSHARED": "clang -bundle -undefined dynamic_lookup -arch arm64",
381
+ "BLDSHARED": "cc -bundle -undefined dynamic_lookup -arch arm64",
252
382
"PYTHON_BUILD_STANDALONE": 1
253
383
}
254
384
"### ) ;
0 commit comments