Skip to content

Commit c3605f8

Browse files
committed
Auto merge of rust-lang#95897 - AzureMarker:feature/horizon-std, r=nagisa
STD support for the Nintendo 3DS Rustc already supports compiling for the Nintendo 3DS using the `armv6k-nintendo-3ds` target (Tier 3). Until now though, only `core` and `alloc` were supported. This PR adds standard library support for the Nintendo 3DS. A notable exclusion is `std::thread` support, which will come in a follow-up PR as it requires more complicated changes. This has been a joint effort by `@Meziu,` `@ian-h-chamberlain,` myself, and prior work by `@rust3ds` members. ### Background The Nintendo 3DS (Horizon OS) is a mostly-UNIX looking system, with the caveat that it does not come with a full libc implementation out of the box. On the homebrew side (I'm not under NDA), the libc interface is partially implemented by the [devkitPro](https://devkitpro.org/wiki/devkitPro_pacman) toolchain and a user library like [`libctru`](https://github.com/devkitPro/libctru). This is important because there are [some possible legal barriers](rust-lang#88529 (comment)) to linking directly to a library that uses the underlying platform APIs, since they might be considered a trade secret or under NDA. To get around this, the standard library impl for the 3DS does not directly depend on any platform-level APIs. Instead, it expects standard libc functions to be linked in. The implementation of these libc functions is left to the user. Some functions are provided by the devkitPro toolchain, but in our testing, we used the following to fill in the other functions: - [`libctru`] - provides more basic APIs, such as `nanosleep`. Linked in by way of [`ctru-sys`](https://github.com/Meziu/ctru-rs/tree/master/ctru-sys). - [`pthread-3ds`](https://github.com/Meziu/pthread-3ds) - provides pthread APIs for `std::thread`. Implemented using [`libctru`]. - [`linker-fix-3ds`](https://github.com/Meziu/rust-linker-fix-3ds) - fulfills some other missing libc APIs. Implemented using [`libctru`]. For more details, see the `src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md` file added in this PR. ### Notes We've already upstreamed changes to the [`libc`] crate to support this PR, as well as the upcoming threading PR. These changes have all been released as of 0.2.121, so we bump the crate version in this PR. Edit: After some rebases, the version bump has already been merged so it doesn't appear in this PR. A lot of the changes in this PR are straightforward, and follow in the footsteps of the ESP-IDF target: rust-lang#87666. The 3DS does not support user space process spawning, so these APIs are unimplemented (similar to ESP-IDF). [`libctru`]: https://github.com/devkitPro/libctru [`libc`]: https://github.com/rust-lang/libc
2 parents a4cec97 + c814f84 commit c3605f8

27 files changed

+437
-89
lines changed

compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ pub fn target() -> Target {
3737
pre_link_args,
3838
exe_suffix: ".elf".into(),
3939
no_default_libraries: false,
40-
has_thread_local: true,
40+
// There are some issues in debug builds with this enabled in certain programs.
41+
has_thread_local: false,
4142
..Default::default()
4243
},
4344
}

