Use cfg_select in a bunch more places (#7740)

This commit is contained in:
Noa
2026-05-04 15:26:16 -05:00
committed by GitHub
parent 0325fd429e
commit 02932384d6
23 changed files with 336 additions and 444 deletions

View File

@@ -1,12 +1,7 @@
#[cfg(not(feature = "threading"))]
use alloc::rc::Rc;
#[cfg(feature = "threading")]
use alloc::sync::Arc;
// type aliases instead of new-types because you can't do `fn method(self: PyRc<Self>)` with a
// newtype; requires the arbitrary_self_types unstable feature
#[cfg(feature = "threading")]
pub type PyRc<T> = Arc<T>;
#[cfg(not(feature = "threading"))]
pub type PyRc<T> = Rc<T>;
pub type PyRc<T> = cfg_select! {
feature = "threading" => alloc::sync::Arc::<T>,
_ => alloc::rc::Rc::<T>,
};

View File

@@ -20,10 +20,10 @@ const WEAK_COUNT: usize = 1 << STRONG_WIDTH;
reason = "refcount overflow must preserve upstream abort semantics"
)]
fn refcount_overflow() -> ! {
#[cfg(feature = "std")]
std::process::abort();
#[cfg(not(feature = "std"))]
core::panic!("refcount overflow");
cfg_select! {
feature = "std" => std::process::abort(),
_ => core::panic!("refcount overflow"),
}
}
/// State wraps reference count + flags in a single word (platform usize)

View File

@@ -7,12 +7,11 @@ use core::fmt;
use core::ops::{Bound, RangeBounds};
use core::sync::atomic::Ordering::Relaxed;
#[cfg(not(target_arch = "wasm32"))]
#[allow(non_camel_case_types)]
pub type wchar_t = libc::wchar_t;
#[cfg(target_arch = "wasm32")]
#[allow(non_camel_case_types)]
pub type wchar_t = u32;
pub type wchar_t = cfg_select! {
target_arch = "wasm32" => u32,
_ => libc::wchar_t,
};
/// Utf8 + state.ascii (+ PyUnicode_Kind in future)
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]

View File

