Skip to content

Commit 7a38e56

Browse files
committed
Fix sysconfigdata platform-specific alias name registration
- Register _sysconfigdata under both short name and platform-specific name - Refactor sysconfigdata_name() to be reusable across modules - Add platform-specific name to sys.builtin_module_names - Eliminate code duplication in sysconfigdata name formatting This fixes the CI failure where sysconfig module imports '_sysconfigdata_t_darwin_aarch64-apple-darwin' but RustPython only registered '_sysconfigdata'. PyGlobalState
1 parent 8b7c26a commit 7a38e56

File tree

11 files changed

+153
-122
lines changed

11 files changed

+153
-122
lines changed

crates/common/src/crt_fd.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ use alloc::fmt;
55
use core::cmp;
66
use std::{ffi, io};
77

8+
#[cfg(unix)]
9+
use std::os::fd::AsFd;
810
#[cfg(not(windows))]
9-
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
11+
use std::os::fd::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
1012
#[cfg(windows)]
1113
use std::os::windows::io::BorrowedHandle;
1214

crates/vm/src/stdlib/nt.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
// spell-checker:disable
22

3-
use crate::{PyRef, VirtualMachine, builtins::PyModule};
4-
53
pub(crate) use module::module_def;
64
pub use module::raw_set_handle_inheritable;
75