library/core/src/ffi/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ mod c_char_definition {
143143
target_arch = "powerpc"
144144
)
145145
),
146-
all(target_os = "fuchsia", target_arch = "aarch64")
146+
all(target_os = "fuchsia", target_arch = "aarch64"),
147+
target_os = "horizon"
147148
))] {
148149
pub type c_char = u8;
149150
pub type NonZero_c_char = crate::num::NonZeroU8;

library/std/build.rs

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ fn main() {
2929
|| target.contains("asmjs")
3030
|| target.contains("espidf")
3131
|| target.contains("solid")
32+
|| target.contains("nintendo-3ds")
3233
{
3334
// These platforms don't have any special requirements.
3435
} else {

library/std/src/os/horizon/fs.rs

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#![stable(feature = "metadata_ext", since = "1.1.0")]
2+
3+
use crate::fs::Metadata;
4+
use crate::sys_common::AsInner;
5+
6+
/// OS-specific extensions to [`fs::Metadata`].
7+
///
8+
/// [`fs::Metadata`]: crate::fs::Metadata
9+
#[stable(feature = "metadata_ext", since = "1.1.0")]
10+
pub trait MetadataExt {
11+
#[stable(feature = "metadata_ext2", since = "1.8.0")]
12+
fn st_dev(&self) -> u64;
13+
#[stable(feature = "metadata_ext2", since = "1.8.0")]
14+
fn st_ino(&self) -> u64;
15+
#[stable(feature = "metadata_ext2", since = "1.8.0")]
16+
fn st_mode(&self) -> u32;
17+
#[stable(feature = "metadata_ext2", since = "1.8.0")]
18+
fn st_nlink(&self) -> u64;
19+
#[stable(feature = "metadata_ext2", since = "1.8.0")]
20+
fn st_uid(&self) -> u32;
21+
#[stable(feature = "metadata_ext2", since = "1.8.0")]
22+
fn st_gid(&self) -> u32;
23+
#[stable(feature = "metadata_ext2", since = "1.8.0")]
24+
fn st_rdev(&self) -> u64;
25+
#[stable(feature = "metadata_ext2", since = "1.8.0")]
26+
fn st_size(&self) -> u64;
27+
#[stable(feature = "metadata_ext2", since = "1.8.0")]
28+
fn st_atime(&self) -> i64;
29+
#[stable(feature = "metadata_ext2", since = "1.8.0")]
30+
fn st_atime_nsec(&self) -> i64;
31+
#[stable(feature = "metadata_ext2", since = "1.8.0")]
32+
fn st_mtime(&self) -> i64;
33+
#[stable(feature = "metadata_ext2", since = "1.8.0")]
34+
fn st_mtime_nsec(&self) -> i64;
35+
#[stable(feature = "metadata_ext2", since = "1.8.0")]
36+
fn st_ctime(&self) -> i64;
37+
#[stable(feature = "metadata_ext2", since = "1.8.0")]
38+
fn st_ctime_nsec(&self) -> i64;
39+
#[stable(feature = "metadata_ext2", since = "1.8.0")]
40+
fn st_blksize(&self) -> u64;
41+
#[stable(feature = "metadata_ext2", since = "1.8.0")]
42+
fn st_blocks(&self) -> u64;
43+
}
44+
45+
#[stable(feature = "metadata_ext", since = "1.1.0")]
46+
impl MetadataExt for Metadata {
47+
fn st_dev(&self) -> u64 {
48+
self.as_inner().as_inner().st_dev as u64
49+
}
50+
fn st_ino(&self) -> u64 {
51+
self.as_inner().as_inner().st_ino as u64
52+
}
53+
fn st_mode(&self) -> u32 {
54+
self.as_inner().as_inner().st_mode as u32
55+
}
56+
fn st_nlink(&self) -> u64 {
57+
self.as_inner().as_inner().st_nlink as u64
58+
}
59+
fn st_uid(&self) -> u32 {
60+
self.as_inner().as_inner().st_uid as u32
61+
}
62+
fn st_gid(&self) -> u32 {
63+
self.as_inner().as_inner().st_gid as u32
64+
}
65+
fn st_rdev(&self) -> u64 {
66+
self.as_inner().as_inner().st_rdev as u64
67+
}
68+
fn st_size(&self) -> u64 {
69+
self.as_inner().as_inner().st_size as u64
70+
}
71+
fn st_atime(&self) -> i64 {
72+
self.as_inner().as_inner().st_atim.tv_sec
73+
}
74+
fn st_atime_nsec(&self) -> i64 {
75+
self.as_inner().as_inner().st_atim.tv_nsec as i64
76+
}
77+
fn st_mtime(&self) -> i64 {
78+
self.as_inner().as_inner().st_mtim.tv_sec
79+
}
80+
fn st_mtime_nsec(&self) -> i64 {
81+
self.as_inner().as_inner().st_mtim.tv_nsec as i64
82+
}
83+
fn st_ctime(&self) -> i64 {
84+
self.as_inner().as_inner().st_ctim.tv_sec
85+
}
86+
fn st_ctime_nsec(&self) -> i64 {
87+
self.as_inner().as_inner().st_ctim.tv_nsec as i64
88+
}
89+
fn st_blksize(&self) -> u64 {
90+
self.as_inner().as_inner().st_blksize as u64
91+
}
92+
fn st_blocks(&self) -> u64 {
93+
self.as_inner().as_inner().st_blocks as u64
94+
}
95+
}

library/std/src/os/horizon/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//! Definitions for Horizon OS
2+
3+
#![stable(feature = "raw_ext", since = "1.1.0")]
4+
5+
pub mod fs;
6+
pub(crate) mod raw;

library/std/src/os/horizon/raw.rs

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//! Horizon OS raw type definitions
2+
3+
#![stable(feature = "raw_ext", since = "1.1.0")]
4+
#![deprecated(
5+
since = "1.8.0",
6+
note = "these type aliases are no longer supported by \
7+
the standard library, the `libc` crate on \
8+
crates.io should be used instead for the correct \
9+
definitions"
10+
)]
11+
#![allow(deprecated)]
12+
13+
use crate::os::raw::c_long;
14+
use crate::os::unix::raw::{gid_t, uid_t};
15+
16+
#[stable(feature = "pthread_t", since = "1.8.0")]
17+
pub type pthread_t = libc::pthread_t;
18+
19+
#[stable(feature = "raw_ext", since = "1.1.0")]
20+
pub type blkcnt_t = libc::blkcnt_t;
21+
22+
#[stable(feature = "raw_ext", since = "1.1.0")]
23+
pub type blksize_t = libc::blksize_t;
24+
#[stable(feature = "raw_ext", since = "1.1.0")]
25+
pub type dev_t = libc::dev_t;
26+
#[stable(feature = "raw_ext", since = "1.1.0")]
27+
pub type ino_t = libc::ino_t;
28+
#[stable(feature = "raw_ext", since = "1.1.0")]
29+
pub type mode_t = libc::mode_t;
30+
#[stable(feature = "raw_ext", since = "1.1.0")]
31+
pub type nlink_t = libc::nlink_t;
32+
#[stable(feature = "raw_ext", since = "1.1.0")]
33+
pub type off_t = libc::off_t;
34+
35+
#[stable(feature = "raw_ext", since = "1.1.0")]
36+
pub type time_t = libc::time_t;
37+
38+
#[repr(C)]
39+
#[derive(Clone)]
40+
#[stable(feature = "raw_ext", since = "1.1.0")]
41+
pub struct stat {
42+
#[stable(feature = "raw_ext", since = "1.1.0")]
43+
pub st_dev: dev_t,
44+
#[stable(feature = "raw_ext", since = "1.1.0")]
45+
pub st_ino: ino_t,
46+
#[stable(feature = "raw_ext", since = "1.1.0")]
47+
pub st_mode: mode_t,
48+
#[stable(feature = "raw_ext", since = "1.1.0")]
49+
pub st_nlink: nlink_t,
50+
#[stable(feature = "raw_ext", since = "1.1.0")]
51+
pub st_uid: uid_t,
52+
#[stable(feature = "raw_ext", since = "1.1.0")]
53+
pub st_gid: gid_t,
54+
#[stable(feature = "raw_ext", since = "1.1.0")]
55+
pub st_rdev: dev_t,
56+
#[stable(feature = "raw_ext", since = "1.1.0")]
57+
pub st_size: off_t,
58+
#[stable(feature = "raw_ext", since = "1.1.0")]
59+
pub st_atime: time_t,
60+
#[stable(feature = "raw_ext", since = "1.1.0")]
61+
pub st_mtime: time_t,
62+
#[stable(feature = "raw_ext", since = "1.1.0")]
63+
pub st_ctime: time_t,
64+
#[stable(feature = "raw_ext", since = "1.1.0")]
65+
pub st_blksize: blksize_t,
66+
#[stable(feature = "raw_ext", since = "1.1.0")]
67+
pub st_blocks: blkcnt_t,
68+
#[stable(feature = "raw_ext", since = "1.1.0")]
69+
pub st_spare4: [c_long; 2usize],
70+
}

library/std/src/os/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ pub mod freebsd;
123123
pub mod fuchsia;
124124
#[cfg(target_os = "haiku")]
125125
pub mod haiku;
126+
#[cfg(target_os = "horizon")]
127+
pub mod horizon;
126128
#[cfg(target_os = "illumos")]
127129
pub mod illumos;
128130
#[cfg(target_os = "ios")]

library/std/src/os/unix/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ mod platform {
5151
pub use crate::os::fuchsia::*;
5252
#[cfg(target_os = "haiku")]
5353
pub use crate::os::haiku::*;
54+
#[cfg(target_os = "horizon")]
55+
pub use crate::os::horizon::*;
5456
#[cfg(target_os = "illumos")]
5557
pub use crate::os::illumos::*;
5658
#[cfg(target_os = "ios")]

library/std/src/os/unix/process.rs

+16-30
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ use crate::sealed::Sealed;
1212
use crate::sys;
1313
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
1414

15+
#[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))]
16+
type UserId = u32;
17+
#[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))]
18+
type GroupId = u32;
19+
20+
#[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))]
21+
type UserId = u16;
22+
#[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))]
23+
type GroupId = u16;
24+
1525
/// Unix-specific extensions to the [`process::Command`] builder.
1626
///
1727
/// This trait is sealed: it cannot be implemented outside the standard library.
@@ -22,29 +32,17 @@ pub trait CommandExt: Sealed {
2232
/// `setuid` call in the child process. Failure in the `setuid`
2333
/// call will cause the spawn to fail.
2434
#[stable(feature = "rust1", since = "1.0.0")]
25-
fn uid(
26-
&mut self,
27-
#[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
28-
#[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
29-
) -> &mut process::Command;
35+
fn uid(&mut self, id: UserId) -> &mut process::Command;
3036

3137
/// Similar to `uid`, but sets the group ID of the child process. This has
3238
/// the same semantics as the `uid` field.
3339
#[stable(feature = "rust1", since = "1.0.0")]
34-
fn gid(
35-
&mut self,
36-
#[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
37-
#[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
38-
) -> &mut process::Command;
40+
fn gid(&mut self, id: GroupId) -> &mut process::Command;
3941

4042
/// Sets the supplementary group IDs for the calling process. Translates to
4143
/// a `setgroups` call in the child process.
4244
#[unstable(feature = "setgroups", issue = "90747")]
43-
fn groups(
44-
&mut self,
45-
#[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] groups: &[u32],
46-
#[cfg(any(target_os = "vxworks", target_os = "espidf"))] groups: &[u16],
47-
) -> &mut process::Command;
45+
fn groups(&mut self, groups: &[GroupId]) -> &mut process::Command;
4846

4947
/// Schedules a closure to be run just before the `exec` function is
5048
/// invoked.
@@ -158,29 +156,17 @@ pub trait CommandExt: Sealed {
158156

159157
#[stable(feature = "rust1", since = "1.0.0")]
160158
impl CommandExt for process::Command {
161-
fn uid(
162-
&mut self,
163-
#[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
164-
#[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
165-
) -> &mut process::Command {
159+
fn uid(&mut self, id: UserId) -> &mut process::Command {
166160
self.as_inner_mut().uid(id);
167161
self
168162
}
169163

170-
fn gid(
171-
&mut self,
172-
#[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
173-
#[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
174-
) -> &mut process::Command {
164+
fn gid(&mut self, id: GroupId) -> &mut process::Command {
175165
self.as_inner_mut().gid(id);
176166
self
177167
}
178168

179-
fn groups(
180-
&mut self,
181-
#[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] groups: &[u32],
182-
#[cfg(any(target_os = "vxworks", target_os = "espidf"))] groups: &[u16],
183-
) -> &mut process::Command {
169+
fn groups(&mut self, groups: &[GroupId]) -> &mut process::Command {
184170
self.as_inner_mut().groups(groups);
185171
self
186172
}

library/std/src/sys/unix/alloc.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ cfg_if::cfg_if! {
5858
target_os = "illumos",
5959
target_os = "redox",
6060
target_os = "solaris",
61-
target_os = "espidf"
61+
target_os = "espidf",
62+
target_os = "horizon"
6263
))] {
6364
#[inline]
6465
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {

library/std/src/sys/unix/args.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ impl DoubleEndedIterator for Args {
6868
target_os = "l4re",
6969
target_os = "fuchsia",
7070
target_os = "redox",
71-
target_os = "vxworks"
71+
target_os = "vxworks",
72+
target_os = "horizon"
7273
))]
7374
mod imp {
7475
use super::Args;

library/std/src/sys/unix/env.rs

+11
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,17 @@ pub mod os {
119119
pub const EXE_EXTENSION: &str = "";
120120
}
121121

122+
#[cfg(target_os = "horizon")]
123+
pub mod os {
124+
pub const FAMILY: &str = "unix";
125+
pub const OS: &str = "horizon";
126+
pub const DLL_PREFIX: &str = "lib";
127+
pub const DLL_SUFFIX: &str = ".so";
128+
pub const DLL_EXTENSION: &str = "so";
129+
pub const EXE_SUFFIX: &str = ".elf";
130+
pub const EXE_EXTENSION: &str = "elf";
131+
}
132+
122133
#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))]
123134
pub mod os {
124135
pub const FAMILY: &str = "unix";

0 commit comments

Comments
 (0)