@@ -26,15 +26,15 @@ mod c {
// this is basically what CPython has for Py_off_t; windows uses long long
// for offsets, other platforms just use off_t
#[cfg(not(windows))]
pub type Offset = c::off_t;
#[cfg(windows)]
pub type Offset = c::c_longlong;
pub type Offset = cfg_select! {
windows => c::c_longlong,
_ => c::off_t,
};
#[cfg(not(windows))]
pub type Raw = RawFd;
#[cfg(windows)]
pub type Raw = i32;
pub type Raw = cfg_select! {
windows => i32,
_ => RawFd,
};
#[inline]
fn cvt<I: num_traits::PrimInt>(ret: I) -> io::Result<I> {
@@ -351,18 +351,16 @@ pub fn ftruncate(fd: Borrowed<'_>, len: Offset) -> io::Result<()> {
let ret = unsafe { suppress_iph!(c::ftruncate(fd.as_raw(), len)) };
// On Windows, _chsize_s returns 0 on success, or a positive error code (errno value) on failure.
// On other platforms, ftruncate returns 0 on success, or -1 on failure with errno set.
#[cfg(windows)]
{
if ret != 0 {
// _chsize_s returns errno directly, convert to Windows error code
let winerror = crate::os::errno_to_winerror(ret);
return Err(io::Error::from_raw_os_error(winerror));
cfg_select! {
windows => {
if ret != 0 {
// _chsize_s returns errno directly, convert to Windows error code
let winerror = crate::os::errno_to_winerror(ret);
return Err(io::Error::from_raw_os_error(winerror));
}
}
}
#[cfg(not(windows))]
{
cvt(ret)?;
}
_ => cvt(ret)?,
};
Ok(())
}

View File

@@ -119,30 +119,12 @@ mod decl {
// PUTS macro
#[cfg(any(unix, windows))]
fn puts(fd: i32, s: &str) {
let _ = unsafe {
#[cfg(windows)]
{
libc::write(fd, s.as_ptr() as *const libc::c_void, s.len() as u32)
}
#[cfg(not(windows))]
{
libc::write(fd, s.as_ptr() as *const libc::c_void, s.len())
}
};
puts_bytes(fd, s.as_bytes())
}
#[cfg(any(unix, windows))]
fn puts_bytes(fd: i32, s: &[u8]) {
let _ = unsafe {
#[cfg(windows)]
{
libc::write(fd, s.as_ptr() as *const libc::c_void, s.len() as u32)
}
#[cfg(not(windows))]
{
libc::write(fd, s.as_ptr() as *const libc::c_void, s.len())
}
};
let _ = unsafe { libc::write(fd, s.as_ptr().cast::<libc::c_void>(), s.len() as _) };
}
// _Py_DumpHexadecimal (traceback.c)
@@ -158,16 +140,7 @@ mod decl {
buf[2 + i] = HEX_CHARS[digit];
}
let _ = unsafe {
#[cfg(windows)]
{
libc::write(fd, buf.as_ptr() as *const libc::c_void, (2 + width) as u32)
}
#[cfg(not(windows))]
{
libc::write(fd, buf.as_ptr() as *const libc::c_void, 2 + width)
}
};
puts_bytes(fd, &buf[..2 + width]);
}
// _Py_DumpDecimal (traceback.c)
@@ -188,17 +161,7 @@ mod decl {
v /= 10;
}
let len = buf.len() - i;
let _ = unsafe {
#[cfg(windows)]
{
libc::write(fd, buf[i..].as_ptr() as *const libc::c_void, len as u32)
}
#[cfg(not(windows))]
{
libc::write(fd, buf[i..].as_ptr() as *const libc::c_void, len)
}
};
puts_bytes(fd, &buf[i..]);
}
/// Get current thread ID
@@ -857,30 +820,31 @@ mod decl {
drop(guard); // Release lock before I/O
// Timeout occurred, dump traceback
#[cfg(target_arch = "wasm32")]
let _ = (exit, fd, &header);
cfg_select! {
target_arch = "wasm32" => {
let _ = (exit, fd, &header);
}
_ => {
puts_bytes(fd, header.as_bytes());
#[cfg(not(target_arch = "wasm32"))]
{
puts_bytes(fd, header.as_bytes());
// Use thread frame slots when threading is enabled (includes all threads).
// Fall back to live frame walking for non-threaded builds.
#[cfg(feature = "threading")]
{
for (tid, slot) in &thread_frame_slots {
let frames = slot.frames.lock();
dump_traceback_thread_frames(fd, *tid, false, &frames);
// Use thread frame slots when threading is enabled (includes all threads).
// Fall back to live frame walking for non-threaded builds.
cfg_select! {
feature = "threading" => {
for (tid, slot) in &thread_frame_slots {
let frames = slot.frames.lock();
dump_traceback_thread_frames(fd, *tid, false, &frames);
}
}
_ => {
write_thread_id(fd, current_thread_id(), false);
dump_live_frames(fd);
}
}
}
#[cfg(not(feature = "threading"))]
{
write_thread_id(fd, current_thread_id(), false);
dump_live_frames(fd);
}
if exit {
rustpython_host_env::os::exit(1);
if exit {
rustpython_host_env::os::exit(1);
}
}
}

View File

@@ -1307,15 +1307,13 @@ mod _ssl {
#[pygetset]
fn num_tickets(&self, _vm: &VirtualMachine) -> PyResult<usize> {
// Only supported for TLS 1.3
#[cfg(ossl110)]
{
let ctx = self.ctx();
let num = unsafe { sys::SSL_CTX_get_num_tickets(ctx.as_ptr()) };
Ok(num)
}
#[cfg(not(ossl110))]
{
Ok(0)
cfg_select! {
ossl111 => {
let ctx = self.ctx();
let num = unsafe { sys::SSL_CTX_get_num_tickets(ctx.as_ptr()) };
Ok(num)
}
_ => Ok(0),
}
}
#[pygetset(setter)]
@@ -1330,19 +1328,19 @@ mod _ssl {
return Err(vm.new_value_error("SSLContext is not a server context."));
}
#[cfg(ossl110)]
{
let ctx = self.builder();
let result = unsafe { sys::SSL_CTX_set_num_tickets(ctx.as_ptr(), value as usize) };
if result != 1 {
return Err(vm.new_value_error("failed to set num tickets."));
cfg_select! {
ossl110 => {
let ctx = self.builder();
let result = unsafe { sys::SSL_CTX_set_num_tickets(ctx.as_ptr(), value as usize) };
if result != 1 {
return Err(vm.new_value_error("failed to set num tickets."));
}
Ok(())
}
_ => {
let _ = (value, vm);
Ok(())
}
Ok(())
}
#[cfg(not(ossl110))]
{
let _ = (value, vm);
Ok(())
}
}
@@ -1564,10 +1562,10 @@ mod _ssl {
) -> PyResult<Vec<PyObjectRef>> {
let binary_form = args.binary_form.unwrap_or(false);
let ctx = self.ctx();
#[cfg(ossl300)]
let certs = ctx.cert_store().all_certificates();
#[cfg(not(ossl300))]
let certs = ctx.cert_store().objects().iter().filter_map(|x| x.x509());
let certs = cfg_select! {
ossl300 => ctx.cert_store().all_certificates(),
_ => ctx.cert_store().objects().iter().filter_map(|x| x.x509()),
};
// Filter to only include CA certificates (Basic Constraints: CA=TRUE)
let certs = certs
@@ -2792,21 +2790,21 @@ mod _ssl {
#[pymethod]
fn verify_client_post_handshake(&self, vm: &VirtualMachine) -> PyResult<()> {
#[cfg(ossl111)]
{
let stream = self.connection.read();
let result = unsafe { SSL_verify_client_post_handshake(stream.ssl().as_ptr()) };
if result == 0 {
Err(convert_openssl_error(vm, openssl::error::ErrorStack::get()))
} else {
Ok(())
cfg_select! {
ossl111 => {
let stream = self.connection.read();
let result = unsafe { SSL_verify_client_post_handshake(stream.ssl().as_ptr()) };
if result == 0 {
Err(convert_openssl_error(vm, openssl::error::ErrorStack::get()))
} else {
Ok(())
}
}
_ => {
Err(vm.new_not_implemented_error(
"Post-handshake auth is not supported by your OpenSSL version.",
))
}
}
#[cfg(not(ossl111))]
{
Err(vm.new_not_implemented_error(
"Post-handshake auth is not supported by your OpenSSL version.",
))
}
}
@@ -3681,15 +3679,9 @@ mod _ssl {
impl PySslSession {
#[pygetset]
fn time(&self) -> i64 {
unsafe {
#[cfg(ossl330)]
{
sys::SSL_SESSION_get_time(self.session) as i64
}
#[cfg(not(ossl330))]
{
sys::SSL_SESSION_get_time(self.session) as i64
}
cfg_select! {
ossl330 => unsafe { sys::SSL_SESSION_get_time(self.session) as i64 },
_ => unsafe { sys::SSL_SESSION_get_time(self.session) as i64 },
}
}
@@ -3701,14 +3693,10 @@ mod _ssl {
#[pygetset]
fn ticket_lifetime_hint(&self) -> u64 {
// SSL_SESSION_get_ticket_lifetime_hint available in OpenSSL 1.1.0+
#[cfg(ossl110)]
{
unsafe { SSL_SESSION_get_ticket_lifetime_hint(self.session) as u64 }
}
#[cfg(not(ossl110))]
{
cfg_select! {
ossl110 => unsafe { SSL_SESSION_get_ticket_lifetime_hint(self.session) as u64 },
// Not available in older OpenSSL versions
0
_ => 0,
}
}
@@ -3725,14 +3713,10 @@ mod _ssl {
#[pygetset]
fn has_ticket(&self) -> bool {
// SSL_SESSION_has_ticket available in OpenSSL 1.1.0+
#[cfg(ossl110)]
{
unsafe { SSL_SESSION_has_ticket(self.session) != 0 }
}
#[cfg(not(ossl110))]
{
cfg_select! {
ossl110 => unsafe { SSL_SESSION_has_ticket(self.session) != 0 },
// Not available in older OpenSSL versions
false
_ => false,
}
}
}

View File

@@ -3273,7 +3273,7 @@ mod _socket {
fn sock_from_raw(fileno: RawSocket, vm: &VirtualMachine) -> PyResult<Socket> {
let invalid = cfg_select! {
windows => fileno == INVALID_SOCKET,
_ => fileno < 0
_ => fileno < 0,
};
if invalid {
return Err(vm.new_value_error("negative file descriptor"));

View File

@@ -4832,31 +4832,20 @@ mod _ssl {
// Common default paths for different platforms
// These match the first candidates that rustls-native-certs/openssl-probe checks
#[cfg(target_os = "macos")]
let (default_cafile, default_capath) = {
let (default_cafile, default_capath): (Option<&str>, Option<&str>) = cfg_select! {
// macOS primarily uses Keychain API, but provides fallback paths
// for compatibility and when Keychain access fails
(Some("/etc/ssl/cert.pem"), Some("/etc/ssl/certs"))
};
#[cfg(target_os = "linux")]
let (default_cafile, default_capath) = {
target_os = "macos" => (Some("/etc/ssl/cert.pem"), Some("/etc/ssl/certs")),
// Linux: matches openssl-probe's first candidate (/etc/ssl/cert.pem)
// openssl-probe checks multiple locations at runtime, but we return
// OpenSSL's compile-time default
(Some("/etc/ssl/cert.pem"), Some("/etc/ssl/certs"))
};
#[cfg(windows)]
let (default_cafile, default_capath) = {
target_os = "linux" => (Some("/etc/ssl/cert.pem"), Some("/etc/ssl/certs")),
// Windows uses certificate store, not file paths
// Return empty strings to avoid None being passed to os.path.isfile()
(Some(""), Some(""))
windows => (Some(""), Some("")),
_ => (None, None),
};
#[cfg(not(any(target_os = "macos", target_os = "linux", windows)))]
let (default_cafile, default_capath): (Option<&str>, Option<&str>) = (None, None);
let tuple = vm.ctx.new_tuple(vec![
vm.ctx.new_str("SSL_CERT_FILE").into(), // openssl_cafile_env
default_cafile

View File

@@ -61,10 +61,10 @@ impl ByteOrder for LittleEndian {
}
}
#[cfg(target_endian = "big")]
type NativeEndian = BigEndian;
#[cfg(target_endian = "little")]
type NativeEndian = LittleEndian;
type NativeEndian = cfg_select! {
target_endian = "big" => BigEndian,
target_endian = "little" => LittleEndian,
};
#[derive(Copy, Clone, num_enum::TryFromPrimitive)]
#[repr(u8)]

View File

@@ -441,15 +441,15 @@ enum StandardEncoding {
}
impl StandardEncoding {
#[cfg(target_endian = "little")]
const UTF_16_NE: Self = Self::Utf16Le;
#[cfg(target_endian = "big")]
const UTF_16_NE: Self = Self::Utf16Be;
const UTF_16_NE: Self = cfg_select! {
target_endian = "little" => Self::Utf16Le,
target_endian = "big" => Self::Utf16Be,
};
#[cfg(target_endian = "little")]
const UTF_32_NE: Self = Self::Utf32Le;
#[cfg(target_endian = "big")]
const UTF_32_NE: Self = Self::Utf32Be;
const UTF_32_NE: Self = cfg_select! {
target_endian = "little" => Self::Utf32Le,
target_endian = "big" => Self::Utf32Be,
};
fn parse(encoding: &str) -> Option<Self> {
if let Some(encoding) = encoding.to_lowercase().strip_prefix("utf") {

View File

@@ -1354,10 +1354,10 @@ impl OSErrorBuilder {
} = self;
let args = if let Some(errno) = errno {
#[cfg(windows)]
let winerror = winerror.to_pyobject(vm);
#[cfg(not(windows))]
let winerror = vm.ctx.none();
let winerror = cfg_select! {
windows => winerror.to_pyobject(vm),
_ => vm.ctx.none(),
};
vec![
errno.to_pyobject(vm),
@@ -2089,21 +2089,19 @@ pub(super) mod types {
.get_attr("filename2", vm)
.ok()
.filter(|f| !vm.is_none(f));
#[cfg(windows)]
let winerror = obj.get_attr("winerror", vm).ok().filter(|w| !vm.is_none(w));
let winerror: Option<PyObjectRef> = cfg_select! {
windows => obj.get_attr("winerror", vm).ok().filter(|w| !vm.is_none(w)),
_ => None,
};
if let Some(filename2) = filename2 {
#[cfg(windows)]
{
args_reduced.push(winerror.unwrap_or_else(|| vm.ctx.none()));
}
#[cfg(not(windows))]
args_reduced.push(vm.ctx.none());
args_reduced.push(filename2);
#[allow(clippy::unnecessary_literal_unwrap)]
let winerror = winerror.unwrap_or_else(|| vm.ctx.none());
args_reduced.extend([winerror, filename2]);
} else {
// Diverges from CPython: include winerror even without
// filename2 so it survives pickle round-trips.
#[cfg(windows)]
if let Some(winerror) = winerror {
args_reduced.push(winerror);
}

View File

@@ -307,11 +307,10 @@ fn calculate_base_executable(executable: Option<&PathBuf>, home_dir: &Option<Pat
/// Calculate stdlib_dir (sys._stdlib_dir)
/// Returns None if the stdlib directory doesn't exist
fn calculate_stdlib_dir(prefix: &str) -> Option<String> {
#[cfg(not(windows))]
let stdlib_dir = PathBuf::from(prefix).join(platform::stdlib_subdir());
#[cfg(windows)]
let stdlib_dir = PathBuf::from(prefix).join(platform::STDLIB_SUBDIR);
let stdlib_dir = Path::new(prefix).join(cfg_select! {
windows => platform::STDLIB_SUBDIR,
_ => platform::stdlib_subdir(),
});
if stdlib_dir.is_dir() {
Some(stdlib_dir.to_string_lossy().into_owned())

View File

@@ -655,24 +655,24 @@ fn wstring_at_impl(ptr: usize, size: isize, vm: &VirtualMachine) -> PyResult {
// Windows: wchar_t = u16 (UTF-16) -> use Wtf8Buf::from_wide
// macOS/Linux: wchar_t = i32 (UTF-32) -> convert via char::from_u32
#[cfg(windows)]
{
use rustpython_common::wtf8::Wtf8Buf;
let wide: Vec<u16> = wchars.to_vec();
let wtf8 = Wtf8Buf::from_wide(&wide);
Ok(vm.ctx.new_str(wtf8).into())
}
#[cfg(not(windows))]
{
#[allow(
clippy::useless_conversion,
reason = "wchar_t is i32 on some platforms and u32 on others"
)]
let s: String = wchars
.iter()
.filter_map(|&c| u32::try_from(c).ok().and_then(char::from_u32))
.collect();
Ok(vm.ctx.new_str(s).into())
cfg_select! {
windows => {
use rustpython_common::wtf8::Wtf8Buf;
let wide: Vec<u16> = wchars.to_vec();
let wtf8 = Wtf8Buf::from_wide(&wide);
Ok(vm.ctx.new_str(wtf8).into())
}
_ => {
#[allow(
clippy::useless_conversion,
reason = "wchar_t is i32 on some platforms and u32 on others"
)]
let s: String = wchars
.iter()
.filter_map(|&c| u32::try_from(c).ok().and_then(char::from_u32))
.collect();
Ok(vm.ctx.new_str(s).into())
}
}
}
@@ -2027,24 +2027,24 @@ fn ffi_to_python(ty: &Py<PyType>, ptr: *const c_void, vm: &VirtualMachine) -> Py
let slice = core::slice::from_raw_parts(wstr_ptr, len);
// Windows: wchar_t = u16 (UTF-16) -> use Wtf8Buf::from_wide
// Unix: wchar_t = i32 (UTF-32) -> convert via char::from_u32
#[cfg(windows)]
{
use rustpython_common::wtf8::Wtf8Buf;
let wide: Vec<u16> = slice.to_vec();
let wtf8 = Wtf8Buf::from_wide(&wide);
vm.ctx.new_str(wtf8).into()
}
#[cfg(not(windows))]
{
#[allow(
clippy::useless_conversion,
reason = "wchar_t is i32 on some platforms and u32 on others"
)]
let s: String = slice
.iter()
.filter_map(|&c| u32::try_from(c).ok().and_then(char::from_u32))
.collect();
vm.ctx.new_str(s).into()
cfg_select! {
windows => {
use rustpython_common::wtf8::Wtf8Buf;
let wide: Vec<u16> = slice.to_vec();
let wtf8 = Wtf8Buf::from_wide(&wide);
vm.ctx.new_str(wtf8).into()
}
_ => {
#[allow(
clippy::useless_conversion,
reason = "wchar_t is i32 on some platforms and u32 on others"
)]
let s: String = slice
.iter()
.filter_map(|&c| u32::try_from(c).ok().and_then(char::from_u32))
.collect();
vm.ctx.new_str(s).into()
}
}
}
}

View File

@@ -18,12 +18,12 @@ use core::fmt::Debug;
use num_traits::ToPrimitive;
/// Valid type codes for ctypes simple types
#[cfg(windows)]
// spell-checker: disable-next-line
pub(super) const SIMPLE_TYPE_CHARS: &str = "cbBhHiIlLdfuzZqQPXOv?g";
#[cfg(not(windows))]
// spell-checker: disable-next-line
pub(super) const SIMPLE_TYPE_CHARS: &str = "cbBhHiIlLdfuzZqQPOv?g";
pub(super) const SIMPLE_TYPE_CHARS: &str = cfg_select! {
// spell-checker: disable-next-line
windows => "cbBhHiIlLdfuzZqQPXOv?g",
// spell-checker: disable-next-line
_ => "cbBhHiIlLdfuzZqQPOv?g",
};
/// Convert ctypes type code to PEP 3118 format code.
/// Some ctypes codes need to be mapped to standard-size codes based on platform.

View File

@@ -152,7 +152,7 @@ mod _io {
any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux") => {
x || matches!(whence, libc::SEEK_DATA | libc::SEEK_HOLE)
}
_ => x
_ => x,
}
}
@@ -5096,23 +5096,23 @@ mod _io {
// Construct a RawIO (subclass of RawIOBase)
// On Windows, use _WindowsConsoleIO for console handles.
// This is subsequently consumed by a Buffered Class.
#[cfg(all(feature = "host_env", windows))]
let is_console = super::winconsoleio::pyio_get_console_type(&file, vm) != '\0';
#[cfg(not(all(feature = "host_env", windows)))]
let is_console = false;
let file_io_class: &Py<PyType> = {
cfg_select! {
all(feature = "host_env", windows) => {
if is_console {
Some(super::winconsoleio::WindowsConsoleIO::static_type())
} else {
Some(super::fileio::FileIO::static_type())
}
}
feature = "host_env" => Some(super::fileio::FileIO::static_type()),
_ => None,
let is_console = cfg_select! {
all(feature = "host_env", windows) => {
super::winconsoleio::pyio_get_console_type(&file, vm) != '\0'
}
_ => false,
};
let file_io_class: &Py<PyType> = cfg_select! {
all(feature = "host_env", windows) => {
if is_console {
Some(super::winconsoleio::WindowsConsoleIO::static_type())
} else {
Some(super::fileio::FileIO::static_type())
}
}
feature = "host_env" => Some(super::fileio::FileIO::static_type()),
_ => None,
}
.ok_or_else(|| {
new_unsupported_operation(

View File

@@ -16,11 +16,11 @@ pub(crate) mod _signal {
#[cfg(unix)]
use rustpython_host_env::signal::{double_to_timeval, itimerval_to_tuple};
#[cfg(any(unix, windows))]
use libc::sighandler_t;
#[allow(non_camel_case_types)]
#[cfg(not(any(unix, windows)))]
type sighandler_t = usize;
type sighandler_t = cfg_select! {
any(unix, windows) => libc::sighandler_t,
_ => usize,
};
cfg_select! {
windows => {
@@ -558,40 +558,39 @@ pub(crate) mod _signal {
use crate::PyPayload;
use crate::builtins::PySet;
let set = PySet::default().into_ref(&vm.ctx);
#[cfg(unix)]
{
// Use sigfillset to get all valid signals
let mut mask: libc::sigset_t = unsafe { core::mem::zeroed() };
// SAFETY: mask is a valid pointer
if unsafe { libc::sigfillset(&mut mask) } != 0 {
return Err(vm.new_os_error("sigfillset failed".to_owned()));
}
// Convert the filled mask to a Python set
for signum in 1..signal::NSIG {
if unsafe { libc::sigismember(&mask, signum as i32) } == 1 {
set.add(vm.ctx.new_int(signum as i32).into(), vm)?;
cfg_select! {
unix => {
// Use sigfillset to get all valid signals
let mut mask: libc::sigset_t = unsafe { core::mem::zeroed() };
// SAFETY: mask is a valid pointer
if unsafe { libc::sigfillset(&mut mask) } != 0 {
return Err(vm.new_os_error("sigfillset failed".to_owned()));
}
// Convert the filled mask to a Python set
for signum in 1..signal::NSIG {
if unsafe { libc::sigismember(&mask, signum as i32) } == 1 {
set.add(vm.ctx.new_int(signum as i32).into(), vm)?;
}
}
}
}
#[cfg(windows)]
{
// Windows only supports a limited set of signals
for &signum in &[
libc::SIGINT,
libc::SIGILL,
libc::SIGFPE,
libc::SIGSEGV,
libc::SIGTERM,
SIGBREAK,
libc::SIGABRT,
] {
set.add(vm.ctx.new_int(signum).into(), vm)?;
windows => {
// Windows only supports a limited set of signals
for &signum in &[
libc::SIGINT,
libc::SIGILL,
libc::SIGFPE,
libc::SIGSEGV,
libc::SIGTERM,
SIGBREAK,
libc::SIGABRT,
] {
set.add(vm.ctx.new_int(signum).into(), vm)?;
}
}
_ => {
// Empty set for platforms without signal support (e.g., WASM)
let _ = &set;
}
}
#[cfg(not(any(unix, windows)))]
{
// Empty set for platforms without signal support (e.g., WASM)
let _ = &set;
}
Ok(set.into())
}

View File

@@ -824,10 +824,10 @@ pub(super) mod _os {
.map_err(|e| e.into_pyexception(vm))?
.ok_or_else(|| crate::exceptions::cstring_error(vm))?;
// On Windows, combine st_ino and st_ino_high into 128-bit value
#[cfg(windows)]
let ino: u128 = stat.st_ino as u128 | ((stat.st_ino_high as u128) << 64);
#[cfg(not(windows))]
let ino: u128 = stat.st_ino as u128;
let ino: u128 = cfg_select! {
windows => stat.st_ino as u128 | ((stat.st_ino_high as u128) << 64),
_ => stat.st_ino as u128,
};
// Err(T) means other thread set `ino` at the mean time which is safe to ignore
let _ = self.ino.compare_exchange(None, Some(ino));
Ok(ino)

View File

@@ -491,24 +491,23 @@ pub mod decl {
secs: OptionalArg<Option<Either<f64, i64>>>,
vm: &VirtualMachine,
) -> PyResult<StructTimeData> {
#[cfg(any(unix, windows))]
{
let ts = match secs {
OptionalArg::Present(Some(value)) => pyobj_to_time_t(value, vm)?,
OptionalArg::Present(None) | OptionalArg::Missing => current_time_t(),
};
gmtime_from_timestamp(ts, vm)
}
#[cfg(not(any(unix, windows)))]
{
let instant = match secs {
OptionalArg::Present(Some(secs)) => pyobj_to_date_time(secs, vm)?.naive_utc(),
OptionalArg::Present(None) | OptionalArg::Missing => {
chrono::offset::Utc::now().naive_utc()
}
};
Ok(StructTimeData::new_utc(vm, instant))
cfg_select! {
any(unix, windows) => {
let ts = match secs {
OptionalArg::Present(Some(value)) => pyobj_to_time_t(value, vm)?,
OptionalArg::Present(None) | OptionalArg::Missing => current_time_t(),
};
gmtime_from_timestamp(ts, vm)
}
_ => {
let instant = match secs {
OptionalArg::Present(Some(secs)) => pyobj_to_date_time(secs, vm)?.naive_utc(),
OptionalArg::Present(None) | OptionalArg::Missing => {
chrono::offset::Utc::now().naive_utc()
}
};
Ok(StructTimeData::new_utc(vm, instant))
}
}
}
@@ -517,20 +516,18 @@ pub mod decl {
secs: OptionalArg<Option<Either<f64, i64>>>,
vm: &VirtualMachine,
) -> PyResult<StructTimeData> {
#[cfg(any(unix, windows))]
{
let ts = match secs {
OptionalArg::Present(Some(value)) => pyobj_to_time_t(value, vm)?,
OptionalArg::Present(None) | OptionalArg::Missing => current_time_t(),
};
localtime_from_timestamp(ts, vm)
}
#[cfg(not(any(unix, windows)))]
let instant = secs.naive_or_local(vm)?;
#[cfg(not(any(unix, windows)))]
{
Ok(StructTimeData::new_local(vm, instant, 0))
cfg_select! {
any(unix, windows) => {
let ts = match secs {
OptionalArg::Present(Some(value)) => pyobj_to_time_t(value, vm)?,
OptionalArg::Present(None) | OptionalArg::Missing => current_time_t(),
};
localtime_from_timestamp(ts, vm)
}
_ => {
let instant = secs.naive_or_local(vm)?;
Ok(StructTimeData::new_local(vm, instant, 0))
}
}
}

View File

@@ -19,20 +19,19 @@ pub const VERSION_HEX: usize =
pub fn get_version() -> String {
// Windows: include MSC v. for compatibility with ctypes.util.find_library
// MSC v.1929 = VS 2019, version 14+ makes find_msvcrt() return None
#[cfg(windows)]
let msc_info = {
let arch = if cfg!(target_pointer_width = "64") {
"64 bit (AMD64)"
} else {
"32 bit (Intel)"
};
// Include both RustPython identifier and MSC v. for compatibility
format!(" MSC v.1929 {arch}",)
let msc_info = cfg_select! {
windows => {{
let arch = if cfg!(target_pointer_width = "64") {
"64 bit (AMD64)"
} else {
"32 bit (Intel)"
};
// Include both RustPython identifier and MSC v. for compatibility
format!(" MSC v.1929 {arch}",)
}},
_ => String::new(),
};
#[cfg(not(windows))]
let msc_info = String::new();
format!(
"{:.80} ({:.80}) \n[RustPython {} with {:.80}{}]", // \n is PyPy convention
get_version_number(),

View File

@@ -699,13 +699,11 @@ impl VirtualMachine {
/// Mirrors `_Py_ThreadCanHandleSignals`.
#[allow(dead_code)]
pub(crate) fn is_main_thread(&self) -> bool {
#[cfg(feature = "threading")]
{
crate::stdlib::_thread::get_ident() == self.state.main_thread_ident.load()
}
#[cfg(not(feature = "threading"))]
{
true
cfg_select! {
feature = "threading" => {
crate::stdlib::_thread::get_ident() == self.state.main_thread_ident.load()
}
_ => true,
}
}
@@ -2037,13 +2035,9 @@ impl VirtualMachine {
thread::suspend_if_needed(&self.state.stop_the_world);
#[cfg(not(target_arch = "wasm32"))]
{
crate::signal::check_signals(self)
}
#[cfg(target_arch = "wasm32")]
{
Ok(())
}
crate::signal::check_signals(self)?;
Ok(())
}
/// Push a new exc_info slot (for generator/coroutine resume).
@@ -2158,11 +2152,9 @@ impl VirtualMachine {
}
1
} else if exc.fast_isinstance(self.ctx.exceptions.keyboard_interrupt) {
#[allow(clippy::if_same_then_else)]
{
self.print_exception(exc);
#[cfg(unix)]
{
self.print_exception(exc);
cfg_select! {
unix => {
let action = SigAction::new(
nix::sys::signal::SigHandler::SigDfl,
SaFlags::SA_ONSTACK,
@@ -2176,15 +2168,9 @@ impl VirtualMachine {
(libc::SIGINT as u32) + 128
}
#[cfg(windows)]
{
// STATUS_CONTROL_C_EXIT - same as CPython
0xC000013A
}
#[cfg(not(any(unix, windows)))]
{
1
}
// STATUS_CONTROL_C_EXIT - same as CPython
windows => 0xC000013A,
_ => 1,
}
} else {
self.print_exception(exc);

View File

@@ -12,43 +12,35 @@ impl VirtualMachine {
#[track_caller]
#[cold]
fn _py_panic_failed(&self, exc: PyBaseExceptionRef, msg: &str) -> ! {
#[cfg(not(all(
target_arch = "wasm32",
not(any(target_os = "emscripten", target_os = "wasi")),
)))]
{
self.print_exception(exc);
self.flush_std();
panic!("{msg}")
}
#[cfg(all(
target_arch = "wasm32",
feature = "wasmbind",
not(any(target_os = "emscripten", target_os = "wasi")),
))]
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind"))]
{
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn error(s: &str);
cfg_select! {
all(
target_arch = "wasm32",
not(any(target_os = "emscripten", target_os = "wasi"))
) => cfg_select! {
feature = "wasmbind" => {
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn error(s: &str);
}
let mut s = String::new();
self.write_exception(&mut s, &exc).unwrap();
error(&s);
panic!("{msg}; exception backtrace above")
}
_ => {
use crate::convert::ToPyObject;
let err_string: String = exc.to_pyobject(self).repr(self).unwrap().to_string();
eprintln!("{err_string}");
panic!("{msg}; python exception not available")
}
},
_ => {
self.print_exception(exc);
self.flush_std();
panic!("{msg}")
}
let mut s = String::new();
self.write_exception(&mut s, &exc).unwrap();
error(&s);
panic!("{msg}; exception backtrace above")
}
#[cfg(all(
target_arch = "wasm32",
not(feature = "wasmbind"),
not(any(target_os = "emscripten", target_os = "wasi")),
))]
{
use crate::convert::ToPyObject;
let err_string: String = exc.to_pyobject(self).repr(self).unwrap().to_string();
eprintln!("{err_string}");
panic!("{msg}; python exception not available")
}
}

View File

@@ -15,15 +15,14 @@ impl InterpreterBuilderExt for InterpreterBuilder {
let defs = rustpython_stdlib::stdlib_module_defs(&self.ctx);
let builder = self.add_native_modules(&defs);
#[cfg(feature = "freeze-stdlib")]
let builder = builder
.add_frozen_modules(rustpython_pylib::FROZEN_STDLIB)
.init_hook(set_frozen_stdlib_dir);
#[cfg(not(feature = "freeze-stdlib"))]
let builder = builder.init_hook(setup_dynamic_stdlib);
builder
cfg_select! {
feature = "freeze-stdlib" => {
builder
.add_frozen_modules(rustpython_pylib::FROZEN_STDLIB)
.init_hook(set_frozen_stdlib_dir)
}
_ => builder.init_hook(setup_dynamic_stdlib),
}
}
}
@@ -64,13 +63,9 @@ fn collect_stdlib_paths() -> Vec<String> {
.map(|path| path.into_os_string().into_string().unwrap())
.collect()
} else {
#[cfg(feature = "rustpython-pylib")]
{
vec![rustpython_pylib::LIB_PATH.to_owned()]
}
#[cfg(not(feature = "rustpython-pylib"))]
{
vec![]
}
vec![
#[cfg(feature = "rustpython-pylib")]
rustpython_pylib::LIB_PATH.to_owned(),
]
}
}

View File

@@ -176,18 +176,16 @@ fn run_file(vm: &VirtualMachine, scope: Scope, path: &str) -> PyResult<()> {
vm.insert_sys_path(vm.new_pyobj(dir))?;
}
#[cfg(feature = "host_env")]
{
vm.run_any_file(scope, path)
}
#[cfg(not(feature = "host_env"))]
{
// In sandbox mode, the binary reads the file and feeds source to the VM.
// The VM itself has no filesystem access.
let path = if path.is_empty() { "???" } else { path };
match std::fs::read_to_string(path) {
Ok(source) => vm.run_string(scope, &source, path.to_owned()).map(drop),
Err(err) => Err(vm.new_os_error(err.to_string())),
cfg_select! {
feature = "host_env" => vm.run_any_file(scope, path),
_ => {
// In sandbox mode, the binary reads the file and feeds source to the VM.
// The VM itself has no filesystem access.
let path = if path.is_empty() { "???" } else { path };
match std::fs::read_to_string(path) {
Ok(source) => vm.run_string(scope, &source, path.to_owned()).map(drop),
Err(err) => Err(vm.new_os_error(err.to_string())),
}
}
}
}