From 54aa3cdd0b285f84df5b3d8f79c44a4319a91d24 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 13 Apr 2026 15:58:37 -0700 Subject: [PATCH 01/13] std: add platform support for hexagon-unknown-qurt Remove unix family from hexagon-unknown-qurt target spec and instead explicitly opt into unix implementations where applicable, following the pattern used by similar unix-adjacent targets. The target uses the unix PAL and explicitly selects unix implementations for the supported features. Modules that remain unsupported for qurt: process spawning, networking and pipes. --- .../src/spec/targets/hexagon_unknown_qurt.rs | 2 +- library/core/src/io/io_slice.rs | 2 +- library/std/src/os/fd/mod.rs | 4 +- library/std/src/os/fd/owned.rs | 30 ++-- library/std/src/os/fd/raw.rs | 10 +- library/std/src/os/mod.rs | 3 + library/std/src/os/qurt/ffi.rs | 65 +++++++++ library/std/src/os/qurt/fs.rs | 137 ++++++++++++++++++ library/std/src/os/qurt/io.rs | 8 + library/std/src/os/qurt/mod.rs | 21 +++ library/std/src/os/qurt/raw.rs | 50 +++++++ library/std/src/os/unix/fs.rs | 1 + library/std/src/os/unix/io/mod.rs | 2 +- library/std/src/process.rs | 1 + library/std/src/sys/alloc/mod.rs | 1 + library/std/src/sys/args/unsupported.rs | 4 + library/std/src/sys/backtrace.rs | 7 +- library/std/src/sys/env/mod.rs | 3 +- library/std/src/sys/env/unix.rs | 3 + library/std/src/sys/exit.rs | 1 + library/std/src/sys/fd/mod.rs | 2 +- library/std/src/sys/fd/unix.rs | 41 +++++- library/std/src/sys/fs/mod.rs | 16 +- library/std/src/sys/fs/unix.rs | 131 ++++++++++++++--- library/std/src/sys/io/error/mod.rs | 2 +- library/std/src/sys/io/error/unix.rs | 1 + library/std/src/sys/io/mod.rs | 3 +- .../std/src/sys/net/connection/unsupported.rs | 3 + library/std/src/sys/pal/mod.rs | 2 +- library/std/src/sys/pal/unix/mod.rs | 12 +- library/std/src/sys/paths/mod.rs | 2 +- library/std/src/sys/paths/unix.rs | 11 +- library/std/src/sys/personality/mod.rs | 2 +- library/std/src/sys/pipe/unsupported.rs | 2 +- library/std/src/sys/process/mod.rs | 4 +- library/std/src/sys/process/unix/common.rs | 1 + library/std/src/sys/process/unsupported.rs | 3 + library/std/src/sys/random/mod.rs | 2 + library/std/src/sys/stdio/mod.rs | 7 +- library/std/src/sys/stdio/unix.rs | 2 +- library/std/src/sys/sync/condvar/mod.rs | 1 + library/std/src/sys/sync/mutex/mod.rs | 1 + library/std/src/sys/sync/once/mod.rs | 1 + library/std/src/sys/sync/rwlock/mod.rs | 1 + .../std/src/sys/sync/thread_parking/mod.rs | 1 + library/std/src/sys/thread/mod.rs | 2 +- library/std/src/sys/thread/unix.rs | 7 +- library/std/src/sys/thread_local/mod.rs | 2 +- library/std/src/sys/time/mod.rs | 1 + library/sysroot/src/lib.rs | 1 + library/test/src/lib.rs | 1 + library/unwind/src/lib.rs | 1 + src/bootstrap/src/core/builder/cargo.rs | 1 + 53 files changed, 559 insertions(+), 66 deletions(-) create mode 100644 library/std/src/os/qurt/ffi.rs create mode 100644 library/std/src/os/qurt/fs.rs create mode 100644 library/std/src/os/qurt/io.rs create mode 100644 library/std/src/os/qurt/mod.rs create mode 100644 library/std/src/os/qurt/raw.rs diff --git a/compiler/rustc_target/src/spec/targets/hexagon_unknown_qurt.rs b/compiler/rustc_target/src/spec/targets/hexagon_unknown_qurt.rs index dcc92b4bdcc4a..82bf2b11073b3 100644 --- a/compiler/rustc_target/src/spec/targets/hexagon_unknown_qurt.rs +++ b/compiler/rustc_target/src/spec/targets/hexagon_unknown_qurt.rs @@ -29,7 +29,7 @@ pub(crate) fn target() -> Target { exe_suffix: ".elf".into(), dynamic_linking: true, executables: true, - families: cvs!["unix"], + families: cvs![], has_thread_local: true, has_rpath: false, crt_static_default: false, diff --git a/library/core/src/io/io_slice.rs b/library/core/src/io/io_slice.rs index 0bdd410d3e964..e4d8cbeec03f3 100644 --- a/library/core/src/io/io_slice.rs +++ b/library/core/src/io/io_slice.rs @@ -3,7 +3,7 @@ use crate::mem::take; use crate::ops::{Deref, DerefMut}; cfg_select! { - any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty", target_os = "wasi") => { + any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty", target_os = "wasi", target_os = "qurt") => { #[path = "io_slice/repr_iovec.rs"] mod repr; } diff --git a/library/std/src/os/fd/mod.rs b/library/std/src/os/fd/mod.rs index 473d7ae3e2ae6..a2dfef990cfbf 100644 --- a/library/std/src/os/fd/mod.rs +++ b/library/std/src/os/fd/mod.rs @@ -13,13 +13,13 @@ mod raw; mod owned; // Implementations for `AsRawFd` etc. for network types. -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] mod net; // Implementation of stdio file descriptor constants. mod stdio; -#[cfg(test)] +#[cfg(all(test, not(target_os = "qurt")))] mod tests; // Export the types and traits for the public API. diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index c226a0dc2403f..63a2f1aad95d8 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -341,7 +341,7 @@ impl From for fs::File { } #[stable(feature = "io_safety", since = "1.63.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl AsFd for crate::net::TcpStream { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { @@ -350,7 +350,7 @@ impl AsFd for crate::net::TcpStream { } #[stable(feature = "io_safety", since = "1.63.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl From for OwnedFd { /// Takes ownership of a [`TcpStream`](crate::net::TcpStream)'s socket file descriptor. #[inline] @@ -360,7 +360,7 @@ impl From for OwnedFd { } #[stable(feature = "io_safety", since = "1.63.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl From for crate::net::TcpStream { #[inline] fn from(owned_fd: OwnedFd) -> Self { @@ -371,7 +371,7 @@ impl From for crate::net::TcpStream { } #[stable(feature = "io_safety", since = "1.63.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl AsFd for crate::net::TcpListener { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { @@ -380,7 +380,7 @@ impl AsFd for crate::net::TcpListener { } #[stable(feature = "io_safety", since = "1.63.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl From for OwnedFd { /// Takes ownership of a [`TcpListener`](crate::net::TcpListener)'s socket file descriptor. #[inline] @@ -390,7 +390,7 @@ impl From for OwnedFd { } #[stable(feature = "io_safety", since = "1.63.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl From for crate::net::TcpListener { #[inline] fn from(owned_fd: OwnedFd) -> Self { @@ -401,7 +401,7 @@ impl From for crate::net::TcpListener { } #[stable(feature = "io_safety", since = "1.63.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl AsFd for crate::net::UdpSocket { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { @@ -410,7 +410,7 @@ impl AsFd for crate::net::UdpSocket { } #[stable(feature = "io_safety", since = "1.63.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl From for OwnedFd { /// Takes ownership of a [`UdpSocket`](crate::net::UdpSocket)'s file descriptor. #[inline] @@ -420,7 +420,7 @@ impl From for OwnedFd { } #[stable(feature = "io_safety", since = "1.63.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl From for crate::net::UdpSocket { #[inline] fn from(owned_fd: OwnedFd) -> Self { @@ -529,7 +529,7 @@ impl<'a> AsFd for io::StderrLock<'a> { } #[stable(feature = "anonymous_pipe", since = "1.87.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl AsFd for io::PipeReader { fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_fd() @@ -537,7 +537,7 @@ impl AsFd for io::PipeReader { } #[stable(feature = "anonymous_pipe", since = "1.87.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl From for OwnedFd { fn from(pipe: io::PipeReader) -> Self { pipe.0.into_inner() @@ -545,7 +545,7 @@ impl From for OwnedFd { } #[stable(feature = "anonymous_pipe", since = "1.87.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl AsFd for io::PipeWriter { fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_fd() @@ -553,7 +553,7 @@ impl AsFd for io::PipeWriter { } #[stable(feature = "anonymous_pipe", since = "1.87.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl From for OwnedFd { fn from(pipe: io::PipeWriter) -> Self { pipe.0.into_inner() @@ -561,7 +561,7 @@ impl From for OwnedFd { } #[stable(feature = "anonymous_pipe", since = "1.87.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl From for io::PipeReader { fn from(owned_fd: OwnedFd) -> Self { Self(FromInner::from_inner(owned_fd)) @@ -569,7 +569,7 @@ impl From for io::PipeReader { } #[stable(feature = "anonymous_pipe", since = "1.87.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl From for io::PipeWriter { fn from(owned_fd: OwnedFd) -> Self { Self(FromInner::from_inner(owned_fd)) diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 0d96958b6cca1..97ccc21ef4b55 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -14,6 +14,8 @@ use crate::fs; use crate::io; #[cfg(target_os = "hermit")] use crate::os::hermit::io::OwnedFd; +#[cfg(target_os = "qurt")] +use crate::os::qurt::io::OwnedFd; #[cfg(all(not(target_os = "hermit"), not(target_os = "motor")))] use crate::os::raw; #[cfg(all(doc, not(any(target_arch = "wasm32", target_env = "sgx"))))] @@ -193,7 +195,7 @@ impl IntoRawFd for fs::File { } #[stable(feature = "asraw_stdio", since = "1.21.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl AsRawFd for io::Stdin { #[inline] fn as_raw_fd(&self) -> RawFd { @@ -202,6 +204,7 @@ impl AsRawFd for io::Stdin { } #[stable(feature = "asraw_stdio", since = "1.21.0")] +#[cfg(not(target_os = "qurt"))] impl AsRawFd for io::Stdout { #[inline] fn as_raw_fd(&self) -> RawFd { @@ -210,6 +213,7 @@ impl AsRawFd for io::Stdout { } #[stable(feature = "asraw_stdio", since = "1.21.0")] +#[cfg(not(target_os = "qurt"))] impl AsRawFd for io::Stderr { #[inline] fn as_raw_fd(&self) -> RawFd { @@ -218,7 +222,7 @@ impl AsRawFd for io::Stderr { } #[stable(feature = "asraw_stdio_locks", since = "1.35.0")] -#[cfg(not(target_os = "trusty"))] +#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] impl<'a> AsRawFd for io::StdinLock<'a> { #[inline] fn as_raw_fd(&self) -> RawFd { @@ -227,6 +231,7 @@ impl<'a> AsRawFd for io::StdinLock<'a> { } #[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +#[cfg(not(target_os = "qurt"))] impl<'a> AsRawFd for io::StdoutLock<'a> { #[inline] fn as_raw_fd(&self) -> RawFd { @@ -235,6 +240,7 @@ impl<'a> AsRawFd for io::StdoutLock<'a> { } #[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +#[cfg(not(target_os = "qurt"))] impl<'a> AsRawFd for io::StderrLock<'a> { #[inline] fn as_raw_fd(&self) -> RawFd { diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index a7ffd87d84d93..2c47f2baeed3d 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -73,6 +73,7 @@ cfg_select! { target_os = "trusty", target_os = "wasi", target_os = "motor", + target_os = "qurt", doc ))] pub mod fd; @@ -127,6 +128,8 @@ pub mod nto; pub mod nuttx; #[cfg(target_os = "openbsd")] pub mod openbsd; +#[cfg(target_os = "qurt")] +pub mod qurt; #[cfg(target_os = "redox")] pub mod redox; #[cfg(target_os = "rtems")] diff --git a/library/std/src/os/qurt/ffi.rs b/library/std/src/os/qurt/ffi.rs new file mode 100644 index 0000000000000..9cca5f3619f3d --- /dev/null +++ b/library/std/src/os/qurt/ffi.rs @@ -0,0 +1,65 @@ +//! QuRT-specific extension to the primitives in the [`std::ffi`] module. +//! +//! [`std::ffi`]: crate::ffi + +#![stable(feature = "raw_ext", since = "1.1.0")] + +use crate::ffi::{OsStr, OsString}; +use crate::mem; +use crate::sealed::Sealed; +use crate::sys::os_str::Buf; +use crate::sys::{AsInner, FromInner, IntoInner}; + +/// QuRT-specific extensions to [`OsString`]. +/// +/// This trait is sealed: it cannot be implemented outside the standard library. +#[stable(feature = "raw_ext", since = "1.1.0")] +pub trait OsStringExt: Sealed { + /// Creates an [`OsString`] from a byte vector. + #[stable(feature = "raw_ext", since = "1.1.0")] + fn from_vec(vec: Vec) -> Self; + + /// Yields the underlying byte vector of this [`OsString`]. + #[stable(feature = "raw_ext", since = "1.1.0")] + fn into_vec(self) -> Vec; +} + +#[stable(feature = "raw_ext", since = "1.1.0")] +impl OsStringExt for OsString { + #[inline] + fn from_vec(vec: Vec) -> OsString { + FromInner::from_inner(Buf { inner: vec }) + } + + #[inline] + fn into_vec(self) -> Vec { + self.into_inner().inner + } +} + +/// QuRT-specific extensions to [`OsStr`]. +/// +/// This trait is sealed: it cannot be implemented outside the standard library. +#[stable(feature = "raw_ext", since = "1.1.0")] +pub trait OsStrExt: Sealed { + #[stable(feature = "raw_ext", since = "1.1.0")] + /// Creates an [`OsStr`] from a byte slice. + fn from_bytes(slice: &[u8]) -> &Self; + + /// Gets the underlying byte view of the [`OsStr`] slice. + #[stable(feature = "raw_ext", since = "1.1.0")] + fn as_bytes(&self) -> &[u8]; +} + +#[stable(feature = "raw_ext", since = "1.1.0")] +impl OsStrExt for OsStr { + #[inline] + fn from_bytes(slice: &[u8]) -> &OsStr { + unsafe { mem::transmute(slice) } + } + + #[inline] + fn as_bytes(&self) -> &[u8] { + &self.as_inner().inner + } +} diff --git a/library/std/src/os/qurt/fs.rs b/library/std/src/os/qurt/fs.rs new file mode 100644 index 0000000000000..e7bc270e55bea --- /dev/null +++ b/library/std/src/os/qurt/fs.rs @@ -0,0 +1,137 @@ +//! QuRT-specific extensions to primitives in the [`std::fs`] module. +//! +//! [`std::fs`]: crate::fs +//! +//! Note: QuRT has a minimal stat structure without uid/gid/blksize/blocks/nsec fields. +//! The accessor methods for these fields return stub values (0). + +#![stable(feature = "metadata_ext", since = "1.1.0")] + +use crate::fs::Metadata; +#[allow(deprecated)] +use crate::os::qurt::raw; +use crate::sys::AsInner; + +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: crate::fs::Metadata +/// +/// Note: QuRT has a minimal stat structure. The following fields are not available +/// and return stub values: +/// - `st_uid`, `st_gid`: QuRT doesn't have user/group ownership (returns 0) +/// - `st_blksize`, `st_blocks`: QuRT doesn't track block information (returns 0) +/// - `st_atime_nsec`, `st_mtime_nsec`, `st_ctime_nsec`: QuRT only has second-level precision (returns 0) +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + #[stable(feature = "metadata_ext", since = "1.1.0")] + #[deprecated( + since = "1.8.0", + note = "deprecated in favor of the accessor \ + methods of this trait" + )] + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat; + + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mode(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + /// Returns 0 on QuRT (user ownership not supported). + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + /// Returns 0 on QuRT (group ownership not supported). + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + /// Returns 0 on QuRT (nanosecond precision not supported). + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + /// Returns 0 on QuRT (nanosecond precision not supported). + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + /// Returns 0 on QuRT (nanosecond precision not supported). + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + /// Returns 0 on QuRT (block size not tracked). + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + /// Returns 0 on QuRT (block count not tracked). + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; +} + +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat { + unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } + } + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + fn st_uid(&self) -> u32 { + // QuRT doesn't have user ownership + 0 + } + fn st_gid(&self) -> u32 { + // QuRT doesn't have group ownership + 0 + } + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atime as i64 + } + fn st_atime_nsec(&self) -> i64 { + // QuRT only has second-level precision + 0 + } + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtime as i64 + } + fn st_mtime_nsec(&self) -> i64 { + // QuRT only has second-level precision + 0 + } + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctime as i64 + } + fn st_ctime_nsec(&self) -> i64 { + // QuRT only has second-level precision + 0 + } + fn st_blksize(&self) -> u64 { + // QuRT doesn't track block size + 0 + } + fn st_blocks(&self) -> u64 { + // QuRT doesn't track block count + 0 + } +} diff --git a/library/std/src/os/qurt/io.rs b/library/std/src/os/qurt/io.rs new file mode 100644 index 0000000000000..119f4f0944b1b --- /dev/null +++ b/library/std/src/os/qurt/io.rs @@ -0,0 +1,8 @@ +//! QuRT-specific I/O functionality. +//! +//! QuRT supports Unix-like file descriptors through its POSIX compatibility layer. + +#![stable(feature = "raw_ext", since = "1.1.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::os::fd::*; diff --git a/library/std/src/os/qurt/mod.rs b/library/std/src/os/qurt/mod.rs new file mode 100644 index 0000000000000..e006deac5f199 --- /dev/null +++ b/library/std/src/os/qurt/mod.rs @@ -0,0 +1,21 @@ +//! QuRT-specific definitions. + +#![stable(feature = "raw_ext", since = "1.1.0")] + +pub mod ffi; +pub mod fs; +pub mod io; +pub mod raw; + +/// A prelude for conveniently writing platform-specific code. +/// +/// Includes all extension traits, and some important type definitions. +#[stable(feature = "rust1", since = "1.0.0")] +pub mod prelude { + #[doc(no_inline)] + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::ffi::{OsStrExt, OsStringExt}; + #[doc(no_inline)] + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::fs::MetadataExt; +} diff --git a/library/std/src/os/qurt/raw.rs b/library/std/src/os/qurt/raw.rs new file mode 100644 index 0000000000000..0b91767080bf1 --- /dev/null +++ b/library/std/src/os/qurt/raw.rs @@ -0,0 +1,50 @@ +//! QuRT-specific raw type definitions. + +#![stable(feature = "raw_ext", since = "1.1.0")] + +use core::ffi::c_long; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type dev_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type ino_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type mode_t = u32; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type nlink_t = u32; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type off_t = c_long; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type time_t = c_long; + +// Threading types for QuRT pthread support +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type pthread_t = libc::pthread_t; + +/// Matches the layout of `libc::stat` for QuRT. +/// +/// QuRT has a minimal stat structure without uid/gid, blksize/blocks, +/// or nanosecond timestamp fields. +#[repr(C)] +#[derive(Clone)] +#[stable(feature = "raw_ext", since = "1.1.0")] +pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: ino_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: mode_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: nlink_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: off_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: time_t, +} diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index c119912c3b022..1bd3948c014d6 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -7,6 +7,7 @@ #[allow(unused_imports)] use io::{Read, Write}; +#[allow(unused_imports)] use super::platform::fs::MetadataExt as _; // Used for `File::read` on intra-doc links use crate::ffi::OsStr; diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs index 0385e5513ea08..eecebcbb061fe 100644 --- a/library/std/src/os/unix/io/mod.rs +++ b/library/std/src/os/unix/io/mod.rs @@ -217,7 +217,7 @@ fn replace_stdio_fd(this: BorrowedFd<'_>, other: OwnedFd) -> io::Result<()> { target_arch = "wasm32", target_os = "hermit", target_os = "trusty", - target_os = "motor" + target_os = "motor", )) => { cvt(unsafe {libc::dup2(other.as_raw_fd(), this.as_raw_fd())}).map(|_| ()) } diff --git a/library/std/src/process.rs b/library/std/src/process.rs index c5ffbbc666e43..5f44a75efe00a 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -157,6 +157,7 @@ target_os = "xous", target_os = "trusty", target_os = "hermit", + target_os = "qurt", )) ))] mod tests; diff --git a/library/std/src/sys/alloc/mod.rs b/library/std/src/sys/alloc/mod.rs index f2f1d1c7feceb..dc2c6ca357967 100644 --- a/library/std/src/sys/alloc/mod.rs +++ b/library/std/src/sys/alloc/mod.rs @@ -71,6 +71,7 @@ unsafe fn realloc_fallback( cfg_select! { any( target_family = "unix", + target_os = "qurt", target_os = "wasi", target_os = "teeos", target_os = "trusty", diff --git a/library/std/src/sys/args/unsupported.rs b/library/std/src/sys/args/unsupported.rs index ecffc6d26414b..ba63d04731d00 100644 --- a/library/std/src/sys/args/unsupported.rs +++ b/library/std/src/sys/args/unsupported.rs @@ -3,6 +3,10 @@ use crate::fmt; pub struct Args {} +pub unsafe fn init(_argc: isize, _argv: *const *const u8) { + // No-op for unsupported platforms +} + pub fn args() -> Args { Args {} } diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs index 858a95882b39f..6b31a34df50b4 100644 --- a/library/std/src/sys/backtrace.rs +++ b/library/std/src/sys/backtrace.rs @@ -202,7 +202,12 @@ pub fn output_filename( use crate::os::unix::prelude::*; Path::new(crate::ffi::OsStr::from_bytes(bytes)).into() } - #[cfg(not(unix))] + #[cfg(target_os = "qurt")] + BytesOrWideString::Bytes(bytes) => { + use crate::os::qurt::prelude::*; + Path::new(crate::ffi::OsStr::from_bytes(bytes)).into() + } + #[cfg(not(any(unix, target_os = "qurt")))] BytesOrWideString::Bytes(bytes) => { Path::new(crate::str::from_utf8(bytes).unwrap_or("")).into() } diff --git a/library/std/src/sys/env/mod.rs b/library/std/src/sys/env/mod.rs index 89856516b6dce..aae1a5a3ed2b1 100644 --- a/library/std/src/sys/env/mod.rs +++ b/library/std/src/sys/env/mod.rs @@ -6,6 +6,7 @@ target_family = "unix", target_os = "hermit", target_os = "motor", + target_os = "qurt", all(target_vendor = "fortanix", target_env = "sgx"), target_os = "solid_asp3", target_os = "uefi", @@ -15,7 +16,7 @@ mod common; cfg_select! { - target_family = "unix" => { + any(target_family = "unix", target_os = "qurt") => { mod unix; pub use unix::*; } diff --git a/library/std/src/sys/env/unix.rs b/library/std/src/sys/env/unix.rs index 7a19f97b3ad50..a319cdae6d537 100644 --- a/library/std/src/sys/env/unix.rs +++ b/library/std/src/sys/env/unix.rs @@ -5,6 +5,9 @@ use libc::c_char; pub use super::common::Env; use crate::ffi::{CStr, OsStr, OsString}; use crate::io; +#[cfg(target_os = "qurt")] +use crate::os::qurt::prelude::*; +#[cfg(not(target_os = "qurt"))] use crate::os::unix::prelude::*; use crate::sync::{PoisonError, RwLock}; use crate::sys::cvt; diff --git a/library/std/src/sys/exit.rs b/library/std/src/sys/exit.rs index 53fb92ba077e0..98ff547e45a1e 100644 --- a/library/std/src/sys/exit.rs +++ b/library/std/src/sys/exit.rs @@ -114,6 +114,7 @@ pub fn exit(code: i32) -> ! { } any( target_family = "unix", + target_os = "qurt", target_os = "wasi", ) => { unsafe { libc::exit(code as crate::ffi::c_int) } diff --git a/library/std/src/sys/fd/mod.rs b/library/std/src/sys/fd/mod.rs index 02d61a62f4e6b..746a839f5b1e8 100644 --- a/library/std/src/sys/fd/mod.rs +++ b/library/std/src/sys/fd/mod.rs @@ -3,7 +3,7 @@ #![forbid(unsafe_op_in_unsafe_fn)] cfg_select! { - any(target_family = "unix", target_os = "wasi") => { + any(target_family = "unix", target_os = "wasi", target_os = "qurt") => { mod unix; pub use unix::*; } diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index 392e33a77dc50..0920ba8406f54 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -8,6 +8,7 @@ mod tests; target_os = "l4re", target_os = "android", target_os = "hurd", + target_os = "qurt", )))] use libc::off_t as off64_t; #[cfg(any( @@ -28,6 +29,8 @@ cfg_select! { // #[cfg(gnu_file_offset_bits64)]. use libc::pread64; } + // QuRT doesn't have pread/pwrite - handled separately below + target_os = "qurt" => {} _ => { use libc::pread as pread64; } @@ -96,6 +99,7 @@ const fn max_iov() -> usize { target_os = "openbsd", target_os = "horizon", target_os = "vita", + target_os = "qurt", target_vendor = "apple", target_os = "cygwin", )))] @@ -123,6 +127,7 @@ impl FileDesc { #[cfg(not(any( target_os = "espidf", target_os = "horizon", + target_os = "qurt", target_os = "vita", target_os = "nuttx" )))] @@ -140,6 +145,7 @@ impl FileDesc { #[cfg(any( target_os = "espidf", target_os = "horizon", + target_os = "qurt", target_os = "vita", target_os = "nuttx" ))] @@ -152,6 +158,7 @@ impl FileDesc { cfg!(not(any( target_os = "espidf", target_os = "horizon", + target_os = "qurt", target_os = "vita", target_os = "nuttx", target_os = "wasi", @@ -163,6 +170,7 @@ impl FileDesc { (&mut me).read_to_end(buf) } + #[cfg(not(target_os = "qurt"))] pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { cvt(unsafe { pread64( @@ -175,6 +183,11 @@ impl FileDesc { .map(|n| n as usize) } + #[cfg(target_os = "qurt")] + pub fn read_at(&self, _buf: &mut [u8], _offset: u64) -> io::Result { + Err(io::const_error!(io::ErrorKind::Unsupported, "pread not supported on QuRT")) + } + pub fn read_buf(&self, mut cursor: BorrowedCursor<'_, u8>) -> io::Result<()> { // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes let ret = cvt(unsafe { @@ -192,6 +205,7 @@ impl FileDesc { Ok(()) } + #[cfg(not(target_os = "qurt"))] pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_, u8>, offset: u64) -> io::Result<()> { // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes let ret = cvt(unsafe { @@ -210,6 +224,11 @@ impl FileDesc { Ok(()) } + #[cfg(target_os = "qurt")] + pub fn read_buf_at(&self, _cursor: BorrowedCursor<'_>, _offset: u64) -> io::Result<()> { + Err(io::const_error!(io::ErrorKind::Unsupported, "pread not supported on QuRT")) + } + #[cfg(any( target_os = "aix", target_os = "dragonfly", // DragonFly 1.5 @@ -357,6 +376,7 @@ impl FileDesc { #[cfg(not(any( target_os = "espidf", target_os = "horizon", + target_os = "qurt", target_os = "vita", target_os = "nuttx" )))] @@ -374,6 +394,7 @@ impl FileDesc { #[cfg(any( target_os = "espidf", target_os = "horizon", + target_os = "qurt", target_os = "vita", target_os = "nuttx" ))] @@ -386,12 +407,14 @@ impl FileDesc { cfg!(not(any( target_os = "espidf", target_os = "horizon", + target_os = "qurt", target_os = "vita", target_os = "nuttx", target_os = "wasi", ))) } + #[cfg(not(target_os = "qurt"))] pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { #[cfg(not(any( all(target_os = "linux", not(target_env = "musl")), @@ -417,6 +440,11 @@ impl FileDesc { } } + #[cfg(target_os = "qurt")] + pub fn write_at(&self, _buf: &[u8], _offset: u64) -> io::Result { + Err(io::const_error!(io::ErrorKind::Unsupported, "pwrite not supported on QuRT")) + } + #[cfg(any( target_os = "aix", target_os = "dragonfly", // DragonFly 1.5 @@ -565,6 +593,10 @@ impl FileDesc { target_os = "nto", target_os = "qnx", target_os = "wasi", + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "qurt", )))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { @@ -601,9 +633,14 @@ impl FileDesc { Ok(()) } } - #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] + #[cfg(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "qurt" + ))] pub fn set_cloexec(&self) -> io::Result<()> { - // FD_CLOEXEC is not supported in ESP-IDF, Horizon OS and Vita but there's no need to, + // FD_CLOEXEC is not supported in ESP-IDF, Horizon OS, Vita, and QuRT but there's no need to, // because none of them supports spawning processes. Ok(()) } diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 0c297c5766b82..d835dc4ad53ea 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -6,14 +6,14 @@ use crate::path::{Path, PathBuf}; pub mod common; cfg_select! { - any(target_family = "unix", target_os = "wasi") => { + any(target_family = "unix", target_os = "wasi", target_os = "qurt") => { mod unix; use unix as imp; - #[cfg(not(target_os = "wasi"))] + #[cfg(not(any(target_os = "wasi", target_os = "qurt")))] pub use unix::{chown, fchown, lchown, mkfifo}; - #[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] + #[cfg(not(any(target_os = "fuchsia", target_os = "wasi", target_os = "qurt")))] pub use unix::chroot; - #[cfg(not(target_os = "wasi"))] + #[cfg(not(any(target_os = "wasi", target_os = "qurt")))] pub(crate) use unix::debug_assert_fd_is_open; #[cfg(any(target_os = "linux", target_os = "android"))] pub(super) use unix::CachedFileMetadata; @@ -52,7 +52,12 @@ cfg_select! { } // FIXME: Replace this with platform-specific path conversion functions. -#[cfg(not(any(target_family = "unix", target_os = "windows", target_os = "wasi")))] +#[cfg(not(any( + target_family = "unix", + target_os = "windows", + target_os = "wasi", + target_os = "qurt" +)))] #[inline] pub fn with_native_path(path: &Path, f: &dyn Fn(&Path) -> io::Result) -> io::Result { f(path) @@ -124,6 +129,7 @@ pub fn set_permissions(path: &Path, perm: FilePermissions) -> io::Result<()> { pub fn set_permissions_nofollow(path: &Path, perm: crate::fs::Permissions) -> io::Result<()> { use crate::fs::OpenOptions; + #[cfg_attr(any(target_os = "espidf", target_os = "horizon"), allow(unused_mut))] let mut options = OpenOptions::new(); // ESP-IDF and Horizon do not support O_NOFOLLOW, so we skip setting it. diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 7283e8f710c55..7fa06c0e31352 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -29,6 +29,7 @@ use libc::fstatat64; target_os = "illumos", target_os = "nto", target_os = "qnx", + target_os = "qurt", target_os = "redox", target_os = "solaris", target_os = "vita", @@ -47,6 +48,7 @@ use libc::readdir as readdir64; target_os = "linux", target_os = "nto", target_os = "qnx", + target_os = "qurt", target_os = "redox", target_os = "solaris", target_os = "vita", @@ -68,11 +70,18 @@ use libc::{ target_os = "l4re", target_os = "android", target_os = "hurd", + target_os = "qurt", )))] use libc::{ dirent as dirent64, fstat as fstat64, ftruncate as ftruncate64, lseek as lseek64, lstat as lstat64, off_t as off64_t, open as open64, stat as stat64, }; +// QuRT doesn't have lstat - use stat instead +#[cfg(target_os = "qurt")] +use libc::{ + dirent as dirent64, fstat as fstat64, ftruncate as ftruncate64, lseek as lseek64, + off_t as off64_t, open as open64, stat as stat64, stat as lstat64, +}; #[cfg(any( all(target_os = "linux", not(target_env = "musl")), target_os = "l4re", @@ -84,7 +93,9 @@ use crate::ffi::{CStr, OsStr, OsString}; use crate::fmt::{self, Write as _}; use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; -use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd}; +use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; +#[cfg(target_os = "qurt")] +use crate::os::qurt::prelude::*; #[cfg(target_family = "unix")] use crate::os::unix::prelude::*; #[cfg(target_os = "wasi")] @@ -100,6 +111,7 @@ use crate::sys::weak::syscall; #[cfg(target_os = "android")] use crate::sys::weak::weak; use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, cvt, cvt_r}; +#[cfg_attr(target_os = "qurt", allow(unused_imports))] use crate::{mem, ptr}; pub struct File(FileDesc); @@ -282,6 +294,7 @@ cfg_select! { target_os = "redox", target_os = "espidf", target_os = "horizon", + target_os = "qurt", target_os = "vita", target_os = "nto", target_os = "qnx", @@ -414,6 +427,7 @@ fn get_path_from_fd(fd: c_int) -> Option { target_os = "linux", target_os = "nto", target_os = "qnx", + target_os = "qurt", target_os = "redox", target_os = "solaris", target_os = "vita", @@ -441,6 +455,7 @@ pub struct DirEntry { target_os = "linux", target_os = "nto", target_os = "qnx", + target_os = "qurt", target_os = "redox", target_os = "solaris", target_os = "vita", @@ -454,6 +469,7 @@ struct dirent64_min { target_os = "aix", target_os = "nto", target_os = "qnx", + target_os = "qurt", target_os = "vita", )))] d_type: u8, @@ -469,6 +485,7 @@ struct dirent64_min { target_os = "linux", target_os = "nto", target_os = "qnx", + target_os = "qurt", target_os = "redox", target_os = "solaris", target_os = "vita", @@ -632,6 +649,7 @@ impl FileAttr { target_os = "horizon", target_os = "vita", target_os = "hurd", + target_os = "qurt", target_os = "rtems", target_os = "nuttx", )))] @@ -649,6 +667,7 @@ impl FileAttr { #[cfg(any( all(target_os = "vxworks", vxworks_lt_25_09), target_os = "espidf", + target_os = "qurt", target_os = "vita", target_os = "rtems", ))] @@ -672,6 +691,7 @@ impl FileAttr { target_os = "horizon", target_os = "vita", target_os = "hurd", + target_os = "qurt", target_os = "rtems", target_os = "nuttx", )))] @@ -689,6 +709,7 @@ impl FileAttr { #[cfg(any( all(target_os = "vxworks", vxworks_lt_25_09), target_os = "espidf", + target_os = "qurt", target_os = "vita", target_os = "rtems" ))] @@ -868,6 +889,7 @@ impl Iterator for ReadDir { target_os = "linux", target_os = "nto", target_os = "qnx", + target_os = "qurt", target_os = "redox", target_os = "solaris", target_os = "vita", @@ -942,6 +964,7 @@ impl Iterator for ReadDir { target_os = "aix", target_os = "nto", target_os = "qnx", + target_os = "qurt", )))] d_type: (*entry_ptr).d_type as u8, }; @@ -968,6 +991,7 @@ impl Iterator for ReadDir { target_os = "linux", target_os = "nto", target_os = "qnx", + target_os = "qurt", target_os = "redox", target_os = "solaris", target_os = "vita", @@ -1013,6 +1037,7 @@ impl Iterator for ReadDir { /// So we check file flags instead which live on the file descriptor and not the underlying file. /// The downside is that it costs an extra syscall, so we only do it for debug. #[inline] +#[cfg_attr(target_os = "qurt", allow(dead_code))] pub(crate) fn debug_assert_fd_is_open(fd: RawFd) { use crate::sys::io::errno; @@ -1032,6 +1057,7 @@ impl Drop for DirStream { target_os = "redox", target_os = "nto", target_os = "qnx", + target_os = "qurt", target_os = "vita", target_os = "hurd", target_os = "espidf", @@ -1121,6 +1147,7 @@ impl DirEntry { target_os = "aix", target_os = "nto", target_os = "qnx", + target_os = "qurt", target_os = "vita", ))] pub fn file_type(&self) -> io::Result { @@ -1135,6 +1162,7 @@ impl DirEntry { target_os = "aix", target_os = "nto", target_os = "qnx", + target_os = "qurt", target_os = "vita", )))] pub fn file_type(&self) -> io::Result { @@ -1166,6 +1194,7 @@ impl DirEntry { target_os = "linux", target_os = "nto", target_os = "qnx", + target_os = "qurt", target_os = "redox", target_os = "rtems", target_os = "solaris", @@ -1226,6 +1255,7 @@ impl DirEntry { target_os = "aix", target_os = "nto", target_os = "qnx", + target_os = "qurt", target_os = "vita", target_os = "hurd", target_os = "wasi", @@ -1244,6 +1274,7 @@ impl DirEntry { target_os = "aix", target_os = "nto", target_os = "qnx", + target_os = "qurt", target_os = "vita", target_os = "hurd", target_os = "wasi", @@ -1410,6 +1441,7 @@ impl File { Ok(FileAttr::from_stat64(stat)) } + #[cfg(not(target_os = "qurt"))] pub fn fsync(&self) -> io::Result<()> { cvt_r(|| unsafe { os_fsync(self.as_raw_fd()) })?; return Ok(()); @@ -1424,6 +1456,12 @@ impl File { } } + #[cfg(target_os = "qurt")] + pub fn fsync(&self) -> io::Result<()> { + Err(io::const_error!(io::ErrorKind::Unsupported, "fsync not supported on QuRT")) + } + + #[cfg(not(target_os = "qurt"))] pub fn datasync(&self) -> io::Result<()> { cvt_r(|| unsafe { os_datasync(self.as_raw_fd()) })?; return Ok(()); @@ -1465,6 +1503,23 @@ impl File { } } + #[cfg(target_os = "qurt")] + pub fn datasync(&self) -> io::Result<()> { + Err(io::const_error!(io::ErrorKind::Unsupported, "datasync not supported on QuRT")) + } + + #[cfg(any( + target_os = "freebsd", + target_os = "fuchsia", + target_os = "hurd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", + target_os = "illumos", + target_os = "aix", + target_vendor = "apple", + ))] pub fn lock(&self) -> io::Result<()> { cfg_select! { any( @@ -1697,16 +1752,22 @@ impl File { self.0.duplicate().map(File) } + #[cfg(not(target_os = "qurt"))] pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { cvt_r(|| unsafe { libc::fchmod(self.as_raw_fd(), perm.mode) })?; Ok(()) } + #[cfg(target_os = "qurt")] + pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { + Err(io::const_error!(io::ErrorKind::Unsupported, "fchmod not supported on QuRT")) + } + pub fn set_times(&self, times: FileTimes) -> io::Result<()> { cfg_select! { - any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "nuttx") => { + any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "nuttx", target_os = "qurt") => { // Redox doesn't appear to support `UTIME_OMIT`. - // ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore + // ESP-IDF, HorizonOS, and QuRT do not support `futimens` at all and the behavior for those OS is therefore // the same as for Redox. let _ = times; Err(io::const_error!( @@ -1773,6 +1834,7 @@ impl File { target_os = "espidf", target_os = "horizon", target_os = "nuttx", + target_os = "qurt", )))] fn file_time_to_timespec(time: Option) -> io::Result { match time { @@ -2009,14 +2071,21 @@ pub fn rename(old: &CStr, new: &CStr) -> io::Result<()> { cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }).map(|_| ()) } +#[cfg(not(target_os = "qurt"))] pub fn set_perm(p: &CStr, perm: FilePermissions) -> io::Result<()> { cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) }).map(|_| ()) } +#[cfg(target_os = "qurt")] +pub fn set_perm(_p: &CStr, _perm: FilePermissions) -> io::Result<()> { + Err(io::const_error!(io::ErrorKind::Unsupported, "chmod not supported on QuRT")) +} + pub fn rmdir(p: &CStr) -> io::Result<()> { cvt(unsafe { libc::rmdir(p.as_ptr()) }).map(|_| ()) } +#[cfg(not(target_os = "qurt"))] pub fn readlink(c_path: &CStr) -> io::Result { let p = c_path.as_ptr(); @@ -2043,12 +2112,28 @@ pub fn readlink(c_path: &CStr) -> io::Result { } } +#[cfg(target_os = "qurt")] +pub fn readlink(_c_path: &CStr) -> io::Result { + Err(io::const_error!(io::ErrorKind::Unsupported, "readlink not supported on QuRT")) +} + +#[cfg(not(target_os = "qurt"))] pub fn symlink(original: &CStr, link: &CStr) -> io::Result<()> { cvt(unsafe { libc::symlink(original.as_ptr(), link.as_ptr()) }).map(|_| ()) } +#[cfg(target_os = "qurt")] +pub fn symlink(_original: &CStr, _link: &CStr) -> io::Result<()> { + Err(io::const_error!(io::ErrorKind::Unsupported, "symlink not supported on QuRT")) +} + pub fn link(original: &CStr, link: &CStr) -> io::Result<()> { cfg_select! { + target_os = "qurt" => { + // QuRT doesn't support hard links + let _ = (original, link); + Err(io::const_error!(io::ErrorKind::Unsupported, "link not supported on QuRT")) + } any( // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. // POSIX leaves it implementation-defined whether `link` follows @@ -2066,14 +2151,15 @@ pub fn link(original: &CStr, link: &CStr) -> io::Result<()> { target_env = "nto70", ) => { cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?; + Ok(()) } _ => { // Where we can, use `linkat` instead of `link`; see the comment above // this one for details on why. cvt(unsafe { libc::linkat(libc::AT_FDCWD, original.as_ptr(), libc::AT_FDCWD, link.as_ptr(), 0) })?; + Ok(()) } } - Ok(()) } pub fn stat(p: &CStr) -> io::Result { @@ -2110,6 +2196,7 @@ pub fn lstat(p: &CStr) -> io::Result { Ok(FileAttr::from_stat64(stat)) } +#[cfg(not(target_os = "qurt"))] pub fn canonicalize(path: &CStr) -> io::Result { let r = unsafe { libc::realpath(path.as_ptr(), ptr::null_mut()) }; if r.is_null() { @@ -2122,6 +2209,11 @@ pub fn canonicalize(path: &CStr) -> io::Result { }))) } +#[cfg(target_os = "qurt")] +pub fn canonicalize(_path: &CStr) -> io::Result { + Err(io::const_error!(io::ErrorKind::Unsupported, "realpath not supported on QuRT")) +} + fn open_from(from: &Path) -> io::Result<(crate::fs::File, crate::fs::Metadata)> { use crate::fs::File; use crate::sys::fs::common::NOT_FILE_ERROR; @@ -2136,7 +2228,7 @@ fn open_from(from: &Path) -> io::Result<(crate::fs::File, crate::fs::Metadata)> fn set_times_impl(p: &CStr, times: FileTimes, follow_symlinks: bool) -> io::Result<()> { cfg_select! { - any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "nuttx", target_os = "vita", target_os = "rtems") => { + any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "nuttx", target_os = "vita", target_os = "rtems", target_os = "qurt") => { let _ = (p, times, follow_symlinks); Err(io::const_error!( io::ErrorKind::Unsupported, @@ -2215,7 +2307,7 @@ pub fn set_times_nofollow(p: &CStr, times: FileTimes) -> io::Result<()> { set_times_impl(p, times, false) } -#[cfg(any(target_os = "espidf", target_os = "wasi"))] +#[cfg(any(target_os = "espidf", target_os = "qurt", target_os = "wasi"))] fn open_to_and_set_permissions( to: &Path, _reader_metadata: &crate::fs::Metadata, @@ -2226,7 +2318,7 @@ fn open_to_and_set_permissions( Ok((writer, writer_metadata)) } -#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +#[cfg(not(any(target_os = "espidf", target_os = "qurt", target_os = "wasi")))] fn open_to_and_set_permissions( to: &Path, reader_metadata: &crate::fs::Metadata, @@ -2374,7 +2466,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { Ok(bytes_copied as u64) } -#[cfg(not(target_os = "wasi"))] +#[cfg(not(any(target_os = "wasi", target_os = "qurt")))] pub fn chown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { run_path_with_cstr(path, &|path| { cvt(unsafe { libc::chown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) }) @@ -2382,13 +2474,13 @@ pub fn chown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { }) } -#[cfg(not(target_os = "wasi"))] +#[cfg(not(any(target_os = "wasi", target_os = "qurt")))] pub fn fchown(fd: c_int, uid: u32, gid: u32) -> io::Result<()> { cvt(unsafe { libc::fchown(fd, uid as libc::uid_t, gid as libc::gid_t) })?; Ok(()) } -#[cfg(not(any(target_os = "vxworks", target_os = "wasi")))] +#[cfg(not(any(target_os = "vxworks", target_os = "wasi", target_os = "qurt")))] pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { run_path_with_cstr(path, &|path| { cvt(unsafe { libc::lchown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) }) @@ -2397,23 +2489,26 @@ pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { } #[cfg(target_os = "vxworks")] -pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { - let (_, _, _) = (path, uid, gid); +pub fn lchown(_path: &Path, _uid: u32, _gid: u32) -> io::Result<()> { Err(io::const_error!(io::ErrorKind::Unsupported, "lchown not supported by vxworks")) } -#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks", target_os = "wasi")))] +#[cfg(not(any( + target_os = "fuchsia", + target_os = "vxworks", + target_os = "wasi", + target_os = "qurt" +)))] pub fn chroot(dir: &Path) -> io::Result<()> { run_path_with_cstr(dir, &|dir| cvt(unsafe { libc::chroot(dir.as_ptr()) }).map(|_| ())) } #[cfg(target_os = "vxworks")] -pub fn chroot(dir: &Path) -> io::Result<()> { - let _ = dir; +pub fn chroot(_dir: &Path) -> io::Result<()> { Err(io::const_error!(io::ErrorKind::Unsupported, "chroot not supported by vxworks")) } -#[cfg(not(target_os = "wasi"))] +#[cfg(not(any(target_os = "wasi", target_os = "qurt")))] pub fn mkfifo(path: &Path, mode: u32) -> io::Result<()> { run_path_with_cstr(path, &|path| { cvt(unsafe { libc::mkfifo(path.as_ptr(), mode.try_into().unwrap()) }).map(|_| ()) @@ -2422,11 +2517,12 @@ pub fn mkfifo(path: &Path, mode: u32) -> io::Result<()> { pub use remove_dir_impl::remove_dir_all; -// Fallback for REDOX, ESP-ID, Horizon, Vita, Vxworks and Miri +// Fallback for REDOX, ESP-ID, Horizon, QuRT, Vita, Vxworks and Miri #[cfg(any( target_os = "redox", target_os = "espidf", target_os = "horizon", + target_os = "qurt", target_os = "vita", target_os = "nto", target_os = "qnx", @@ -2442,6 +2538,7 @@ mod remove_dir_impl { target_os = "redox", target_os = "espidf", target_os = "horizon", + target_os = "qurt", target_os = "vita", target_os = "nto", target_os = "qnx", diff --git a/library/std/src/sys/io/error/mod.rs b/library/std/src/sys/io/error/mod.rs index cc8cda9aec045..65108cf240d93 100644 --- a/library/std/src/sys/io/error/mod.rs +++ b/library/std/src/sys/io/error/mod.rs @@ -23,7 +23,7 @@ cfg_select! { mod uefi; pub use uefi::*; } - target_family = "unix" => { + any(target_family = "unix", target_os = "qurt") => { mod unix; pub use unix::*; } diff --git a/library/std/src/sys/io/error/unix.rs b/library/std/src/sys/io/error/unix.rs index 85e3c09782ae2..a765575f5bb17 100644 --- a/library/std/src/sys/io/error/unix.rs +++ b/library/std/src/sys/io/error/unix.rs @@ -31,6 +31,7 @@ unsafe extern "C" { #[cfg_attr(any(target_os = "freebsd", target_vendor = "apple"), link_name = "__error")] #[cfg_attr(target_os = "haiku", link_name = "_errnop")] #[cfg_attr(target_os = "aix", link_name = "_Errno")] + #[cfg_attr(target_os = "qurt", link_name = "_Geterrno")] // SAFETY: this will always return the same pointer on a given thread. #[unsafe(ffi_const)] pub safe fn errno_location() -> *mut c_int; diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs index 0158137174087..7d68f86dd1b3a 100644 --- a/library/std/src/sys/io/mod.rs +++ b/library/std/src/sys/io/mod.rs @@ -4,7 +4,7 @@ mod error; mod is_terminal { cfg_select! { - any(target_family = "unix", target_os = "wasi") => { + any(target_family = "unix", target_os = "wasi", target_os = "qurt") => { mod isatty; pub use isatty::*; } @@ -38,6 +38,7 @@ pub use error::errno_location; #[cfg_attr(not(target_os = "linux"), allow(unused_imports))] #[cfg(any( all(target_family = "unix", not(any(target_os = "vxworks", target_os = "rtems"))), + target_os = "qurt", target_os = "wasi", ))] pub use error::set_errno; diff --git a/library/std/src/sys/net/connection/unsupported.rs b/library/std/src/sys/net/connection/unsupported.rs index 7a4d3a97b8324..41e747a07ca70 100644 --- a/library/std/src/sys/net/connection/unsupported.rs +++ b/library/std/src/sys/net/connection/unsupported.rs @@ -1,7 +1,10 @@ use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; +#[cfg(not(target_os = "qurt"))] use crate::sys::unsupported; +#[cfg(target_os = "qurt")] +use crate::sys::unsupported::unsupported; use crate::time::Duration; pub struct TcpStream(!); diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index 88d9d42059900..3371dcc87e44c 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -4,7 +4,7 @@ #![allow(missing_debug_implementations)] cfg_select! { - unix => { + any(unix, target_os = "qurt") => { mod unix; pub use self::unix::*; } diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 75a75ab6bc5fd..f53e4c569859c 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -59,6 +59,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { #[cfg(all(target_os = "linux", target_env = "gnu"))] use libc::open64 as open; + #[cfg(not(target_os = "qurt"))] if opened_devnull != -1 { if libc::dup(opened_devnull) != -1 { return; @@ -85,6 +86,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { target_os = "horizon", target_os = "vita", target_os = "rtems", + target_os = "qurt", // The poll on Darwin doesn't set POLLNVAL for closed fds. target_vendor = "apple", )))] @@ -129,6 +131,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { target_os = "l4re", target_os = "horizon", target_os = "vita", + target_os = "qurt", )))] { use crate::sys::io::errno; @@ -206,6 +209,7 @@ static ON_BROKEN_PIPE_USED: crate::sync::atomic::Atomic = target_os = "vxworks", target_os = "vita", target_os = "nuttx", + target_os = "qurt", )))] pub(crate) fn on_broken_pipe_used() -> bool { ON_BROKEN_PIPE_USED.load(crate::sync::atomic::Ordering::Relaxed) @@ -365,7 +369,13 @@ cfg_select! { _ => {} } -#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] +#[cfg(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx", + target_os = "qurt" +))] pub mod unsupported { use crate::io; diff --git a/library/std/src/sys/paths/mod.rs b/library/std/src/sys/paths/mod.rs index 8880a837af7f9..c20ba27cb6e7f 100644 --- a/library/std/src/sys/paths/mod.rs +++ b/library/std/src/sys/paths/mod.rs @@ -30,7 +30,7 @@ cfg_select! { mod uefi; use uefi as imp; } - target_family = "unix" => { + any(target_family = "unix", target_os = "qurt") => { mod unix; use unix as imp; } diff --git a/library/std/src/sys/paths/unix.rs b/library/std/src/sys/paths/unix.rs index c2ecc6e5da3d4..e9e669713e3de 100644 --- a/library/std/src/sys/paths/unix.rs +++ b/library/std/src/sys/paths/unix.rs @@ -5,6 +5,9 @@ use libc::{c_char, c_int, c_void}; use crate::ffi::{CStr, OsStr, OsString}; +#[cfg(target_os = "qurt")] +use crate::os::qurt::prelude::*; +#[cfg(not(target_os = "qurt"))] use crate::os::unix::prelude::*; use crate::path::{self, PathBuf}; use crate::sys::helpers::run_path_with_cstr; @@ -45,12 +48,12 @@ pub fn getcwd() -> io::Result { } } -#[cfg(target_os = "espidf")] +#[cfg(any(target_os = "espidf", target_os = "qurt"))] pub fn chdir(_p: &path::Path) -> io::Result<()> { crate::sys::pal::unsupported::unsupported() } -#[cfg(not(target_os = "espidf"))] +#[cfg(not(any(target_os = "espidf", target_os = "qurt")))] pub fn chdir(p: &path::Path) -> io::Result<()> { let result = run_path_with_cstr(p, &|p| unsafe { Ok(libc::chdir(p.as_ptr())) })?; if result == 0 { Ok(()) } else { Err(io::Error::last_os_error()) } @@ -383,7 +386,7 @@ pub fn current_exe() -> io::Result { path.canonicalize() } -#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] +#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "qurt"))] pub fn current_exe() -> io::Result { crate::sys::pal::unsupported::unsupported() } @@ -442,6 +445,7 @@ pub fn home_dir() -> Option { target_os = "horizon", target_os = "vita", target_os = "nuttx", + target_os = "qurt", all(target_vendor = "apple", not(target_os = "macos")), ))] unsafe fn fallback() -> Option { @@ -456,6 +460,7 @@ pub fn home_dir() -> Option { target_os = "horizon", target_os = "vita", target_os = "nuttx", + target_os = "qurt", all(target_vendor = "apple", not(target_os = "macos")), )))] unsafe fn fallback() -> Option { diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs index eabef92244d01..6a2298c5882f3 100644 --- a/library/std/src/sys/personality/mod.rs +++ b/library/std/src/sys/personality/mod.rs @@ -33,7 +33,7 @@ cfg_select! { target_os = "psp", target_os = "xous", target_os = "solid_asp3", - all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "nuttx")), + all(any(target_family = "unix", target_os = "qurt"), not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "nuttx")), all(target_vendor = "fortanix", target_env = "sgx"), ) => { mod gcc; diff --git a/library/std/src/sys/pipe/unsupported.rs b/library/std/src/sys/pipe/unsupported.rs index 3b1a71eb3af17..fba7f190c6c34 100644 --- a/library/std/src/sys/pipe/unsupported.rs +++ b/library/std/src/sys/pipe/unsupported.rs @@ -56,7 +56,7 @@ impl fmt::Debug for Pipe { } } -#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))] +#[cfg(any(unix, target_os = "hermit", target_os = "qurt", target_os = "wasi"))] mod unix_traits { use super::Pipe; use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; diff --git a/library/std/src/sys/process/mod.rs b/library/std/src/sys/process/mod.rs index ee61175a278b0..59e0c106e584f 100644 --- a/library/std/src/sys/process/mod.rs +++ b/library/std/src/sys/process/mod.rs @@ -45,7 +45,7 @@ pub use imp::{ target_os = "espidf", target_os = "horizon", target_os = "vita", - target_os = "nuttx" + target_os = "nuttx", )) ), target_os = "windows", @@ -83,7 +83,7 @@ pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec, Vec< target_os = "espidf", target_os = "horizon", target_os = "vita", - target_os = "nuttx" + target_os = "nuttx", )) ), target_os = "windows", diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs index 8215b196127ac..021cee76caa01 100644 --- a/library/std/src/sys/process/unix/common.rs +++ b/library/std/src/sys/process/unix/common.rs @@ -688,6 +688,7 @@ pub fn getpid() -> u32 { unsafe { libc::getpid() as u32 } } +#[cfg(not(target_os = "qurt"))] pub fn getppid() -> u32 { unsafe { libc::getppid() as u32 } } diff --git a/library/std/src/sys/process/unsupported.rs b/library/std/src/sys/process/unsupported.rs index 114f0001b7faf..ec6e5c6e78466 100644 --- a/library/std/src/sys/process/unsupported.rs +++ b/library/std/src/sys/process/unsupported.rs @@ -5,7 +5,10 @@ use crate::num::NonZero; use crate::path::Path; use crate::process::StdioPipes; use crate::sys::fs::File; +#[cfg(not(target_os = "qurt"))] use crate::sys::unsupported; +#[cfg(target_os = "qurt")] +use crate::sys::unsupported::unsupported; use crate::{fmt, io}; //////////////////////////////////////////////////////////////////////////////// diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index e5a66dc463c6b..77dbf82b2517b 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -107,6 +107,7 @@ cfg_select! { all(target_family = "wasm", target_os = "unknown"), target_os = "xous", target_os = "vexos", + target_os = "qurt", ) => { // FIXME: finally remove std support for wasm32-unknown-unknown // FIXME: add random data generation to xous @@ -123,6 +124,7 @@ cfg_select! { all(target_os = "wasi", not(target_env = "p1")), target_os = "xous", target_os = "vexos", + target_os = "qurt", )))] pub fn hashmap_random_keys() -> (u64, u64) { let mut buf = [0; 16]; diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs index 86d0f3fe49cb3..915f206a4a77b 100644 --- a/library/std/src/sys/stdio/mod.rs +++ b/library/std/src/sys/stdio/mod.rs @@ -1,7 +1,12 @@ #![forbid(unsafe_op_in_unsafe_fn)] cfg_select! { - any(target_family = "unix", target_os = "hermit", target_os = "wasi") => { + any( + target_family = "unix", + target_os = "hermit", + target_os = "wasi", + target_os = "qurt", + ) => { mod unix; pub use unix::*; } diff --git a/library/std/src/sys/stdio/unix.rs b/library/std/src/sys/stdio/unix.rs index 205478f2a5e99..fc9fd39d6b1e2 100644 --- a/library/std/src/sys/stdio/unix.rs +++ b/library/std/src/sys/stdio/unix.rs @@ -1,6 +1,6 @@ #[cfg(target_os = "hermit")] use hermit_abi::{EBADF, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; -#[cfg(any(target_family = "unix", target_os = "wasi"))] +#[cfg(any(target_family = "unix", target_os = "wasi", target_os = "qurt"))] use libc::{EBADF, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; diff --git a/library/std/src/sys/sync/condvar/mod.rs b/library/std/src/sys/sync/condvar/mod.rs index 83cf0ae629851..9c179054d4181 100644 --- a/library/std/src/sys/sync/condvar/mod.rs +++ b/library/std/src/sys/sync/condvar/mod.rs @@ -17,6 +17,7 @@ cfg_select! { any( target_family = "unix", target_os = "teeos", + target_os = "qurt", ) => { mod pthread; pub use pthread::Condvar; diff --git a/library/std/src/sys/sync/mutex/mod.rs b/library/std/src/sys/sync/mutex/mod.rs index e3d6ad1129c83..8310fd4cbb954 100644 --- a/library/std/src/sys/sync/mutex/mod.rs +++ b/library/std/src/sys/sync/mutex/mod.rs @@ -20,6 +20,7 @@ cfg_select! { any( target_family = "unix", target_os = "teeos", + target_os = "qurt", ) => { mod pthread; pub use pthread::Mutex; diff --git a/library/std/src/sys/sync/once/mod.rs b/library/std/src/sys/sync/once/mod.rs index 5796c6d207dba..aa4bd31d29369 100644 --- a/library/std/src/sys/sync/once/mod.rs +++ b/library/std/src/sys/sync/once/mod.rs @@ -26,6 +26,7 @@ cfg_select! { any( windows, target_family = "unix", + target_os = "qurt", all(target_vendor = "fortanix", target_env = "sgx"), target_os = "solid_asp3", target_os = "xous", diff --git a/library/std/src/sys/sync/rwlock/mod.rs b/library/std/src/sys/sync/rwlock/mod.rs index 8603fca2da5b5..e8c03e499f8c2 100644 --- a/library/std/src/sys/sync/rwlock/mod.rs +++ b/library/std/src/sys/sync/rwlock/mod.rs @@ -20,6 +20,7 @@ cfg_select! { all(target_vendor = "fortanix", target_env = "sgx"), target_os = "xous", target_os = "teeos", + target_os = "qurt", ) => { mod queue; pub use queue::RwLock; diff --git a/library/std/src/sys/sync/thread_parking/mod.rs b/library/std/src/sys/sync/thread_parking/mod.rs index 9d5a0a996b115..b4cc066f19d86 100644 --- a/library/std/src/sys/sync/thread_parking/mod.rs +++ b/library/std/src/sys/sync/thread_parking/mod.rs @@ -38,6 +38,7 @@ cfg_select! { any( target_family = "unix", target_os = "teeos", + target_os = "qurt", ) => { mod pthread; pub use pthread::Parker; diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs index 9816981c7fc88..e6bdfbd4d3c2f 100644 --- a/library/std/src/sys/thread/mod.rs +++ b/library/std/src/sys/thread/mod.rs @@ -48,7 +48,7 @@ cfg_select! { mod unsupported; pub use unsupported::{Thread, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE}; } - any(target_family = "unix", target_os = "wasi") => { + any(target_family = "unix", target_os = "wasi", target_os = "qurt") => { mod unix; pub use unix::{Thread, available_parallelism, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; #[cfg(not(any( diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index e52ffff165beb..9123a34b79efb 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -428,7 +428,7 @@ pub fn set_name(name: &CStr) { target_os = "freebsd", target_os = "dragonfly", target_os = "nuttx", - target_os = "cygwin" + target_os = "cygwin", ))] pub fn set_name(name: &CStr) { unsafe { @@ -532,6 +532,11 @@ pub fn set_name(name: &CStr) { debug_assert_eq!(res, libc::OK); } +#[cfg(target_os = "qurt")] +pub fn set_name(_name: &CStr) { + // QuRT doesn't support pthread_setname_np +} + #[cfg(not(target_os = "espidf"))] pub fn sleep(dur: Duration) { cfg_select! { diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index d48bb1c8b721e..f24e6c3529093 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -146,7 +146,7 @@ pub(crate) mod key { all( not(target_vendor = "apple"), not(target_family = "wasm"), - target_family = "unix", + any(target_family = "unix", target_os = "qurt"), ), all(not(target_thread_local), target_vendor = "apple"), target_os = "teeos", diff --git a/library/std/src/sys/time/mod.rs b/library/std/src/sys/time/mod.rs index 6cd1850e7cca1..687667e580887 100644 --- a/library/std/src/sys/time/mod.rs +++ b/library/std/src/sys/time/mod.rs @@ -21,6 +21,7 @@ cfg_select! { any( target_os = "teeos", target_family = "unix", + target_os = "qurt", target_os = "wasi", ) => { mod unix; diff --git a/library/sysroot/src/lib.rs b/library/sysroot/src/lib.rs index 71ceb580a40c3..8dcc1a554e12c 100644 --- a/library/sysroot/src/lib.rs +++ b/library/sysroot/src/lib.rs @@ -1 +1,2 @@ +#![cfg_attr(target_os = "qurt", feature(restricted_std))] // This is intentionally empty since this crate is only used to depend on other library crates. diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index e4280520bd8ba..8f0a06e87cc9a 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -26,6 +26,7 @@ #![feature(panic_can_unwind)] #![cfg_attr(test, feature(test))] #![feature(thread_spawn_hook)] +#![cfg_attr(target_os = "qurt", feature(restricted_std))] #![allow(internal_features)] #![warn(rustdoc::unescaped_backticks)] #![warn(unreachable_pub)] diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index cb4a3593c51d6..174ef0903cc85 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -30,6 +30,7 @@ cfg_select! { unix, windows, target_os = "psp", + target_os = "qurt", target_os = "solid_asp3", all(target_vendor = "fortanix", target_env = "sgx"), all(target_os = "wasi", panic = "unwind"), diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 60d76719dac62..8d2a1b94f42f9 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -332,6 +332,7 @@ impl Cargo { && !target.contains("cygwin") && !target.contains("aix") && !target.contains("xous") + && !target.contains("qurt") { self.rustflags.arg("-Clink-args=-Wl,-z,origin"); Some(format!("-Wl,-rpath,$ORIGIN/../{libdir}")) From fba5b0a70a1f9f7b8930931606018bcf3519ba1a Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 5 May 2026 15:51:22 -0700 Subject: [PATCH 02/13] Update hexagon-unknown-qurt platform support documentation Update documentation with details about how to leverage qurt, now that there's some level of libstd support --- .../platform-support/hexagon-unknown-qurt.md | 377 ++++++++++++++---- 1 file changed, 289 insertions(+), 88 deletions(-) diff --git a/src/doc/rustc/src/platform-support/hexagon-unknown-qurt.md b/src/doc/rustc/src/platform-support/hexagon-unknown-qurt.md index d33a90bf188c7..11c2c8af7fb16 100644 --- a/src/doc/rustc/src/platform-support/hexagon-unknown-qurt.md +++ b/src/doc/rustc/src/platform-support/hexagon-unknown-qurt.md @@ -15,33 +15,40 @@ Rust for Hexagon QuRT (Qualcomm Real-Time OS). ## Requirements This target is cross-compiled. There is support for `std`. The target uses -QuRT's standard library and runtime. +QuRT's POSIX-like threading and Dinkumware C library. By default, code generated with this target should run on Hexagon DSP hardware -running the QuRT real-time operating system. +running the QuRT real-time operating system, or on `qemu-system-hexagon`. - `-Ctarget-cpu=hexagonv69` targets Hexagon V69 architecture (default) - `-Ctarget-cpu=hexagonv73` adds support for instructions defined up to Hexagon V73 Functions marked `extern "C"` use the [Hexagon architecture calling convention](https://lists.llvm.org/pipermail/llvm-dev/attachments/20190916/21516a52/attachment-0001.pdf). -This target generates position-independent ELF binaries by default, making it -suitable for both static images and dynamic shared objects. - The [Hexagon SDK](https://softwarecenter.qualcomm.com/catalog/item/Hexagon_SDK) is -required for building programs for this target. +required for building and running programs for this target. It provides: -## Linking +- `hexagon-clang` (compiler and linker) +- QuRT runtime libraries (`libqurt.a`, `libposix.a`, etc.) +- CRT startup objects (`crt1.o`, `crt0.o`, `init.o`, `fini.o`, `debugmon.o`) +- `qemu-system-hexagon` emulator -This target uses `hexagon-clang` from the Hexagon SDK as the default linker. -The linker is available at paths like -`/opt/Hexagon_SDK/6.4.0.2/tools/HEXAGON_Tools/19.0.04/Tools/bin/hexagon-clang`. +Programs require the `restricted_std` feature gate: -Alternative linkers include: -- [eld](https://github.com/qualcomm/eld), which is provided with both - [the opensource hexagon toolchain](https://github.com/quic/toolchain_for_hexagon) - and the Hexagon SDK -- `rust-lld` can be used by specifying `-C linker=rust-lld` +```rust +#![feature(restricted_std)] +``` + +## SDK setup + +Source the SDK environment script to set `HEXAGON_SDK_ROOT` and tool paths: + +```sh +source /opt/Hexagon_SDK/6.4.0.2/setup_sdk_env.source +``` + +This exports `HEXAGON_SDK_ROOT`, `DEFAULT_HEXAGON_TOOLS_ROOT`, and +`DEFAULT_QURT_PATH`. All paths below reference these variables. ## Building the target @@ -72,114 +79,308 @@ this target, you will either need to build Rust with the target enabled (see "Building the target" above), or build your own copy of `core` by using `build-std` or similar. -## Static Image Targeting +## Linking + +QuRT executables require specific CRT startup objects and system libraries. +A `build.rs` script can derive the library paths from environment variables set +by the SDK's `setup_sdk_env.source`. -For static executables that run directly on QuRT, use the default target -configuration with additional linker flags: +### Example `build.rs` + +```rust +use std::env; +use std::path::PathBuf; + +fn main() { + // Only apply QuRT link configuration when targeting hexagon-unknown-qurt + let target = env::var("TARGET").unwrap_or_default(); + if target != "hexagon-unknown-qurt" { + return; + } + + // Derive paths from Hexagon SDK environment variables. + // These are set by: source $HEXAGON_SDK_ROOT/setup_sdk_env.source + let sdk = env::var("HEXAGON_SDK_ROOT") + .expect("HEXAGON_SDK_ROOT not set — source setup_sdk_env.source"); + let tools_root = env::var("DEFAULT_HEXAGON_TOOLS_ROOT") + .unwrap_or_else(|_| format!("{sdk}/tools/HEXAGON_Tools/19.0.04")); + let qurt_path = env::var("DEFAULT_QURT_PATH") + .unwrap_or_else(|_| format!("{sdk}/rtos/qurt")); + + let arch = "v69"; // match -Ctarget-cpu + let hexlib = PathBuf::from(&tools_root) + .join("Tools/target/hexagon/lib").join(arch).join("G0"); + let qurtlib = PathBuf::from(&qurt_path) + .join(format!("compute{arch}")).join("lib"); + + // CRT startup objects + println!("cargo:rustc-link-arg={}", qurtlib.join("crt1.o").display()); + println!("cargo:rustc-link-arg={}", hexlib.join("crt0.o").display()); + println!("cargo:rustc-link-arg={}", hexlib.join("init.o").display()); + println!("cargo:rustc-link-arg={}", qurtlib.join("debugmon.o").display()); + + // QuRT's ELF loader requires the program's load address to fall within + // the virtual memory pool (starting at page 0x40 = address 0x40000). + println!("cargo:rustc-link-arg=-Wl,--section-start=.start=0x40000"); + + // Stub symbols not available on QuRT + for sym in ["sched_yield", "unsetenv", "_Unwind_Backtrace", "_Unwind_GetIPInfo"] { + println!("cargo:rustc-link-arg=-Wl,--defsym={sym}=abort"); + } + + // Library search paths + println!("cargo:rustc-link-search=native={}", qurtlib.display()); + println!("cargo:rustc-link-search=native={}", hexlib.display()); + + // QuRT system libraries (use --start-group for circular deps) + println!("cargo:rustc-link-arg=-Wl,--start-group"); + for lib in ["qurt", "posix", "qurtcfs", "timer_main", "timer_island"] { + println!("cargo:rustc-link-lib=static={lib}"); + } + + // Exception handling and C runtime + println!("cargo:rustc-link-lib=static=c_eh"); + println!("cargo:rustc-link-lib=static=c"); + println!("cargo:rustc-link-lib=static=qcc"); + println!("cargo:rustc-link-arg=-Wl,--end-group"); + + // CRT finalization + println!("cargo:rustc-link-arg={}", hexlib.join("fini.o").display()); + + // Re-run if SDK path changes + println!("cargo:rerun-if-env-changed=HEXAGON_SDK_ROOT"); + println!("cargo:rerun-if-env-changed=DEFAULT_HEXAGON_TOOLS_ROOT"); + println!("cargo:rerun-if-env-changed=DEFAULT_QURT_PATH"); +} +``` + +### Compiling and linking + +With the `build.rs` above, build with: ```sh -# Build a static executable for QuRT -cargo rustc --target hexagon-unknown-qurt -- \ - -C link-args="-static -nostdlib" \ - -C link-args="-L/opt/Hexagon_SDK/6.3.0.0/rtos/qurt/computev69/lib" \ - -C link-args="-lqurt -lc" +source ${HEXAGON_SDK_ROOT}/setup_sdk_env.source + +cargo build --target hexagon-unknown-qurt \ + -Zbuild-std=core,alloc,std,panic_abort \ + -Zbuild-std-features=restricted-std ``` -This approach is suitable for: -- Standalone QuRT applications -- System-level services -- Boot-time initialization code -- Applications that need deterministic memory layout +Or with `rustc` directly, passing all link flags explicitly (set `HEXLIB` and +`QURTLIB` from the SDK environment as shown in the `build.rs` above): -## User-Loadable Shared Object Targeting +```sh +HEXLIB="${DEFAULT_HEXAGON_TOOLS_ROOT}/Tools/target/hexagon/lib/v69/G0" +QURTLIB="${DEFAULT_QURT_PATH}/computev69/lib" + +rustc program.rs \ + --target hexagon-unknown-qurt \ + --edition 2021 \ + -C linker=hexagon-clang \ + -C panic=abort \ + -C "link-args=-nostdlib" \ + -C "link-args=${QURTLIB}/crt1.o ${HEXLIB}/crt0.o ${HEXLIB}/init.o ${QURTLIB}/debugmon.o" \ + -C "link-args=-Wl,--section-start=.start=0x40000" \ + -C "link-args=-Wl,--defsym=sched_yield=abort" \ + -C "link-args=-Wl,--defsym=unsetenv=abort" \ + -C "link-args=-Wl,--defsym=_Unwind_Backtrace=abort" \ + -C "link-args=-Wl,--defsym=_Unwind_GetIPInfo=abort" \ + -C "link-args=-L${QURTLIB} -L${HEXLIB}" \ + -C "link-args=-Wl,--start-group" \ + -C "link-args=-lqurt -lposix -lqurtcfs -ltimer_main -ltimer_island" \ + -C "link-args=${HEXLIB}/libc_eh.a -lc -lqcc" \ + -C "link-args=-Wl,--end-group" \ + -C "link-args=${HEXLIB}/fini.o" \ + -o program +``` -For shared libraries that can be dynamically loaded by QuRT applications: +The above use hexagon-clang/ld.qcld, but an alternative linker is available: +- [eld](https://github.com/qualcomm/eld), which is provided with both + [the opensource hexagon toolchain](https://github.com/quic/toolchain_for_hexagon) + and the Hexagon SDK + +## Testing + +Programs can be tested using `qemu-system-hexagon` from the Hexagon SDK. + +### Running a static executable on QEMU + +For programs linked as static executables (as shown in the linking examples +above), pass the program directly to `runelf.pbn`: ```sh -# Build a shared object for QuRT -cargo rustc --target hexagon-unknown-qurt \ - --crate-type=cdylib -- \ - -C link-args="-shared -fPIC" \ - -C link-args="-L/opt/Hexagon_SDK/6.3.0.0/rtos/qurt/computev69/lib" +${HEXAGON_SDK_ROOT}/tools/Tools/QEMUHexagon/bin/qemu-system-hexagon \ + -machine V69NA_1024 \ + -kernel ${DEFAULT_QURT_PATH}/computev69/sdksim_bin/runelf.pbn \ + -append "/path/to/program" ``` -This approach is suitable for: -- Plugin architectures -- Runtime-loadable modules -- Libraries shared between multiple applications -- Code that needs to be updated without system restart +The QuRT boot loader (`runelf.pbn`) is passed as `-kernel` and it loads the +user program specified via `-append`. No configuration files or cosim plugins +are needed — the machine model includes timer and interrupt controller +emulation. -## Configuration Options +### Running a shared object on QEMU -The target can be customized for different use cases: +The Hexagon SDK provides `run_main_on_hexagon_sim`, a QuRT program that +dynamically loads a user shared object and calls its `main()`. This is the +standard approach used by the SDK's build system for running tests. -### For Static Images -```toml -# In .cargo/config.toml -[target.hexagon-unknown-qurt] -rustflags = [ - "-C", "link-args=-static", - "-C", "link-args=-nostdlib", - "-C", "target-feature=-small-data" -] +First, build the Rust program as a shared object: + +```sh +rustc program.rs \ + --target hexagon-unknown-qurt \ + --edition 2021 \ + --crate-type cdylib \ + -C linker=hexagon-clang \ + -C panic=abort \ + -o libprogram.so ``` -### For Shared Objects -```toml -# In .cargo/config.toml -[target.hexagon-unknown-qurt] -rustflags = [ - "-C", "link-args=-shared", - "-C", "link-args=-fPIC", - "-C", "relocation-model=pic" -] +Then run it using `run_main_on_hexagon_sim`: + +```sh +RUN_MAIN="${HEXAGON_SDK_ROOT}/libs/run_main_on_hexagon/ship/hexagon_toolv19_v69/run_main_on_hexagon_sim" + +${HEXAGON_SDK_ROOT}/tools/Tools/QEMUHexagon/bin/qemu-system-hexagon \ + -machine V69NA_1024 \ + -kernel ${DEFAULT_QURT_PATH}/computev69/sdksim_bin/runelf.pbn \ + -append "${RUN_MAIN} -- libprogram.so" ``` -## Testing +Arguments after the `.so` filename are passed as `argc`/`argv` to `main()`: + +```sh + -append "${RUN_MAIN} -- libprogram.so arg1 arg2" +``` + +The `run_main_on_hexagon_sim` approach is useful for: +- Programs that need to be loaded dynamically (plugin architectures) +- Matching the SDK's standard test workflow +- Testing shared libraries built with `--crate-type cdylib` + +## Qualcomm Hexagon Libraries (QHL) + +The Hexagon SDK includes optimized math, BLAS, and DSP libraries that can be +called from Rust via `extern "C"` declarations: + +- **qhmath** — scalar and array math: `qhmath_sin_f`, `qhmath_cos_f`, + `qhmath_sqrt_f`, `qhmath_exp_f`, `qhmath_sigmoid_f`, etc. +- **qhblas** — BLAS operations: `qhblas_vector_add_af`, + `qhblas_f_vector_dot_af`, `qhblas_vector_scaling_af`, etc. +- **qhblas_hvx** — HVX-accelerated BLAS: `qhblas_hvx_vector_add_af`, + `qhblas_hvx_f_vector_dot_af`, `qhblas_hvx_vector_hadamard_af`, etc. +- **qhmath_hvx** — HVX-accelerated math: `qhmath_hvx_sin_af`, + `qhmath_hvx_cos_af`, `qhmath_hvx_sqrt_af` +- **qhdsp** — signal processing: `qhdsp_crc32_poly`, FFT, FIR/IIR filters + +To link QHL libraries, add these paths and libraries (in `build.rs` or as +`-C link-args`): + +```rust,ignore (snippet-missing-imports-and-context) +// In build.rs, inside the hexagon-unknown-qurt block: +let qhl = PathBuf::from(&sdk).join("libs/qhl/prebuilt/hexagon_toolv19_v69"); +let qhl_hvx = PathBuf::from(&sdk).join("libs/qhl_hvx/prebuilt/hexagon_toolv19_v69"); +println!("cargo:rustc-link-search=native={}", qhl.display()); +println!("cargo:rustc-link-search=native={}", qhl_hvx.display()); +for lib in ["qhmath", "qhblas", "qhdsp", "qhcomplex", + "qhmath_hvx", "qhblas_hvx", "qhdsp_hvx"] { + println!("cargo:rustc-link-lib=static={lib}"); +} +``` -Since `hexagon-unknown-qurt` requires the QuRT runtime environment, testing requires -either: -- Hexagon hardware with QuRT -- `hexagon-sim` -- QEMU (`qemu-system-hexagon`) +Example Rust usage: + +```rust,ignore (requires-qhl-libraries-to-link) +extern "C" { + fn qhmath_sqrt_f(x: f32) -> f32; + fn qhblas_hvx_vector_add_af( + i1: *const f32, i2: *const f32, out: *mut f32, size: u32, + ) -> i32; +} + +unsafe { + let sqrt4 = qhmath_sqrt_f(4.0); // 2.0 + let a = [1.0f32, 2.0, 3.0, 4.0]; + let b = [10.0f32, 20.0, 30.0, 40.0]; + let mut c = [0.0f32; 4]; + qhblas_hvx_vector_add_af(a.as_ptr(), b.as_ptr(), c.as_mut_ptr(), 4); + // c ≈ [11.0, 22.0, 33.0, 44.0] (HVX float has ~1e-5 precision) +} +``` + +## Working `std` functionality + +The following `std` features are expected to work: + +- **Heap allocation**: `Vec`, `String`, `Box`, `HashMap`, `BTreeMap`, `VecDeque`, + `Rc`, `Arc` +- **Formatting/IO**: `println!`, `eprintln!`, `format!`, `write!`, + `stdout().write_all()`, `stderr().write_all()` +- **Synchronization**: `Mutex`, `RwLock`, `Condvar`, `Once`, `OnceLock`, + `AtomicI32`, `AtomicU32`, `AtomicBool` (max atomic width is 32 bits) +- **Threading**: `thread::spawn`, `thread::Builder` (set stack size), + `thread::sleep`, `thread_local!`, `thread::current().id()` +- **Time**: `Instant::now()`, `SystemTime::now()`, `Duration` arithmetic +- **File I/O**: `File::create`, `File::open`, `fs::remove_file` +- **Environment**: `env::current_dir()`, `env::temp_dir()`, `env::var()` + (read-only) +- **Error handling**: `Result`, `Option` combinators +- **HVX SIMD**: `core::arch::hexagon` intrinsics (128-byte vectors via + `#![feature(stdarch_hexagon)]`) + +## Known limitations + +- **`panic=unwind` not functional at runtime**: The target compiles with + `panic=unwind` but panics abort instead of unwinding. Use `-C panic=abort`. +- **No process spawning**: `Command` / `process::exit` are not available +- **No networking**: Socket APIs are not supported +- **32-bit atomics maximum**: Use `AtomicU32`/`AtomicI32`, not + `AtomicU64`/`AtomicUsize` on this 32-bit target +- **Thread stack size**: QuRT's default heap is limited (~512 KB); use + `thread::Builder::new().stack_size(8192)` or similar small values to + avoid out-of-memory failures +- **Environment variables**: `env::set_var` and `env::remove_var` are not + functional; `env::var` works for reading pre-set variables +- **File I/O quirks**: QuRT's CFS (cosim filesystem) has known issues: + `write()` may report one extra byte written, `read()` may return 0 bytes + in the emulator, and `stat()` is not supported +- **`thread::yield_now()`**: Calls `sched_yield` which is stubbed to `abort`; + use `thread::sleep(Duration::from_millis(0))` as an alternative +- **`_Unwind_Backtrace`**: Stubbed to `abort`; backtraces are not available ## Cross-compilation toolchains and C code -This target requires the proprietary [Hexagon SDK toolchain for C interoperability](https://softwarecenter.qualcomm.com/catalog/item/Hexagon_SDK): +This target requires the [Hexagon SDK](https://softwarecenter.qualcomm.com/catalog/item/Hexagon_SDK) +for C interoperability: -- **Sample SDK Path**: `/opt/Hexagon_SDK/6.3.0.0/` -- **Toolchain**: Use `hexagon-clang` from the Hexagon SDK -- **Libraries**: Link against QuRT system libraries as needed +- **Compiler**: `hexagon-clang` / `hexagon-clang++` +- **QuRT libraries**: `${DEFAULT_QURT_PATH}/computev69/lib/` +- **Hex tools libraries**: `${DEFAULT_HEXAGON_TOOLS_ROOT}/Tools/target/hexagon/lib/v69/G0/` +- **QHL libraries**: `${HEXAGON_SDK_ROOT}/libs/qhl/prebuilt/hexagon_toolv19_v69/` -### C Interoperability Example +### Simple C Interoperability Example ```rust -// lib.rs -#![no_std] -extern crate std; +#![feature(restricted_std)] #[unsafe(no_mangle)] -pub extern "C" fn rust_function() -> i32 { - // Your Rust code here - 42 +pub extern "C" fn rust_add(a: i32, b: i32) -> i32 { + a + b } fn main() { - // Example usage - let result = rust_function(); - assert_eq!(result, 42); + let result = rust_add(2, 3); + println!("result = {result}"); } ``` ```c -// wrapper.c -extern int rust_function(void); +// call_from_c.c +extern int rust_add(int a, int b); -int main() { - return rust_function(); +int use_rust(void) { + return rust_add(2, 3); } ``` - -The target supports both static linking for standalone applications and dynamic -linking for modular architectures, making it flexible for various QuRT -deployment scenarios. From dafb237ab2ca02263c3236d4ddde49574f2d758d Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 24 May 2026 10:37:41 -0700 Subject: [PATCH 03/13] fixup! std: add platform support for hexagon-unknown-qurt Remove spurious #[allow(unused_imports)] added before `use super::platform::fs::MetadataExt as _` in os/unix/fs.rs. This import is used and the annotation is not needed. --- library/std/src/os/unix/fs.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 1bd3948c014d6..c119912c3b022 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -7,7 +7,6 @@ #[allow(unused_imports)] use io::{Read, Write}; -#[allow(unused_imports)] use super::platform::fs::MetadataExt as _; // Used for `File::read` on intra-doc links use crate::ffi::OsStr; From fc47aa4b19cbb930faeaee3e705344442c13e9f6 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 24 May 2026 10:37:50 -0700 Subject: [PATCH 04/13] fixup! std: add platform support for hexagon-unknown-qurt Remove #[cfg(not(target_os = "qurt"))] guard on getppid() in sys/process/unix/common.rs. QuRT's libc provides getpid/getppid, so no special-casing is needed. --- library/std/src/sys/process/unix/common.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs index 021cee76caa01..8215b196127ac 100644 --- a/library/std/src/sys/process/unix/common.rs +++ b/library/std/src/sys/process/unix/common.rs @@ -688,7 +688,6 @@ pub fn getpid() -> u32 { unsafe { libc::getpid() as u32 } } -#[cfg(not(target_os = "qurt"))] pub fn getppid() -> u32 { unsafe { libc::getppid() as u32 } } From b8c0a9341f9d0321f0e7b8acfe27aff1273f3ad6 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 24 May 2026 10:37:57 -0700 Subject: [PATCH 05/13] fixup! std: add platform support for hexagon-unknown-qurt Remove target_os = "qurt" from the libunwind branch in library/unwind/src/lib.rs. QuRT's _Unwind_* symbols are provided by libc_eh (linked via build.rs), not by Rust's in-tree libunwind. panic_unwind for qurt falls through to dummy.rs which aborts, so no libunwind symbols are needed from this crate. --- library/unwind/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 174ef0903cc85..cb4a3593c51d6 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -30,7 +30,6 @@ cfg_select! { unix, windows, target_os = "psp", - target_os = "qurt", target_os = "solid_asp3", all(target_vendor = "fortanix", target_env = "sgx"), all(target_os = "wasi", panic = "unwind"), From 00be71bf4b89b29da2edcaf1ed28c83e93b016a9 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 24 May 2026 10:38:05 -0700 Subject: [PATCH 06/13] fixup! std: add platform support for hexagon-unknown-qurt Move qurt's set_name no-op from thread/unix.rs into thread/mod.rs by adding target_os = "qurt" to the cfg lists that select unsupported::set_name. This is the canonical pattern used by other targets (newlib, l4re, wasi, etc.) that don't support thread naming, rather than adding a per-OS stub function in unix.rs. --- library/std/src/sys/thread/mod.rs | 2 ++ library/std/src/sys/thread/unix.rs | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs index e6bdfbd4d3c2f..bd45fb1391234 100644 --- a/library/std/src/sys/thread/mod.rs +++ b/library/std/src/sys/thread/mod.rs @@ -59,6 +59,7 @@ cfg_select! { target_os = "hurd", target_os = "aix", target_os = "wasi", + target_os = "qurt", )))] pub use unix::set_name; #[cfg(any( @@ -85,6 +86,7 @@ cfg_select! { target_os = "hurd", target_os = "aix", target_os = "wasi", + target_os = "qurt", ))] pub use unsupported::set_name; } diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index 9123a34b79efb..66fb56358898f 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -532,11 +532,6 @@ pub fn set_name(name: &CStr) { debug_assert_eq!(res, libc::OK); } -#[cfg(target_os = "qurt")] -pub fn set_name(_name: &CStr) { - // QuRT doesn't support pthread_setname_np -} - #[cfg(not(target_os = "espidf"))] pub fn sleep(dur: Duration) { cfg_select! { @@ -783,8 +778,13 @@ pub fn sleep_until(deadline: crate::time::Instant) { } pub fn yield_now() { - let ret = unsafe { libc::sched_yield() }; - debug_assert_eq!(ret, 0); + #[cfg(not(target_os = "qurt"))] + { + let ret = unsafe { libc::sched_yield() }; + debug_assert_eq!(ret, 0); + } + #[cfg(target_os = "qurt")] + sleep(Duration::ZERO); } #[cfg(any(target_os = "android", target_os = "linux"))] From 36dfd0a67cbec3fb1c3c9a45626a69034986da54 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 24 May 2026 10:38:12 -0700 Subject: [PATCH 07/13] fixup! std: add platform support for hexagon-unknown-qurt Make unsetenv panic for qurt rather than calling libc::unsetenv, which is not available. This causes std::env::remove_var to panic on qurt, which is the correct behaviour for an unsupported operation. The linker stub --defsym=unsetenv=abort is no longer needed. --- library/std/src/sys/env/unix.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/std/src/sys/env/unix.rs b/library/std/src/sys/env/unix.rs index a319cdae6d537..967ea670f8fbe 100644 --- a/library/std/src/sys/env/unix.rs +++ b/library/std/src/sys/env/unix.rs @@ -138,9 +138,15 @@ pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { }) } +#[cfg(not(target_os = "qurt"))] pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { run_with_cstr(n.as_bytes(), &|nbuf| { let _guard = ENV_LOCK.write(); cvt(unsafe { libc::unsetenv(nbuf.as_ptr()) }).map(drop) }) } + +#[cfg(target_os = "qurt")] +pub unsafe fn unsetenv(_n: &OsStr) -> io::Result<()> { + panic!("remove_var is not supported on this platform") +} From a14adb9c6f8ab4708e62b688c6bf550d89f54fde Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 24 May 2026 10:38:18 -0700 Subject: [PATCH 08/13] fixup! std: add platform support for hexagon-unknown-qurt Remove qurt exclusions from AsRawFd impls for Stdin/Stdout/Stderr and their lock types in os/fd/raw.rs. QuRT's libc defines STDIN_FILENO, STDOUT_FILENO and STDERR_FILENO, and stdio is functional on this platform, so these impls should be available. --- library/std/src/os/fd/raw.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 97ccc21ef4b55..1f8c025ea26e3 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -195,7 +195,7 @@ impl IntoRawFd for fs::File { } #[stable(feature = "asraw_stdio", since = "1.21.0")] -#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] +#[cfg(not(target_os = "trusty"))] impl AsRawFd for io::Stdin { #[inline] fn as_raw_fd(&self) -> RawFd { @@ -204,7 +204,6 @@ impl AsRawFd for io::Stdin { } #[stable(feature = "asraw_stdio", since = "1.21.0")] -#[cfg(not(target_os = "qurt"))] impl AsRawFd for io::Stdout { #[inline] fn as_raw_fd(&self) -> RawFd { @@ -213,7 +212,6 @@ impl AsRawFd for io::Stdout { } #[stable(feature = "asraw_stdio", since = "1.21.0")] -#[cfg(not(target_os = "qurt"))] impl AsRawFd for io::Stderr { #[inline] fn as_raw_fd(&self) -> RawFd { @@ -222,7 +220,7 @@ impl AsRawFd for io::Stderr { } #[stable(feature = "asraw_stdio_locks", since = "1.35.0")] -#[cfg(not(any(target_os = "trusty", target_os = "qurt")))] +#[cfg(not(target_os = "trusty"))] impl<'a> AsRawFd for io::StdinLock<'a> { #[inline] fn as_raw_fd(&self) -> RawFd { @@ -231,7 +229,6 @@ impl<'a> AsRawFd for io::StdinLock<'a> { } #[stable(feature = "asraw_stdio_locks", since = "1.35.0")] -#[cfg(not(target_os = "qurt"))] impl<'a> AsRawFd for io::StdoutLock<'a> { #[inline] fn as_raw_fd(&self) -> RawFd { @@ -240,7 +237,6 @@ impl<'a> AsRawFd for io::StdoutLock<'a> { } #[stable(feature = "asraw_stdio_locks", since = "1.35.0")] -#[cfg(not(target_os = "qurt"))] impl<'a> AsRawFd for io::StderrLock<'a> { #[inline] fn as_raw_fd(&self) -> RawFd { From 6d0ab7a0a8f5065ee443c87afe8b3913b6a80546 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 24 May 2026 10:38:27 -0700 Subject: [PATCH 09/13] fixup! std: add platform support for hexagon-unknown-qurt Gate the no-op args::init in sys/args/unsupported.rs with #[cfg(target_os = "qurt")]. Without this, all other targets using the unsupported args module would see an unused function warning. Only qurt needs it there because it uses the unix PAL (which calls args::init) but is not in the unix family and so falls through to the unsupported args module. --- library/std/src/sys/args/unsupported.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/args/unsupported.rs b/library/std/src/sys/args/unsupported.rs index ba63d04731d00..2eda5ea08e10e 100644 --- a/library/std/src/sys/args/unsupported.rs +++ b/library/std/src/sys/args/unsupported.rs @@ -3,8 +3,9 @@ use crate::fmt; pub struct Args {} +#[cfg(target_os = "qurt")] pub unsafe fn init(_argc: isize, _argv: *const *const u8) { - // No-op for unsupported platforms + // No-op: QuRT initializes args through the unix PAL but has no args to process } pub fn args() -> Args { From 8f841cef41b6a06886f1b2388141b24c127dd069 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 24 May 2026 10:38:34 -0700 Subject: [PATCH 10/13] fixup! std: add platform support for hexagon-unknown-qurt Change #[allow(unused_mut)] to #[expect(unused_mut)] for the set_permissions_nofollow options binding, so the compiler will warn if the attribute becomes unnecessary in the future. --- library/std/src/sys/fs/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index d835dc4ad53ea..3c08af31267f1 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -129,7 +129,7 @@ pub fn set_permissions(path: &Path, perm: FilePermissions) -> io::Result<()> { pub fn set_permissions_nofollow(path: &Path, perm: crate::fs::Permissions) -> io::Result<()> { use crate::fs::OpenOptions; - #[cfg_attr(any(target_os = "espidf", target_os = "horizon"), allow(unused_mut))] + #[cfg_attr(any(target_os = "espidf", target_os = "horizon"), expect(unused_mut))] let mut options = OpenOptions::new(); // ESP-IDF and Horizon do not support O_NOFOLLOW, so we skip setting it. From 457cbd1bcb04df90347b839dae3879e4acc72b92 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 24 May 2026 10:38:50 -0700 Subject: [PATCH 11/13] fixup! std: add platform support for hexagon-unknown-qurt Remove as_raw_stat() from qurt's MetadataExt trait and its raw::stat struct definition. as_raw_stat() has been deprecated since 1.8.0 in favour of the individual accessor methods; adding it to a brand-new platform only to immediately deprecate it is unnecessary. This follows the pattern of newer platforms like AIX that only expose the metadata_ext2 accessors. --- library/std/src/os/qurt/fs.rs | 15 --------------- library/std/src/os/qurt/raw.rs | 28 ---------------------------- 2 files changed, 43 deletions(-) diff --git a/library/std/src/os/qurt/fs.rs b/library/std/src/os/qurt/fs.rs index e7bc270e55bea..5a9316bff0d57 100644 --- a/library/std/src/os/qurt/fs.rs +++ b/library/std/src/os/qurt/fs.rs @@ -8,8 +8,6 @@ #![stable(feature = "metadata_ext", since = "1.1.0")] use crate::fs::Metadata; -#[allow(deprecated)] -use crate::os::qurt::raw; use crate::sys::AsInner; /// OS-specific extensions to [`fs::Metadata`]. @@ -23,15 +21,6 @@ use crate::sys::AsInner; /// - `st_atime_nsec`, `st_mtime_nsec`, `st_ctime_nsec`: QuRT only has second-level precision (returns 0) #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[deprecated( - since = "1.8.0", - note = "deprecated in favor of the accessor \ - methods of this trait" - )] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_dev(&self) -> u64; #[stable(feature = "metadata_ext2", since = "1.8.0")] @@ -75,10 +64,6 @@ pub trait MetadataExt { #[stable(feature = "metadata_ext", since = "1.1.0")] impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } - } fn st_dev(&self) -> u64 { self.as_inner().as_inner().st_dev as u64 } diff --git a/library/std/src/os/qurt/raw.rs b/library/std/src/os/qurt/raw.rs index 0b91767080bf1..1faf42c003443 100644 --- a/library/std/src/os/qurt/raw.rs +++ b/library/std/src/os/qurt/raw.rs @@ -20,31 +20,3 @@ pub type time_t = c_long; // Threading types for QuRT pthread support #[stable(feature = "raw_ext", since = "1.1.0")] pub type pthread_t = libc::pthread_t; - -/// Matches the layout of `libc::stat` for QuRT. -/// -/// QuRT has a minimal stat structure without uid/gid, blksize/blocks, -/// or nanosecond timestamp fields. -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: dev_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: ino_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: mode_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: nlink_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: dev_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: off_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: time_t, -} From 474b1f12cd57cda9de336815ce7a1f927e040c89 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 24 May 2026 10:38:59 -0700 Subject: [PATCH 12/13] fixup! Update hexagon-unknown-qurt platform support documentation Update docs to reflect the sys-layer fixes: - remove_var now panics rather than silently failing (unsetenv is not available; the panic happens at the sys layer so no linker stub needed) - yield_now is implemented as sleep(Duration::ZERO); sched_yield linker stub no longer needed; remove the known-limitation entry entirely - Remove the yield_now and unsetenv --defsym stubs from both the build.rs and rustc direct-invocation examples --- .../src/platform-support/hexagon-unknown-qurt.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/doc/rustc/src/platform-support/hexagon-unknown-qurt.md b/src/doc/rustc/src/platform-support/hexagon-unknown-qurt.md index 11c2c8af7fb16..1920d12136452 100644 --- a/src/doc/rustc/src/platform-support/hexagon-unknown-qurt.md +++ b/src/doc/rustc/src/platform-support/hexagon-unknown-qurt.md @@ -124,7 +124,7 @@ fn main() { println!("cargo:rustc-link-arg=-Wl,--section-start=.start=0x40000"); // Stub symbols not available on QuRT - for sym in ["sched_yield", "unsetenv", "_Unwind_Backtrace", "_Unwind_GetIPInfo"] { + for sym in ["_Unwind_Backtrace", "_Unwind_GetIPInfo"] { println!("cargo:rustc-link-arg=-Wl,--defsym={sym}=abort"); } @@ -181,8 +181,6 @@ rustc program.rs \ -C "link-args=-nostdlib" \ -C "link-args=${QURTLIB}/crt1.o ${HEXLIB}/crt0.o ${HEXLIB}/init.o ${QURTLIB}/debugmon.o" \ -C "link-args=-Wl,--section-start=.start=0x40000" \ - -C "link-args=-Wl,--defsym=sched_yield=abort" \ - -C "link-args=-Wl,--defsym=unsetenv=abort" \ -C "link-args=-Wl,--defsym=_Unwind_Backtrace=abort" \ -C "link-args=-Wl,--defsym=_Unwind_GetIPInfo=abort" \ -C "link-args=-L${QURTLIB} -L${HEXLIB}" \ @@ -341,13 +339,12 @@ The following `std` features are expected to work: - **Thread stack size**: QuRT's default heap is limited (~512 KB); use `thread::Builder::new().stack_size(8192)` or similar small values to avoid out-of-memory failures -- **Environment variables**: `env::set_var` and `env::remove_var` are not - functional; `env::var` works for reading pre-set variables +- **Environment variables**: `env::set_var` is not functional; `env::var` works + for reading pre-set variables; `env::remove_var` panics - **File I/O quirks**: QuRT's CFS (cosim filesystem) has known issues: `write()` may report one extra byte written, `read()` may return 0 bytes in the emulator, and `stat()` is not supported -- **`thread::yield_now()`**: Calls `sched_yield` which is stubbed to `abort`; - use `thread::sleep(Duration::from_millis(0))` as an alternative + - **`_Unwind_Backtrace`**: Stubbed to `abort`; backtraces are not available ## Cross-compilation toolchains and C code From d6050894833e6ecbb9d8ed99465c04a7712d5a1d Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 7 Jul 2026 21:19:27 -0700 Subject: [PATCH 13/13] fixup! std: add platform support for hexagon-unknown-qurt Fix compilation after rebase: - ffi.rs: migrate sealed traits to pub impl(self) syntax - fd/unix.rs: add u8 type parameter to BorrowedCursor - fs/unix.rs: remove redundant cfg guard on lock() methods - unwind/lib.rs: explicitly list qurt for libunwind (no longer in unix family) --- library/std/src/os/qurt/ffi.rs | 5 ++--- library/std/src/sys/fd/unix.rs | 2 +- library/std/src/sys/fs/unix.rs | 12 ------------ library/unwind/src/lib.rs | 1 + 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/library/std/src/os/qurt/ffi.rs b/library/std/src/os/qurt/ffi.rs index 9cca5f3619f3d..dd4c7b6cad235 100644 --- a/library/std/src/os/qurt/ffi.rs +++ b/library/std/src/os/qurt/ffi.rs @@ -6,7 +6,6 @@ use crate::ffi::{OsStr, OsString}; use crate::mem; -use crate::sealed::Sealed; use crate::sys::os_str::Buf; use crate::sys::{AsInner, FromInner, IntoInner}; @@ -14,7 +13,7 @@ use crate::sys::{AsInner, FromInner, IntoInner}; /// /// This trait is sealed: it cannot be implemented outside the standard library. #[stable(feature = "raw_ext", since = "1.1.0")] -pub trait OsStringExt: Sealed { +pub impl(self) trait OsStringExt { /// Creates an [`OsString`] from a byte vector. #[stable(feature = "raw_ext", since = "1.1.0")] fn from_vec(vec: Vec) -> Self; @@ -41,7 +40,7 @@ impl OsStringExt for OsString { /// /// This trait is sealed: it cannot be implemented outside the standard library. #[stable(feature = "raw_ext", since = "1.1.0")] -pub trait OsStrExt: Sealed { +pub impl(self) trait OsStrExt { #[stable(feature = "raw_ext", since = "1.1.0")] /// Creates an [`OsStr`] from a byte slice. fn from_bytes(slice: &[u8]) -> &Self; diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index 0920ba8406f54..4e93ab56bdb83 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -225,7 +225,7 @@ impl FileDesc { } #[cfg(target_os = "qurt")] - pub fn read_buf_at(&self, _cursor: BorrowedCursor<'_>, _offset: u64) -> io::Result<()> { + pub fn read_buf_at(&self, _cursor: BorrowedCursor<'_, u8>, _offset: u64) -> io::Result<()> { Err(io::const_error!(io::ErrorKind::Unsupported, "pread not supported on QuRT")) } diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 7fa06c0e31352..fb1225c5b21fa 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1508,18 +1508,6 @@ impl File { Err(io::const_error!(io::ErrorKind::Unsupported, "datasync not supported on QuRT")) } - #[cfg(any( - target_os = "freebsd", - target_os = "fuchsia", - target_os = "hurd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "cygwin", - target_os = "illumos", - target_os = "aix", - target_vendor = "apple", - ))] pub fn lock(&self) -> io::Result<()> { cfg_select! { any( diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index cb4a3593c51d6..0018e857fb7f3 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -31,6 +31,7 @@ cfg_select! { windows, target_os = "psp", target_os = "solid_asp3", + target_os = "qurt", all(target_vendor = "fortanix", target_env = "sgx"), all(target_os = "wasi", panic = "unwind"), ) => {