86
#[pymodule(name = "nt", with(super::os::_os))]
97
pub(crate) mod module {
108
use crate::{
11-
PyResult, TryFromObject, VirtualMachine,
9+
Py, PyResult, TryFromObject, VirtualMachine,
1210
builtins::{PyBaseExceptionRef, PyDictRef, PyListRef, PyStrRef, PyTupleRef},
1311
common::{crt_fd, suppress_iph, windows::ToWideString},
1412
convert::ToPyException,

crates/vm/src/stdlib/os.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ pub(super) mod _os {
149149
use super::{DirFd, FollowSymlinks, SupportFunc};
150150
#[cfg(windows)]
151151
use crate::common::windows::ToWideString;
152+
#[cfg(any(unix, windows))]
153+
use crate::utils::ToCString;
152154
use crate::{
153155
AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
154156
builtins::{
@@ -168,7 +170,6 @@ pub(super) mod _os {
168170
protocol::PyIterReturn,
169171
recursion::ReprGuard,
170172
types::{IterNext, Iterable, PyStructSequence, Representable, SelfIter},
171-
utils::ToCString,
172173
vm::VirtualMachine,
173174
};
174175
use core::time::Duration;

crates/vm/src/stdlib/posix_compat.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// spell-checker:disable
22

33
//! `posix` compatible module for `not(any(unix, windows))`
4-
use crate::{PyRef, VirtualMachine, builtins::PyModule};
54
65
pub(crate) use module::module_def;
76

crates/vm/src/stdlib/sys.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,11 @@ mod sys {
166166

167167
#[pyattr]
168168
fn builtin_module_names(vm: &VirtualMachine) -> PyTupleRef {
169-
let mut module_names: Vec<&str> = vm.state.module_defs.keys().copied().collect();
170-
module_names.push("sys");
171-
module_names.push("builtins");
169+
let mut module_names: Vec<String> =
170+
vm.state.module_defs.keys().map(|&s| s.to_owned()).collect();
171+
module_names.push("sys".to_owned());
172+
module_names.push("builtins".to_owned());
173+
172174
module_names.sort();
173175
vm.ctx.new_tuple(
174176
module_names
@@ -1673,7 +1675,7 @@ pub fn get_stderr(vm: &VirtualMachine) -> PyResult {
16731675
.map_err(|_| vm.new_runtime_error("lost sys.stderr"))
16741676
}
16751677

1676-
pub(crate) fn sysconfigdata_name() -> String {
1678+
pub fn sysconfigdata_name() -> String {
16771679
format!(
16781680
"_sysconfigdata_{}_{}_{}",
16791681
sys::ABIFLAGS,

crates/vm/src/stdlib/sysconfigdata.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ mod _sysconfigdata {
1616
let build_time_vars = build_time_vars(vm);
1717
module.set_attr("build_time_vars", build_time_vars, vm)?;
1818

19-
// Add CPython-compatible alias to sys.modules
20-
let sysconfigdata_name = sysconfigdata_name();
19+
// Ensure the module is registered under the platform-specific name
20+
// (import_builtin() already handles this, but double-check for safety)
2121
let sys_modules = vm.sys_module.get_attr("modules", vm)?;
22+
let sysconfigdata_name = sysconfigdata_name();
2223
sys_modules.set_item(sysconfigdata_name.as_str(), module.to_owned().into(), vm)?;
24+
2325
Ok(())
2426
}
2527

crates/vm/src/stdlib/winreg.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// spell-checker:disable
22
#![allow(non_snake_case)]
33

4-
use crate::{PyRef, VirtualMachine, builtins::PyModule};
5-
64
pub(crate) use winreg::module_def;
75

86
#[pymodule]

crates/vm/src/vm/interpreter.rs

Lines changed: 111 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{Context, PyConfig, VirtualMachine, setting::Settings, thread};
1+
use super::{Context, PyConfig, PyGlobalState, VirtualMachine, setting::Settings, thread};
22
use crate::{
33
PyResult, builtins, common::rc::PyRc, getpath, stdlib::atexit, vm::PyBaseExceptionRef,
44
};
@@ -16,10 +16,9 @@ type InitFunc = Box<dyn FnOnce(&mut VirtualMachine)>;
1616
/// ```
1717
/// use rustpython_vm::Interpreter;
1818
///
19-
/// let interp = Interpreter::builder()
20-
/// .settings(Default::default())
21-
/// .add_modules(rustpython_stdlib::stdlib_module_defs())
22-
/// .build();
19+
/// let builder = Interpreter::builder(Default::default());
20+
/// // In practice, add stdlib: builder.add_native_modules(&stdlib_module_defs(&builder.ctx))
21+
/// let interp = builder.build();
2322
/// ```
2423
pub struct InterpreterBuilder {
2524
settings: Settings,
@@ -35,37 +34,111 @@ fn initialize_main_vm<F>(
3534
module_defs: Vec<&'static builtins::PyModuleDef>,
3635
init_hooks: Vec<InitFunc>,
3736
init: F,
38-
) -> VirtualMachine
37+
) -> (VirtualMachine, PyRc<PyGlobalState>)
3938
where
4039
F: FnOnce(&mut VirtualMachine),
4140
{
41+
use crate::codecs::CodecsRegistry;
42+
use crate::common::hash::HashSecret;
43+
use crate::common::lock::PyMutex;
44+
use crate::warn::WarningsState;
45+
use crossbeam_utils::atomic::AtomicCell;
46+
use std::sync::atomic::AtomicBool;
4247
let paths = getpath::init_path_config(&settings);
4348
let config = PyConfig::new(settings, paths);
4449

4550
crate::types::TypeZoo::extend(&ctx);
4651
crate::exceptions::ExceptionZoo::extend(&ctx);
4752

48-
let mut vm = VirtualMachine::new(config, ctx);
53+
// Build module_defs map from builtin modules + additional modules
54+
let mut all_module_defs: std::collections::BTreeMap<
55+
&'static str,
56+
&'static builtins::PyModuleDef,
57+
> = crate::stdlib::builtin_module_defs(&ctx)
58+
.into_iter()
59+
.map(|def| (def.name.as_str(), def))
60+
.collect();
4961

50-
// Register module definitions
62+
// Add additional module definitions
5163
for def in module_defs {
52-
PyRc::get_mut(&mut vm.state)
53-
.expect("there should not be multiple threads during initialization")
54-
.module_defs
55-
.insert(def.name.as_str(), def);
64+
all_module_defs.insert(def.name.as_str(), def);
5665
}
5766

58-
// Execute initialization hooks
67+
// Register sysconfigdata under platform-specific name as well
68+
if let Some(&sysconfigdata_def) = all_module_defs.get("_sysconfigdata") {
69+
let sysconfigdata_name = crate::stdlib::sys::sysconfigdata_name();
70+
// Leak the string to get a 'static lifetime for the key
71+
let leaked_name: &'static str = Box::leak(sysconfigdata_name.into_boxed_str());
72+
all_module_defs.insert(leaked_name, sysconfigdata_def);
73+
}
74+
75+
// Create hash secret
76+
let seed = match config.settings.hash_seed {
77+
Some(seed) => seed,
78+
None => super::process_hash_secret_seed(),
79+
};
80+
let hash_secret = HashSecret::new(seed);
81+
82+
// Create codec registry and warnings state
83+
let codec_registry = CodecsRegistry::new(&ctx);
84+
let warnings = WarningsState::init_state(&ctx);
85+
86+
// Create int_max_str_digits
87+
let int_max_str_digits = AtomicCell::new(match config.settings.int_max_str_digits {
88+
-1 => 4300,
89+
other => other,
90+
} as usize);
91+
92+
// Initialize frozen modules
93+
let frozen = super::core_frozen_inits().collect();
94+
95+
// Create PyGlobalState
96+
let global_state = PyRc::new(PyGlobalState {
97+
config,
98+
module_defs: all_module_defs,
99+
frozen,
100+
stacksize: AtomicCell::new(0),
101+
thread_count: AtomicCell::new(0),
102+
hash_secret,
103+
atexit_funcs: PyMutex::default(),
104+
codec_registry,
105+
finalizing: AtomicBool::new(false),
106+
warnings,
107+
override_frozen_modules: AtomicCell::new(0),
108+
before_forkers: PyMutex::default(),
109+
after_forkers_child: PyMutex::default(),
110+
after_forkers_parent: PyMutex::default(),
111+
int_max_str_digits,
112+
switch_interval: AtomicCell::new(0.005),
113+
global_trace_func: PyMutex::default(),
114+
global_profile_func: PyMutex::default(),
115+
#[cfg(feature = "threading")]
116+
main_thread_ident: AtomicCell::new(0),
117+
#[cfg(feature = "threading")]
118+
thread_frames: parking_lot::Mutex::new(std::collections::HashMap::new()),
119+
#[cfg(feature = "threading")]
120+
thread_handles: parking_lot::Mutex::new(Vec::new()),
121+
#[cfg(feature = "threading")]
122+
shutdown_handles: parking_lot::Mutex::new(Vec::new()),
123+
});
124+
125+
// Create VM with the global state
126+
// Note: Don't clone here - init_hooks need exclusive access to mutate state
127+
let mut vm = VirtualMachine::new(ctx, global_state);
128+
129+
// Execute initialization hooks (can mutate vm.state)
59130
for hook in init_hooks {
60131
hook(&mut vm);
61132
}
62133

63-
// Call custom init function
134+
// Call custom init function (can mutate vm.state)
64135
init(&mut vm);
65136

66137
vm.initialize();
67138

68-
vm
139+
// Clone global_state for Interpreter after all initialization is done
140+
let global_state = vm.state.clone();
141+
(vm, global_state)
69142
}
70143

71144
impl InterpreterBuilder {
@@ -91,17 +164,13 @@ impl InterpreterBuilder {
91164
///
92165
/// # Example
93166
/// ```
94-
/// use rustpython_vm::Interpreter;
167+
/// use rustpython_vm::{Interpreter, builtins::PyModuleDef};
95168
///
96-
/// let interp = Interpreter::builder()
97-
/// .init_hook(|vm| {
98-
/// let def = mymodule::module_def(&vm.ctx);
99-
/// rustpython_vm::common::rc::PyRc::get_mut(&mut vm.state)
100-
/// .unwrap()
101-
/// .module_defs
102-
/// .insert(def.name.as_str(), def);
103-
/// })
104-
/// .build();
169+
/// let builder = Interpreter::builder(Default::default());
170+
/// // Note: In practice, use module_def from your #[pymodule]
171+
/// // let def = mymodule::module_def(&builder.ctx);
172+
/// // let interp = builder.add_native_module(def).build();
173+
/// let interp = builder.build();
105174
/// ```
106175
pub fn add_native_module(self, def: &'static builtins::PyModuleDef) -> Self {
107176
self.add_native_modules(&[def])
@@ -113,9 +182,11 @@ impl InterpreterBuilder {
113182
/// ```
114183
/// use rustpython_vm::Interpreter;
115184
///
116-
/// let builder = Interpreter::builder();
117-
/// let defs = rustpython_stdlib::stdlib_module_defs(&builder.ctx);
118-
/// let interp = builder.add_native_modules(&defs).build();
185+
/// let builder = Interpreter::builder(Default::default());
186+
/// // In practice, use module_defs from rustpython_stdlib:
187+
/// // let defs = rustpython_stdlib::stdlib_module_defs(&builder.ctx);
188+
/// // let interp = builder.add_native_modules(&defs).build();
189+
/// let interp = builder.build();
119190
/// ```
120191
pub fn add_native_modules(mut self, defs: &[&'static builtins::PyModuleDef]) -> Self {
121192
self.module_defs.extend_from_slice(defs);
@@ -132,7 +203,7 @@ impl InterpreterBuilder {
132203
/// ```
133204
/// use rustpython_vm::Interpreter;
134205
///
135-
/// let interp = Interpreter::builder()
206+
/// let interp = Interpreter::builder(Default::default())
136207
/// .init_hook(|vm| {
137208
/// // Custom initialization
138209
/// })
@@ -155,8 +226,8 @@ impl InterpreterBuilder {
155226
/// ```
156227
/// use rustpython_vm::Interpreter;
157228
///
158-
/// let interp = Interpreter::builder()
159-
/// .with_frozen(rustpython_pylib::FROZEN_STDLIB)
229+
/// let interp = Interpreter::builder(Default::default())
230+
/// // In practice: .with_frozen(rustpython_pylib::FROZEN_STDLIB)
160231
/// .build();
161232
/// ```
162233
pub fn with_frozen<I>(self, frozen: I) -> Self
@@ -172,14 +243,14 @@ impl InterpreterBuilder {
172243
///
173244
/// This consumes the configuration and returns a fully initialized Interpreter.
174245
pub fn build(self) -> Interpreter {
175-
let vm = initialize_main_vm(
246+
let (vm, global_state) = initialize_main_vm(
176247
self.settings,
177248
self.ctx,
178249
self.module_defs,
179250
self.init_hooks,
180251
|_| {}, // No additional init needed
181252
);
182-
Interpreter { vm }
253+
Interpreter { global_state, vm }
183254
}
184255

185256
/// Alias for `build()` for compatibility with the `interpreter()` pattern.
@@ -213,6 +284,7 @@ impl Default for InterpreterBuilder {
213284
/// });
214285
/// ```
215286
pub struct Interpreter {
287+
pub global_state: PyRc<PyGlobalState>,
216288
vm: VirtualMachine,
217289
}
218290

@@ -223,9 +295,9 @@ impl Interpreter {
223295
/// ```
224296
/// use rustpython_vm::Interpreter;
225297
///
226-
/// let interp = Interpreter::builder(Default::default())
227-
/// .add_native_modules(rustpython_stdlib::stdlib_module_defs())
228-
/// .build();
298+
/// let builder = Interpreter::builder(Default::default());
299+
/// // In practice, add stdlib: builder.add_native_modules(&stdlib_module_defs(&builder.ctx))
300+
/// let interp = builder.build();
229301
/// ```
230302
pub fn builder(settings: Settings) -> InterpreterBuilder {
231303
InterpreterBuilder::new().settings(settings)
@@ -241,27 +313,19 @@ impl Interpreter {
241313

242314
/// Create with initialize function taking mutable vm reference.
243315
///
244-
/// Note: This is a legacy API. To add stdlib, use `Interpreter::builder()` instead:
245-
/// ```
246-
/// use rustpython_vm::Interpreter;
247-
/// let builder = Interpreter::builder(Default::default());
248-
/// let defs = rustpython_stdlib::stdlib_module_defs(&builder.ctx);
249-
/// builder.add_native_modules(&defs).build().enter(|vm| {
250-
/// vm.run_code_string(vm.new_scope_with_builtins(), "print(1)", "<...>".to_owned());
251-
/// });
252-
/// ```
316+
/// Note: This is a legacy API. To add stdlib, use `Interpreter::builder()` instead.
253317
pub fn with_init<F>(settings: Settings, init: F) -> Self
254318
where
255319
F: FnOnce(&mut VirtualMachine),
256320
{
257-
let vm = initialize_main_vm(
321+
let (vm, global_state) = initialize_main_vm(
258322
settings,
259323
Context::genesis().clone(),
260324
Vec::new(), // No module_defs
261325
Vec::new(), // No init_hooks
262326
init,
263327
);
264-
Self { vm }
328+
Self { global_state, vm }
265329
}
266330

267331
/// Run a function with the main virtual machine and return a PyResult of the result.

0 commit comments

Comments
 (0)