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/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 8a39fe073bf95..cc6b07df7fa5a 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -344,7 +344,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<'_> { @@ -353,7 +353,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] @@ -363,7 +363,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 { @@ -374,7 +374,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<'_> { @@ -383,7 +383,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] @@ -393,7 +393,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 { @@ -404,7 +404,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<'_> { @@ -413,7 +413,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] @@ -423,7 +423,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 { @@ -532,7 +532,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() @@ -540,7 +540,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() @@ -548,7 +548,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() @@ -556,7 +556,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() @@ -564,7 +564,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)) @@ -572,7 +572,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 76374402be4b3..c863e592b5d05 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -165,6 +165,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")] @@ -190,6 +192,7 @@ pub mod xous; target_os = "trusty", target_os = "wasi", target_os = "motor", + target_os = "qurt", doc ))] pub mod fd; 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 219b340b92469..6f231520ebfb9 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 18b0f70c06877..c223483392133 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 02fe515ac32c4..1f61e22ece9be 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 c5e8646dada1e..97347e6455c2d 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; } @@ -94,6 +97,7 @@ const fn max_iov() -> usize { target_os = "openbsd", target_os = "horizon", target_os = "vita", + target_os = "qurt", target_vendor = "apple", target_os = "cygwin", )))] @@ -121,6 +125,7 @@ impl FileDesc { #[cfg(not(any( target_os = "espidf", target_os = "horizon", + target_os = "qurt", target_os = "vita", target_os = "nuttx" )))] @@ -138,6 +143,7 @@ impl FileDesc { #[cfg(any( target_os = "espidf", target_os = "horizon", + target_os = "qurt", target_os = "vita", target_os = "nuttx" ))] @@ -150,6 +156,7 @@ impl FileDesc { cfg!(not(any( target_os = "espidf", target_os = "horizon", + target_os = "qurt", target_os = "vita", target_os = "nuttx", target_os = "wasi", @@ -161,6 +168,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( @@ -173,6 +181,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<'_>) -> io::Result<()> { // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes let ret = cvt(unsafe { @@ -190,6 +203,7 @@ impl FileDesc { Ok(()) } + #[cfg(not(target_os = "qurt"))] pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes let ret = cvt(unsafe { @@ -208,6 +222,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 @@ -355,6 +374,7 @@ impl FileDesc { #[cfg(not(any( target_os = "espidf", target_os = "horizon", + target_os = "qurt", target_os = "vita", target_os = "nuttx" )))] @@ -372,6 +392,7 @@ impl FileDesc { #[cfg(any( target_os = "espidf", target_os = "horizon", + target_os = "qurt", target_os = "vita", target_os = "nuttx" ))] @@ -384,12 +405,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")), @@ -415,6 +438,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 @@ -562,6 +590,10 @@ impl FileDesc { target_os = "vxworks", target_os = "nto", target_os = "wasi", + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "qurt", )))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { @@ -597,9 +629,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 9b0ef5539d32b..5ad7b1dabf8d0 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -28,6 +28,7 @@ use libc::fstatat64; target_os = "fuchsia", target_os = "illumos", target_os = "nto", + target_os = "qurt", target_os = "redox", target_os = "solaris", target_os = "vita", @@ -45,6 +46,7 @@ use libc::readdir as readdir64; target_os = "l4re", target_os = "linux", target_os = "nto", + target_os = "qurt", target_os = "redox", target_os = "solaris", target_os = "vita", @@ -66,11 +68,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", @@ -82,7 +91,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")] @@ -98,6 +109,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); @@ -280,6 +292,7 @@ cfg_select! { target_os = "redox", target_os = "espidf", target_os = "horizon", + target_os = "qurt", target_os = "vita", target_os = "nto", target_os = "vxworks", @@ -410,6 +423,7 @@ fn get_path_from_fd(fd: c_int) -> Option { target_os = "illumos", target_os = "linux", target_os = "nto", + target_os = "qurt", target_os = "redox", target_os = "solaris", target_os = "vita", @@ -436,6 +450,7 @@ pub struct DirEntry { target_os = "illumos", target_os = "linux", target_os = "nto", + target_os = "qurt", target_os = "redox", target_os = "solaris", target_os = "vita", @@ -448,6 +463,7 @@ struct dirent64_min { target_os = "illumos", target_os = "aix", target_os = "nto", + target_os = "qurt", target_os = "vita", )))] d_type: u8, @@ -462,6 +478,7 @@ struct dirent64_min { target_os = "illumos", target_os = "linux", target_os = "nto", + target_os = "qurt", target_os = "redox", target_os = "solaris", target_os = "vita", @@ -619,6 +636,7 @@ impl FileAttr { target_os = "horizon", target_os = "vita", target_os = "hurd", + target_os = "qurt", target_os = "rtems", target_os = "nuttx", )))] @@ -636,6 +654,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", ))] @@ -659,6 +678,7 @@ impl FileAttr { target_os = "horizon", target_os = "vita", target_os = "hurd", + target_os = "qurt", target_os = "rtems", target_os = "nuttx", )))] @@ -676,6 +696,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" ))] @@ -854,6 +875,7 @@ impl Iterator for ReadDir { target_os = "illumos", target_os = "linux", target_os = "nto", + target_os = "qurt", target_os = "redox", target_os = "solaris", target_os = "vita", @@ -927,6 +949,7 @@ impl Iterator for ReadDir { target_os = "illumos", target_os = "aix", target_os = "nto", + target_os = "qurt", )))] d_type: (*entry_ptr).d_type as u8, }; @@ -952,6 +975,7 @@ impl Iterator for ReadDir { target_os = "illumos", target_os = "linux", target_os = "nto", + target_os = "qurt", target_os = "redox", target_os = "solaris", target_os = "vita", @@ -997,6 +1021,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; @@ -1015,6 +1040,7 @@ impl Drop for DirStream { miri, target_os = "redox", target_os = "nto", + target_os = "qurt", target_os = "vita", target_os = "hurd", target_os = "espidf", @@ -1103,6 +1129,7 @@ impl DirEntry { target_os = "vxworks", target_os = "aix", target_os = "nto", + target_os = "qurt", target_os = "vita", ))] pub fn file_type(&self) -> io::Result { @@ -1116,6 +1143,7 @@ impl DirEntry { target_os = "vxworks", target_os = "aix", target_os = "nto", + target_os = "qurt", target_os = "vita", )))] pub fn file_type(&self) -> io::Result { @@ -1146,6 +1174,7 @@ impl DirEntry { target_os = "l4re", target_os = "linux", target_os = "nto", + target_os = "qurt", target_os = "redox", target_os = "rtems", target_os = "solaris", @@ -1205,6 +1234,7 @@ impl DirEntry { target_os = "redox", target_os = "aix", target_os = "nto", + target_os = "qurt", target_os = "vita", target_os = "hurd", target_os = "wasi", @@ -1222,6 +1252,7 @@ impl DirEntry { target_os = "redox", target_os = "aix", target_os = "nto", + target_os = "qurt", target_os = "vita", target_os = "hurd", target_os = "wasi", @@ -1388,6 +1419,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(()); @@ -1402,6 +1434,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(()); @@ -1441,6 +1479,11 @@ 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", @@ -1784,16 +1827,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!( @@ -1860,6 +1909,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 { @@ -2096,14 +2146,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(); @@ -2130,12 +2187,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 @@ -2153,14 +2226,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 { @@ -2197,6 +2271,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() { @@ -2209,6 +2284,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; @@ -2223,7 +2303,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, @@ -2302,7 +2382,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, @@ -2313,7 +2393,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, @@ -2461,7 +2541,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) }) @@ -2469,13 +2549,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) }) @@ -2484,23 +2564,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(|_| ()) @@ -2509,11 +2592,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 = "vxworks", @@ -2528,6 +2612,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 = "vxworks", diff --git a/library/std/src/sys/io/error/mod.rs b/library/std/src/sys/io/error/mod.rs index d7a0b9b4b301d..bd7d4d80096a0 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 b10343b2752c2..269e81ac8b5fd 100644 --- a/library/std/src/sys/io/error/unix.rs +++ b/library/std/src/sys/io/error/unix.rs @@ -30,6 +30,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/io_slice/iovec.rs b/library/std/src/sys/io/io_slice/iovec.rs index d549aca250d5f..8dd817f3e779f 100644 --- a/library/std/src/sys/io/io_slice/iovec.rs +++ b/library/std/src/sys/io/io_slice/iovec.rs @@ -1,6 +1,11 @@ #[cfg(target_os = "hermit")] use hermit_abi::iovec; -#[cfg(any(target_family = "unix", target_os = "trusty", target_os = "wasi"))] +#[cfg(any( + target_family = "unix", + target_os = "trusty", + target_os = "wasi", + target_os = "qurt" +))] use libc::iovec; use crate::ffi::c_void; diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs index b3587ab63696a..c0593c7ef0fe3 100644 --- a/library/std/src/sys/io/mod.rs +++ b/library/std/src/sys/io/mod.rs @@ -4,7 +4,14 @@ mod error; mod io_slice { 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", + ) => { mod iovec; pub use iovec::*; } @@ -25,7 +32,7 @@ mod io_slice { 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::*; } @@ -59,6 +66,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 fb18e8dec557c..67bcd3583a913 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 0be150a0bfaa8..4f79dd551ff8b 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -61,6 +61,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; @@ -87,6 +88,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", )))] @@ -133,6 +135,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; @@ -210,6 +213,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) @@ -369,7 +373,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 544d495340db7..c49bdeb6862eb 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()) } @@ -370,7 +373,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() } @@ -429,6 +432,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 { @@ -443,6 +447,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 1c5df47c95817..fb1802ccde143 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 46f4ebf6db421..d84c49e0df984 100644 --- a/library/std/src/sys/process/mod.rs +++ b/library/std/src/sys/process/mod.rs @@ -41,7 +41,7 @@ pub use imp::{ target_os = "espidf", target_os = "horizon", target_os = "vita", - target_os = "nuttx" + target_os = "nuttx", )) ), target_os = "windows", @@ -79,7 +79,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 2d83782b7d0b9..30310c9f97da8 100644 --- a/library/std/src/sys/process/unix/common.rs +++ b/library/std/src/sys/process/unix/common.rs @@ -684,6 +684,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 9ed66a559117c..c10cedcc4675f 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 91f72d0738790..a57845126ce67 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -106,6 +106,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 @@ -122,6 +123,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 ffed376a8e96e..5f1aacf071b8c 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 81ef39581d74d..366720f88dff4 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -421,7 +421,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 { @@ -520,6 +520,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 e88011aa22dad..e8c8947f89e1e 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 f3dbd3d0556ab..46fdb76bb3ce1 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 cce6ca748cccd..0926a608fbf9d 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -31,6 +31,7 @@ cfg_select! { unix, windows, target_os = "psp", + target_os = "qurt", target_os = "solid_asp3", all(target_vendor = "fortanix", target_env = "sgx"), ) => { diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index f785254d90dae..222afe0280116 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -304,6 +304,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}")) 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.