From 293514d68e3635c9948f8a48604eddb2002a235d Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Mon, 6 Jul 2026 14:57:33 +0200 Subject: [PATCH 1/4] Add more build-info functions to c-api --- crates/capi/src/pylifecycle.rs | 33 +++++++++++++++++++++++++++++++++ crates/vm/src/stdlib/sys.rs | 9 +++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/crates/capi/src/pylifecycle.rs b/crates/capi/src/pylifecycle.rs index de673b33f0a..5a51f4a31bf 100644 --- a/crates/capi/src/pylifecycle.rs +++ b/crates/capi/src/pylifecycle.rs @@ -4,6 +4,7 @@ use crate::pystate::ensure_thread_has_vm_attached; use alloc::ffi::CString; use core::ffi::{c_char, c_int, c_ulong}; use rustpython_vm::common::rc::PyRc; +use rustpython_vm::stdlib::sys; use rustpython_vm::version::{MAJOR, MICRO, MINOR, VERSION_HEX}; use rustpython_vm::vm::thread::ThreadedVirtualMachine; use rustpython_vm::{Context, Interpreter}; @@ -80,6 +81,38 @@ pub extern "C" fn Py_GetVersion() -> *const c_char { VERSION.as_ptr() } +#[unsafe(no_mangle)] +pub extern "C" fn Py_GetBuildInfo() -> *const c_char { + static BUILD_INFO: LazyLock = LazyLock::new(|| { + CString::new(sys::BUILD_INFO).expect("build info must not contain interior NULs") + }); + BUILD_INFO.as_ptr() +} + +#[unsafe(no_mangle)] +pub extern "C" fn Py_GetCompiler() -> *const c_char { + static COMPILER: LazyLock = LazyLock::new(|| { + CString::new(sys::COMPILER).expect("compiler must not contain interior NULs") + }); + COMPILER.as_ptr() +} + +#[unsafe(no_mangle)] +pub extern "C" fn Py_GetCopyright() -> *const c_char { + static COPYRIGHT: LazyLock = LazyLock::new(|| { + CString::new(sys::COPYRIGHT).expect("copyright must not contain interior NULs") + }); + COPYRIGHT.as_ptr() +} + +#[unsafe(no_mangle)] +pub extern "C" fn Py_GetPlatform() -> *const c_char { + static PLATFORM: LazyLock = LazyLock::new(|| { + CString::new(sys::PLATFORM).expect("platform must not contain interior NULs") + }); + PLATFORM.as_ptr() +} + #[cfg(test)] mod tests { use pyo3::prelude::*; diff --git a/crates/vm/src/stdlib/sys.rs b/crates/vm/src/stdlib/sys.rs index b8fe578f238..9fcd40c7888 100644 --- a/crates/vm/src/stdlib/sys.rs +++ b/crates/vm/src/stdlib/sys.rs @@ -4,6 +4,7 @@ use crate::{Py, PyPayload, PyResult, VirtualMachine, builtins::PyModule, convert #[cfg(all(not(feature = "host_env"), feature = "stdio"))] pub(crate) use sys::SandboxStdio; +pub use sys::{BUILD_INFO, COMPILER, COPYRIGHT, PLATFORM, VERSION}; pub(crate) use sys::{DOC, MAXSIZE, RUST_MULTIARCH, UnraisableHookArgsData, module_def, multiarch}; #[pymodule(name = "_jit")] @@ -222,7 +223,7 @@ pub mod sys { #[pyattr(name = "api_version")] const API_VERSION: u32 = 0x0; // what C api? #[pyattr(name = "copyright")] - const COPYRIGHT: &str = "Copyright (c) 2019 RustPython Team"; + pub const COPYRIGHT: &str = "Copyright (c) 2019 RustPython Team"; #[pyattr(name = "float_repr_style")] const FLOAT_REPR_STYLE: &str = "short"; #[pyattr(name = "_framework")] @@ -708,7 +709,11 @@ pub mod sys { } #[pyattr(name = "version")] - const VERSION: &str = version::RUSTPYTHON_VERSION; + pub const VERSION: &str = version::RUSTPYTHON_VERSION; + + pub const BUILD_INFO: &str = version::RUSTPYTHON_BUILD_INFO; + + pub const COMPILER: &str = "[Rust]"; // Note: This is Python DLL version in CPython, but we arbitrary fill it for compatibility #[cfg(windows)] From 7881dfdeac4736b59d962cf334e419634f894856 Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Tue, 7 Jul 2026 11:04:17 +0200 Subject: [PATCH 2/4] Use CStr for COMPILER/COPYRIGHT/PLATFORM --- crates/capi/src/pylifecycle.rs | 15 +++------------ crates/vm/src/builtins/str.rs | 7 +++++++ crates/vm/src/stdlib/sys.rs | 23 ++++++++++++----------- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/crates/capi/src/pylifecycle.rs b/crates/capi/src/pylifecycle.rs index 5a51f4a31bf..bf4081a2f24 100644 --- a/crates/capi/src/pylifecycle.rs +++ b/crates/capi/src/pylifecycle.rs @@ -91,26 +91,17 @@ pub extern "C" fn Py_GetBuildInfo() -> *const c_char { #[unsafe(no_mangle)] pub extern "C" fn Py_GetCompiler() -> *const c_char { - static COMPILER: LazyLock = LazyLock::new(|| { - CString::new(sys::COMPILER).expect("compiler must not contain interior NULs") - }); - COMPILER.as_ptr() + sys::COMPILER.as_ptr() } #[unsafe(no_mangle)] pub extern "C" fn Py_GetCopyright() -> *const c_char { - static COPYRIGHT: LazyLock = LazyLock::new(|| { - CString::new(sys::COPYRIGHT).expect("copyright must not contain interior NULs") - }); - COPYRIGHT.as_ptr() + sys::COPYRIGHT.as_ptr() } #[unsafe(no_mangle)] pub extern "C" fn Py_GetPlatform() -> *const c_char { - static PLATFORM: LazyLock = LazyLock::new(|| { - CString::new(sys::PLATFORM).expect("platform must not contain interior NULs") - }); - PLATFORM.as_ptr() + sys::PLATFORM.as_ptr() } #[cfg(test)] diff --git a/crates/vm/src/builtins/str.rs b/crates/vm/src/builtins/str.rs index a72a272679b..151e596fa8d 100644 --- a/crates/vm/src/builtins/str.rs +++ b/crates/vm/src/builtins/str.rs @@ -35,6 +35,7 @@ use crate::{ use alloc::{borrow::Cow, fmt}; use ascii::{AsciiChar, AsciiStr, AsciiString}; use bstr::ByteSlice; +use core::ffi::CStr; use core::{char, mem, ops::Range}; use itertools::Itertools; use num_traits::ToPrimitive; @@ -1868,6 +1869,12 @@ impl ToPyObject for &String { } } +impl ToPyObject for &CStr { + fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef { + vm.ctx.new_str(self.to_string_lossy()).into() + } +} + impl ToPyObject for &Wtf8 { fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef { vm.ctx.new_str(self).into() diff --git a/crates/vm/src/stdlib/sys.rs b/crates/vm/src/stdlib/sys.rs index 9fcd40c7888..1c6466cb351 100644 --- a/crates/vm/src/stdlib/sys.rs +++ b/crates/vm/src/stdlib/sys.rs @@ -51,6 +51,7 @@ pub mod sys { version, vm::{Settings, VirtualMachine}, }; + use core::ffi::CStr; use core::sync::atomic::Ordering; use num_traits::ToPrimitive; use std::{ @@ -223,7 +224,7 @@ pub mod sys { #[pyattr(name = "api_version")] const API_VERSION: u32 = 0x0; // what C api? #[pyattr(name = "copyright")] - pub const COPYRIGHT: &str = "Copyright (c) 2019 RustPython Team"; + pub const COPYRIGHT: &CStr = c"Copyright (c) 2019 RustPython Team"; #[pyattr(name = "float_repr_style")] const FLOAT_REPR_STYLE: &str = "short"; #[pyattr(name = "_framework")] @@ -236,14 +237,14 @@ pub mod sys { const MAXUNICODE: u32 = core::char::MAX as u32; #[pyattr(name = "platform")] - pub const PLATFORM: &str = cfg_select! { - target_os = "linux" => "linux", - target_os = "android" => "android", - target_os = "macos" => "darwin", - target_os = "ios" => "ios", - windows => "win32", - target_os = "wasi" => "wasi", - _ => "unknown" + pub const PLATFORM: &CStr = cfg_select! { + target_os = "linux" => c"linux", + target_os = "android" => c"android", + target_os = "macos" => c"darwin", + target_os = "ios" => c"ios", + windows => c"win32", + target_os = "wasi" => c"wasi", + _ => c"unknown" }; #[pyattr(name = "ps1")] @@ -713,7 +714,7 @@ pub mod sys { pub const BUILD_INFO: &str = version::RUSTPYTHON_BUILD_INFO; - pub const COMPILER: &str = "[Rust]"; + pub const COMPILER: &CStr = c"[Rust]"; // Note: This is Python DLL version in CPython, but we arbitrary fill it for compatibility #[cfg(windows)] @@ -1916,7 +1917,7 @@ pub(crate) fn sysconfigdata_name() -> String { format!( "_sysconfigdata_{}_{}_{}", sys::ABIFLAGS, - sys::PLATFORM, + sys::PLATFORM.to_string_lossy(), sys::multiarch() ) } From 287190d377e5fef35171f80f4f1ddb658d16b3d1 Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers <7943856+bschoenmaeckers@users.noreply.github.com> Date: Tue, 7 Jul 2026 17:17:27 +0200 Subject: [PATCH 3/4] Update crates/vm/src/builtins/str.rs Co-authored-by: Jeong, YunWon <69878+youknowone@users.noreply.github.com> --- crates/vm/src/builtins/str.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/vm/src/builtins/str.rs b/crates/vm/src/builtins/str.rs index 151e596fa8d..52307d2624b 100644 --- a/crates/vm/src/builtins/str.rs +++ b/crates/vm/src/builtins/str.rs @@ -1871,7 +1871,8 @@ impl ToPyObject for &String { impl ToPyObject for &CStr { fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef { - vm.ctx.new_str(self.to_string_lossy()).into() + let s = self.to_str().expect("ToPyObject expects utf-8 CStr"); + vm.ctx.new_str(s).into() } } From b5fd405274a6a67a84396415296aa53124a4a5ad Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Tue, 7 Jul 2026 17:25:39 +0200 Subject: [PATCH 4/4] Review --- crates/capi/src/pylifecycle.rs | 6 +++--- crates/vm/src/stdlib/sys.rs | 8 ++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/crates/capi/src/pylifecycle.rs b/crates/capi/src/pylifecycle.rs index bf4081a2f24..534c97956fe 100644 --- a/crates/capi/src/pylifecycle.rs +++ b/crates/capi/src/pylifecycle.rs @@ -5,7 +5,7 @@ use alloc::ffi::CString; use core::ffi::{c_char, c_int, c_ulong}; use rustpython_vm::common::rc::PyRc; use rustpython_vm::stdlib::sys; -use rustpython_vm::version::{MAJOR, MICRO, MINOR, VERSION_HEX}; +use rustpython_vm::version::{MAJOR, MICRO, MINOR, RUSTPYTHON_BUILD_INFO, VERSION_HEX}; use rustpython_vm::vm::thread::ThreadedVirtualMachine; use rustpython_vm::{Context, Interpreter}; use std::sync::{LazyLock, Mutex}; @@ -84,14 +84,14 @@ pub extern "C" fn Py_GetVersion() -> *const c_char { #[unsafe(no_mangle)] pub extern "C" fn Py_GetBuildInfo() -> *const c_char { static BUILD_INFO: LazyLock = LazyLock::new(|| { - CString::new(sys::BUILD_INFO).expect("build info must not contain interior NULs") + CString::new(RUSTPYTHON_BUILD_INFO).expect("build info must not contain interior NULs") }); BUILD_INFO.as_ptr() } #[unsafe(no_mangle)] pub extern "C" fn Py_GetCompiler() -> *const c_char { - sys::COMPILER.as_ptr() + c"[RUST]".as_ptr() } #[unsafe(no_mangle)] diff --git a/crates/vm/src/stdlib/sys.rs b/crates/vm/src/stdlib/sys.rs index 1c6466cb351..2e665026959 100644 --- a/crates/vm/src/stdlib/sys.rs +++ b/crates/vm/src/stdlib/sys.rs @@ -4,7 +4,7 @@ use crate::{Py, PyPayload, PyResult, VirtualMachine, builtins::PyModule, convert #[cfg(all(not(feature = "host_env"), feature = "stdio"))] pub(crate) use sys::SandboxStdio; -pub use sys::{BUILD_INFO, COMPILER, COPYRIGHT, PLATFORM, VERSION}; +pub use sys::{COPYRIGHT, PLATFORM}; pub(crate) use sys::{DOC, MAXSIZE, RUST_MULTIARCH, UnraisableHookArgsData, module_def, multiarch}; #[pymodule(name = "_jit")] @@ -710,11 +710,7 @@ pub mod sys { } #[pyattr(name = "version")] - pub const VERSION: &str = version::RUSTPYTHON_VERSION; - - pub const BUILD_INFO: &str = version::RUSTPYTHON_BUILD_INFO; - - pub const COMPILER: &CStr = c"[Rust]"; + const VERSION: &str = version::RUSTPYTHON_VERSION; // Note: This is Python DLL version in CPython, but we arbitrary fill it for compatibility #[cfg(windows)]