Auto merge of #111819 - nikarh:vita-improved, r=Amanieu
Improved std support for ps vita target Fixed a couple of things in std support for ps vita via Vita SDK newlib oss implementation: - Added missing hardware features to target spec - Compile in thumb by default (newlib is also compiled in thumb) - Fixed fs calls. Vita newlib has a not-very-posix dirent. Also vita does not expose inodes, it's stubbed as 0 in stat, and I'm stubbing it here for dirent (because vita newlibs's dirent doesn't even have that field) - Enabled signal handlers for panic unwinding - Dropped static link requirement from the platform support md. Also, rearranged sections to better stick with the template.
This commit is contained in:
commit
b3dd578767
@ -1902,9 +1902,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.143"
|
||||
version = "0.2.146"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edc207893e85c5d6be840e969b496b53d94cec8be2d501b214f50daa97fa8024"
|
||||
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
@ -1,15 +1,18 @@
|
||||
use crate::abi::Endian;
|
||||
use crate::spec::{cvs, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
|
||||
use crate::spec::{cvs, Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions};
|
||||
|
||||
/// A base target for PlayStation Vita devices using the VITASDK toolchain (using newlib).
|
||||
///
|
||||
/// Requires the VITASDK toolchain on the host system.
|
||||
|
||||
pub fn target() -> Target {
|
||||
let pre_link_args = TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-Wl,-q"]);
|
||||
let pre_link_args = TargetOptions::link_args(
|
||||
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
|
||||
&["-Wl,-q", "-Wl,--pic-veneer"],
|
||||
);
|
||||
|
||||
Target {
|
||||
llvm_target: "armv7a-vita-eabihf".into(),
|
||||
llvm_target: "thumbv7a-vita-eabihf".into(),
|
||||
pointer_width: 32,
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
|
||||
arch: "arm".into(),
|
||||
@ -18,21 +21,19 @@ pub fn target() -> Target {
|
||||
os: "vita".into(),
|
||||
endian: Endian::Little,
|
||||
c_int_width: "32".into(),
|
||||
dynamic_linking: false,
|
||||
env: "newlib".into(),
|
||||
vendor: "sony".into(),
|
||||
abi: "eabihf".into(),
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No),
|
||||
no_default_libraries: false,
|
||||
cpu: "cortex-a9".into(),
|
||||
executables: true,
|
||||
families: cvs!["unix"],
|
||||
linker: Some("arm-vita-eabi-gcc".into()),
|
||||
relocation_model: RelocModel::Static,
|
||||
features: "+v7,+neon".into(),
|
||||
features: "+v7,+neon,+vfp3,+thumb2,+thumb-mode".into(),
|
||||
pre_link_args,
|
||||
exe_suffix: ".elf".into(),
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
has_thumb_interworking: true,
|
||||
max_atomic_width: Some(64),
|
||||
..Default::default()
|
||||
},
|
||||
|
@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
|
||||
panic_unwind = { path = "../panic_unwind", optional = true }
|
||||
panic_abort = { path = "../panic_abort" }
|
||||
core = { path = "../core", public = true }
|
||||
libc = { version = "0.2.143", default-features = false, features = ['rustc-dep-of-std'], public = true }
|
||||
libc = { version = "0.2.146", default-features = false, features = ['rustc-dep-of-std'], public = true }
|
||||
compiler_builtins = { version = "0.1.92" }
|
||||
profiler_builtins = { path = "../profiler_builtins", optional = true }
|
||||
unwind = { path = "../unwind" }
|
||||
|
@ -15,7 +15,7 @@
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))] {
|
||||
if #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon", target_os = "vita"))] {
|
||||
type UserId = u16;
|
||||
type GroupId = u16;
|
||||
} else if #[cfg(target_os = "nto")] {
|
||||
|
@ -402,7 +402,10 @@ pub fn set_cloexec(&self) -> io::Result<()> {
|
||||
}
|
||||
}
|
||||
#[cfg(any(
|
||||
all(target_env = "newlib", not(any(target_os = "espidf", target_os = "horizon"))),
|
||||
all(
|
||||
target_env = "newlib",
|
||||
not(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))
|
||||
),
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "emscripten",
|
||||
@ -424,10 +427,10 @@ pub fn set_cloexec(&self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
#[cfg(any(target_os = "espidf", target_os = "horizon"))]
|
||||
#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))]
|
||||
pub fn set_cloexec(&self) -> io::Result<()> {
|
||||
// FD_CLOEXEC is not supported in ESP-IDF and Horizon OS but there's no need to,
|
||||
// because neither supports spawning processes.
|
||||
// FD_CLOEXEC is not supported in ESP-IDF, Horizon OS and Vita but there's no need to,
|
||||
// because none of them supports spawning processes.
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
target_os = "redox",
|
||||
target_os = "illumos",
|
||||
target_os = "nto",
|
||||
target_os = "vita",
|
||||
))]
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
|
||||
@ -58,6 +59,7 @@
|
||||
target_os = "redox",
|
||||
target_os = "illumos",
|
||||
target_os = "nto",
|
||||
target_os = "vita",
|
||||
))]
|
||||
use libc::readdir as readdir64;
|
||||
#[cfg(target_os = "linux")]
|
||||
@ -74,6 +76,7 @@
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
target_os = "nto",
|
||||
target_os = "vita",
|
||||
)))]
|
||||
use libc::readdir_r as readdir64_r;
|
||||
#[cfg(target_os = "android")]
|
||||
@ -283,6 +286,7 @@ unsafe impl Sync for Dir {}
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
target_os = "nto",
|
||||
target_os = "vita"
|
||||
))]
|
||||
pub struct DirEntry {
|
||||
dir: Arc<InnerReadDir>,
|
||||
@ -304,10 +308,16 @@ pub struct DirEntry {
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
target_os = "nto",
|
||||
target_os = "vita",
|
||||
))]
|
||||
struct dirent64_min {
|
||||
d_ino: u64,
|
||||
#[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "nto")))]
|
||||
#[cfg(not(any(
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "nto",
|
||||
target_os = "vita"
|
||||
)))]
|
||||
d_type: u8,
|
||||
}
|
||||
|
||||
@ -319,6 +329,7 @@ struct dirent64_min {
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
target_os = "nto",
|
||||
target_os = "vita",
|
||||
)))]
|
||||
pub struct DirEntry {
|
||||
dir: Arc<InnerReadDir>,
|
||||
@ -520,6 +531,7 @@ pub fn created(&self) -> io::Result<SystemTime> {
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "watchos",
|
||||
target_os = "vita",
|
||||
)))]
|
||||
pub fn created(&self) -> io::Result<SystemTime> {
|
||||
cfg_has_statx! {
|
||||
@ -541,6 +553,11 @@ pub fn created(&self) -> io::Result<SystemTime> {
|
||||
currently",
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "vita")]
|
||||
pub fn created(&self) -> io::Result<SystemTime> {
|
||||
Ok(SystemTime::new(self.stat.st_ctime as i64, 0))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "nto")]
|
||||
@ -645,6 +662,7 @@ impl Iterator for ReadDir {
|
||||
target_os = "redox",
|
||||
target_os = "illumos",
|
||||
target_os = "nto",
|
||||
target_os = "vita",
|
||||
))]
|
||||
fn next(&mut self) -> Option<io::Result<DirEntry>> {
|
||||
if self.end_of_stream {
|
||||
@ -725,6 +743,7 @@ macro_rules! offset_ptr {
|
||||
continue;
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "vita"))]
|
||||
let entry = dirent64_min {
|
||||
d_ino: *offset_ptr!(entry_ptr, d_ino) as u64,
|
||||
#[cfg(not(any(
|
||||
@ -735,6 +754,9 @@ macro_rules! offset_ptr {
|
||||
d_type: *offset_ptr!(entry_ptr, d_type) as u8,
|
||||
};
|
||||
|
||||
#[cfg(target_os = "vita")]
|
||||
let entry = dirent64_min { d_ino: 0u64 };
|
||||
|
||||
return Some(Ok(DirEntry {
|
||||
entry,
|
||||
name: name.to_owned(),
|
||||
@ -752,6 +774,7 @@ macro_rules! offset_ptr {
|
||||
target_os = "redox",
|
||||
target_os = "illumos",
|
||||
target_os = "nto",
|
||||
target_os = "vita",
|
||||
)))]
|
||||
fn next(&mut self) -> Option<io::Result<DirEntry>> {
|
||||
if self.end_of_stream {
|
||||
@ -842,6 +865,7 @@ pub fn metadata(&self) -> io::Result<FileAttr> {
|
||||
target_os = "haiku",
|
||||
target_os = "vxworks",
|
||||
target_os = "nto",
|
||||
target_os = "vita",
|
||||
))]
|
||||
pub fn file_type(&self) -> io::Result<FileType> {
|
||||
self.metadata().map(|m| m.file_type())
|
||||
@ -853,6 +877,7 @@ pub fn file_type(&self) -> io::Result<FileType> {
|
||||
target_os = "haiku",
|
||||
target_os = "vxworks",
|
||||
target_os = "nto",
|
||||
target_os = "vita",
|
||||
)))]
|
||||
pub fn file_type(&self) -> io::Result<FileType> {
|
||||
match self.entry.d_type {
|
||||
@ -939,6 +964,7 @@ fn name_bytes(&self) -> &[u8] {
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
target_os = "nto",
|
||||
target_os = "vita",
|
||||
)))]
|
||||
fn name_cstr(&self) -> &CStr {
|
||||
unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
|
||||
@ -951,6 +977,7 @@ fn name_cstr(&self) -> &CStr {
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
target_os = "nto",
|
||||
target_os = "vita",
|
||||
))]
|
||||
fn name_cstr(&self) -> &CStr {
|
||||
&self.name
|
||||
@ -1543,7 +1570,7 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> {
|
||||
run_path_with_cstr(original, |original| {
|
||||
run_path_with_cstr(link, |link| {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon"))] {
|
||||
if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita"))] {
|
||||
// VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves
|
||||
// it implementation-defined whether `link` follows symlinks, so rely on the
|
||||
// `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior.
|
||||
@ -1666,6 +1693,8 @@ fn open_to_and_set_permissions(
|
||||
.truncate(true)
|
||||
.open(to)?;
|
||||
let writer_metadata = writer.metadata()?;
|
||||
// fchmod is broken on vita
|
||||
#[cfg(not(target_os = "vita"))]
|
||||
if writer_metadata.is_file() {
|
||||
// Set the correct file permissions, in case the file already existed.
|
||||
// Don't set the permissions on already existing non-files like
|
||||
@ -1844,11 +1873,12 @@ pub fn chroot(dir: &Path) -> io::Result<()> {
|
||||
|
||||
pub use remove_dir_impl::remove_dir_all;
|
||||
|
||||
// Fallback for REDOX, ESP-ID, Horizon, and Miri
|
||||
// Fallback for REDOX, ESP-ID, Horizon, Vita and Miri
|
||||
#[cfg(any(
|
||||
target_os = "redox",
|
||||
target_os = "espidf",
|
||||
target_os = "horizon",
|
||||
target_os = "vita",
|
||||
target_os = "nto",
|
||||
miri
|
||||
))]
|
||||
@ -1861,6 +1891,7 @@ mod remove_dir_impl {
|
||||
target_os = "redox",
|
||||
target_os = "espidf",
|
||||
target_os = "horizon",
|
||||
target_os = "vita",
|
||||
target_os = "nto",
|
||||
miri
|
||||
)))]
|
||||
|
@ -163,12 +163,7 @@ unsafe fn sanitize_standard_fds() {
|
||||
}
|
||||
|
||||
unsafe fn reset_sigpipe(#[allow(unused_variables)] sigpipe: u8) {
|
||||
#[cfg(not(any(
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "horizon",
|
||||
target_os = "vita"
|
||||
)))]
|
||||
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "horizon")))]
|
||||
{
|
||||
// We don't want to add this as a public type to std, nor do we
|
||||
// want to `include!` a file from the compiler (which would break
|
||||
@ -206,7 +201,6 @@ mod sigpipe {
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "horizon",
|
||||
target_os = "vita"
|
||||
)))]
|
||||
static UNIX_SIGPIPE_ATTR_SPECIFIED: crate::sync::atomic::AtomicBool =
|
||||
crate::sync::atomic::AtomicBool::new(false);
|
||||
@ -216,7 +210,6 @@ mod sigpipe {
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "horizon",
|
||||
target_os = "vita",
|
||||
)))]
|
||||
pub(crate) fn unix_sigpipe_attr_specified() -> bool {
|
||||
UNIX_SIGPIPE_ATTR_SPECIFIED.load(crate::sync::atomic::Ordering::Relaxed)
|
||||
@ -407,6 +400,9 @@ pub fn abort_internal() -> ! {
|
||||
} else if #[cfg(all(target_os = "linux", target_env = "uclibc"))] {
|
||||
#[link(name = "dl")]
|
||||
extern "C" {}
|
||||
} else if #[cfg(target_os = "vita")] {
|
||||
#[link(name = "pthread", kind = "static", modifiers = "-bundle")]
|
||||
extern "C" {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,12 +454,18 @@ pub fn passcred(&self) -> io::Result<bool> {
|
||||
Ok(passcred != 0)
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
|
||||
#[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "vita")))]
|
||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
let mut nonblocking = nonblocking as libc::c_int;
|
||||
cvt(unsafe { libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &mut nonblocking) }).map(drop)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "vita")]
|
||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
let option = nonblocking as libc::c_int;
|
||||
setsockopt(self, libc::SOL_SOCKET, libc::SO_NONBLOCK, option)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
|
||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
// FIONBIO is inadequate for sockets on illumos/Solaris, so use the
|
||||
|
@ -123,7 +123,8 @@ pub unsafe fn new_in_place(parker: *mut Parker) {
|
||||
target_os = "watchos",
|
||||
target_os = "l4re",
|
||||
target_os = "android",
|
||||
target_os = "redox"
|
||||
target_os = "redox",
|
||||
target_os = "vita",
|
||||
))] {
|
||||
addr_of_mut!((*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER));
|
||||
} else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] {
|
||||
|
@ -7,7 +7,7 @@ This tier supports the ARM Cortex A9 processor running on a PlayStation Vita con
|
||||
Rust support for this target is not affiliated with Sony, and is not derived
|
||||
from nor used with any official Sony SDK.
|
||||
|
||||
## Designated Developers
|
||||
## Target maintainers
|
||||
|
||||
* [@amg98](https://github.com/amg98)
|
||||
* [@nikarh](https://github.com/nikarh)
|
||||
@ -27,9 +27,9 @@ In order to support some APIs, binaries must be linked against `libc` written
|
||||
for the target, using a linker for the target. These are provided by the
|
||||
VITASDK toolchain.
|
||||
|
||||
This target generates binaries in the ELF format.
|
||||
This target generates binaries in the ELF format with thumb ISA.
|
||||
|
||||
## Building
|
||||
## Building the target
|
||||
|
||||
Rust does not ship pre-compiled artifacts for this target. You can use `build-std` flag to build binaries with `std`:
|
||||
|
||||
@ -37,43 +37,9 @@ Rust does not ship pre-compiled artifacts for this target. You can use `build-st
|
||||
cargo build -Z build-std=std,panic_abort --target=armv7-sony-vita-newlibeabihf --release
|
||||
```
|
||||
|
||||
## Cross-compilation
|
||||
## Building Rust programs
|
||||
|
||||
This target can be cross-compiled from `x86_64` on either Windows, MacOS or Linux systems. Other hosts are not supported for cross-compilation.
|
||||
|
||||
## Testing
|
||||
|
||||
Currently there is no support to run the rustc test suite for this target.
|
||||
|
||||
## Building and Running Rust Programs
|
||||
|
||||
`std` support for this target relies on newlib. In order to work, newlib must be initialized correctly. The easiest way to achieve this with VITASDK newlib implementation is by compiling your program as a staticlib with and exposing your main function from rust to `_init` function in `crt0`.
|
||||
|
||||
Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[profile.release]
|
||||
panic = 'abort'
|
||||
lto = true
|
||||
opt-level = 3
|
||||
```
|
||||
|
||||
Your entrypoint should look roughly like this, `src/lib.rs`:
|
||||
```rust,ignore,no_run
|
||||
#[used]
|
||||
#[export_name = "_newlib_heap_size_user"]
|
||||
pub static _NEWLIB_HEAP_SIZE_USER: u32 = 100 * 1024 * 1024; // Default heap size is only 32mb, increase it to something suitable for your application
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
```
|
||||
|
||||
To test your developed rust programs on PlayStation Vita, first you must correctly link and package your rust staticlib. These steps can be preformed using tools available in VITASDK, and can be automated using tools like `cargo-make`.
|
||||
To test your developed rust programs on PlayStation Vita, first you must correctly package your elf. These steps can be preformed using tools available in VITASDK, and can be automated using a tool like `cargo-make`.
|
||||
|
||||
First, set up environment variables for `VITASDK`, and it's binaries:
|
||||
|
||||
@ -88,40 +54,21 @@ Use the example below as a template for your project:
|
||||
[env]
|
||||
TITLE = "Rust Hello World"
|
||||
TITLEID = "RUST00001"
|
||||
# Add other libs required by your project here
|
||||
LINKER_LIBS = "-lpthread -lm -lmathneon"
|
||||
|
||||
# At least a "sce_sys" folder should be place there for app metadata (title, icons, description...)
|
||||
# You can find sample assets for that on $VITASDK/share/gcc-arm-vita-eabi/samples/hello_world/sce_sys/
|
||||
STATIC_DIR = "static" # Folder where static assets should be placed (sce_sys folder is at $STATIC_DIR/sce_sys)
|
||||
CARGO_TARGET_DIR = { script = ["echo ${CARGO_TARGET_DIR:=target}"] }
|
||||
RUST_TARGET = "armv7-sony-vita-newlibeabihf"
|
||||
CARGO_OUT_DIR = "${CARGO_TARGET_DIR}/${RUST_TARGET}/release"
|
||||
|
||||
TARGET_LINKER = "arm-vita-eabi-gcc"
|
||||
TARGET_LINKER_FLAGS = "-Wl,-q"
|
||||
|
||||
[tasks.build]
|
||||
description = "Build the project using `cargo` as a static lib."
|
||||
description = "Build the project using `cargo`."
|
||||
command = "cargo"
|
||||
args = ["build", "-Z", "build-std=std,panic_abort", "--target=armv7-sony-vita-newlibeabihf", "--release"]
|
||||
|
||||
[tasks.link]
|
||||
description = "Build an ELF executable using the `vitasdk` linker."
|
||||
dependencies = ["build"]
|
||||
script = [
|
||||
"""
|
||||
${TARGET_LINKER} ${TARGET_LINKER_FLAGS} \
|
||||
-L"${CARGO_OUT_DIR}" \
|
||||
-l"${CARGO_MAKE_CRATE_FS_NAME}" \
|
||||
${LINKER_LIBS} \
|
||||
-o"${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_NAME}.elf"
|
||||
"""
|
||||
]
|
||||
|
||||
[tasks.strip]
|
||||
description = "Strip the produced ELF executable."
|
||||
dependencies = ["link"]
|
||||
dependencies = ["build"]
|
||||
command = "arm-vita-eabi-strip"
|
||||
args = ["-g", '${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_FS_NAME}.elf']
|
||||
|
||||
@ -194,3 +141,11 @@ script = [
|
||||
```
|
||||
|
||||
After running the above script, you should be able to get a *.vpk file in the same folder your *.elf executable resides. Now you can pick it and install it on your own PlayStation Vita using, or you can use an [Vita3K](https://vita3k.org/) emulator.
|
||||
|
||||
## Testing
|
||||
|
||||
Currently there is no support to run the rustc test suite for this target.
|
||||
|
||||
## Cross-compilation
|
||||
|
||||
This target can be cross-compiled from `x86_64` on either Windows, MacOS or Linux systems. Other hosts are not supported for cross-compilation.
|
||||
|
Loading…
Reference in New Issue
Block a user