From b4f5cba86b7544675a14be4d5e89b3dbe9c61c07 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 29 Mar 2024 10:59:59 -0700 Subject: [PATCH] Start migrating some Wasmtime crates to no_std This commit is the first in what will be multiple PRs to migrate Wasmtime to being compatible with `#![no_std]`. This work is outlined in #8341 and the rough plan I have in mind is to go on a crate-by-crate basis and use CI as a "ratchet" to ensure that `no_std` compat is preserved. In that sense this PR is a bit of a template for future PRs. This PR migrates a few small crates to `no_std`, basically those that need no changes beyond simply adding the attribute. The nontrivial parts introduced in this PR are: * CI is introduced to verify that a subset of crates can indeed be built on a `no_std` target. The target selected is `x86_64-unknown-none` which is known to not have `std` and will result in a build error if it's attempted to be used. * The `anyhow` crate, which `wasmtime-jit-icache-coherence` now depends on, has its `std` feature disabled by default in Wasmtime's workspace. This means that some crates which require `std` now need to explicitly enable the feature, but it means that by-default its usage is appropriate for `no_std`. The first point should provide CI checks that compatibility with `no_std` indeed works, at least from an "it compiles" perspective. Note that it's not sufficient to test with a target like `x86_64-unknown-linux-gnu` because `extern crate std` will work on that target, even when `#![no_std]` is active. The second point however is likely to increase maintenance burden in Wasmtime unfortunately. Namely we'll inevitably, either here or in the future, forget to turn on some feature for some crate that's not covered in CI checks. While I've tried to do my best here in covering it there's no guarantee that everything will work and the combinatorial explosion of what could be checked in CI can't all be added to CI. Instead we'll have to rely on bug fixes, users, and perhaps point releases to add more use cases to CI over time as we see fit. --- .github/workflows/main.yml | 13 +++++++++++++ Cargo.lock | 1 + Cargo.toml | 2 +- cranelift/codegen/Cargo.toml | 2 +- crates/asm-macros/src/lib.rs | 2 ++ crates/component-util/src/lib.rs | 2 ++ crates/environ/Cargo.toml | 2 +- crates/jit-icache-coherence/Cargo.toml | 1 + crates/jit-icache-coherence/src/lib.rs | 11 ++++++----- crates/jit-icache-coherence/src/libc.rs | 11 ++++++++--- crates/jit-icache-coherence/src/win.rs | 6 +++++- crates/test-programs/Cargo.toml | 2 +- 12 files changed, 42 insertions(+), 13 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 37086e8af914..6dbd228904e2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -357,6 +357,19 @@ jobs: - run: cargo check -p wasmtime-c-api --no-default-features --features wat - run: cargo check -p wasmtime-c-api --no-default-features --features wasi + # Checks for no_std support, ensure that crates can build on a no_std + # target + - run: rustup target add x86_64-unknown-none + - run: cargo check -p wasmtime-jit-icache-coherence + env: + CARGO_BUILD_TARGET: x86_64-unknown-none + - run: cargo check -p wasmtime-component-util + env: + CARGO_BUILD_TARGET: x86_64-unknown-none + - run: cargo check -p wasmtime-asm-macros + env: + CARGO_BUILD_TARGET: x86_64-unknown-none + # Check that wasmtime-runtime compiles with panic=abort since there's some # #[cfg] for specifically panic=abort there. - run: cargo check -p wasmtime-runtime diff --git a/Cargo.lock b/Cargo.lock index de9ad7eab980..a2506707f7b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3784,6 +3784,7 @@ dependencies = [ name = "wasmtime-jit-icache-coherence" version = "21.0.0" dependencies = [ + "anyhow", "cfg-if", "libc", "windows-sys 0.52.0", diff --git a/Cargo.toml b/Cargo.toml index f137a2e269dc..3559de830a37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -248,7 +248,7 @@ wit-component = "0.205.0" # -------------------------- object = { version = "0.33", default-features = false, features = ['read_core', 'elf', 'std'] } gimli = { version = "0.28.0", default-features = false, features = ['read', 'std'] } -anyhow = "1.0.22" +anyhow = { version = "1.0.22", default-features = false } windows-sys = "0.52.0" env_logger = "0.10" log = { version = "0.4.8", default-features = false } diff --git a/cranelift/codegen/Cargo.toml b/cranelift/codegen/Cargo.toml index 2dfde787eda9..8a6c18fa2ed8 100644 --- a/cranelift/codegen/Cargo.toml +++ b/cranelift/codegen/Cargo.toml @@ -16,7 +16,7 @@ edition.workspace = true workspace = true [dependencies] -anyhow = { workspace = true, optional = true } +anyhow = { workspace = true, optional = true, features = ['std'] } bumpalo = "3" capstone = { workspace = true, optional = true } cranelift-codegen-shared = { path = "./shared", version = "0.108.0" } diff --git a/crates/asm-macros/src/lib.rs b/crates/asm-macros/src/lib.rs index efd970d6bca0..0fd62e8b382f 100644 --- a/crates/asm-macros/src/lib.rs +++ b/crates/asm-macros/src/lib.rs @@ -6,6 +6,8 @@ //! function) and additionally handles visibility across platforms. All symbols //! should be visible to Rust but not visible externally outside of a `*.so`. +#![no_std] + cfg_if::cfg_if! { if #[cfg(target_os = "macos")] { #[macro_export] diff --git a/crates/component-util/src/lib.rs b/crates/component-util/src/lib.rs index db1e4b97689e..642b8e34969d 100644 --- a/crates/component-util/src/lib.rs +++ b/crates/component-util/src/lib.rs @@ -1,3 +1,5 @@ +#![no_std] + /// Represents the possible sizes in bytes of the discriminant of a variant type in the component model #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum DiscriminantSize { diff --git a/crates/environ/Cargo.toml b/crates/environ/Cargo.toml index c0a78b943593..00236a5e5918 100644 --- a/crates/environ/Cargo.toml +++ b/crates/environ/Cargo.toml @@ -14,7 +14,7 @@ edition.workspace = true workspace = true [dependencies] -anyhow = { workspace = true } +anyhow = { workspace = true, features = ['std'] } bincode = { workspace = true } cpp_demangle = { version = "0.4.3", optional = true } cranelift-entity = { workspace = true } diff --git a/crates/jit-icache-coherence/Cargo.toml b/crates/jit-icache-coherence/Cargo.toml index 8fcbcc280acc..2f7461f1c20d 100644 --- a/crates/jit-icache-coherence/Cargo.toml +++ b/crates/jit-icache-coherence/Cargo.toml @@ -13,6 +13,7 @@ workspace = true [dependencies] cfg-if = { workspace = true } +anyhow = { workspace = true } [target.'cfg(target_os = "windows")'.dependencies.windows-sys] workspace = true diff --git a/crates/jit-icache-coherence/src/lib.rs b/crates/jit-icache-coherence/src/lib.rs index 8964372b729e..fc9a20d3a9a8 100644 --- a/crates/jit-icache-coherence/src/lib.rs +++ b/crates/jit-icache-coherence/src/lib.rs @@ -34,7 +34,7 @@ //! # len: usize, //! # } //! # -//! # fn main() -> io::Result<()> { +//! # fn main() -> anyhow::Result<()> { //! # //! # let run_code = || {}; //! # let code = vec![0u8; 64]; @@ -67,8 +67,9 @@ //! //! [ARM Community - Caches and Self-Modifying Code]: https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/caches-and-self-modifying-code -use std::ffi::c_void; -use std::io::Result; +#![no_std] + +use core::ffi::c_void; cfg_if::cfg_if! { if #[cfg(target_os = "windows")] { @@ -91,7 +92,7 @@ cfg_if::cfg_if! { /// after all calls to [clear_cache]. /// /// If the architecture does not require a pipeline flush, this function does nothing. -pub fn pipeline_flush_mt() -> Result<()> { +pub fn pipeline_flush_mt() -> imp::Result<()> { imp::pipeline_flush_mt() } @@ -103,6 +104,6 @@ pub fn pipeline_flush_mt() -> Result<()> { /// /// It is necessary to call [pipeline_flush_mt] after this function if you are running in a multi-threaded /// environment. -pub unsafe fn clear_cache(ptr: *const c_void, len: usize) -> Result<()> { +pub unsafe fn clear_cache(ptr: *const c_void, len: usize) -> imp::Result<()> { imp::clear_cache(ptr, len) } diff --git a/crates/jit-icache-coherence/src/libc.rs b/crates/jit-icache-coherence/src/libc.rs index 364658bd1813..596d9e648d7f 100644 --- a/crates/jit-icache-coherence/src/libc.rs +++ b/crates/jit-icache-coherence/src/libc.rs @@ -1,14 +1,16 @@ -use std::ffi::c_void; -use std::io::Result; +use core::ffi::c_void; #[cfg(all( target_arch = "aarch64", any(target_os = "linux", target_os = "android") ))] mod details { + extern crate std; + use super::*; use libc::{syscall, EINVAL, EPERM}; use std::io::Error; + pub use std::io::Result; const MEMBARRIER_CMD_GLOBAL: libc::c_int = 1; const MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE: libc::c_int = 32; @@ -87,7 +89,10 @@ mod details { any(target_os = "linux", target_os = "android") )))] mod details { - pub(crate) fn pipeline_flush_mt() -> std::io::Result<()> { + // NB: this uses `anyhow::Result` instead of `std::io::Result` to compile on + // `no_std`. + pub use anyhow::Result; + pub(crate) fn pipeline_flush_mt() -> Result<()> { Ok(()) } } diff --git a/crates/jit-icache-coherence/src/win.rs b/crates/jit-icache-coherence/src/win.rs index 488e15f46670..83e0ff6679cc 100644 --- a/crates/jit-icache-coherence/src/win.rs +++ b/crates/jit-icache-coherence/src/win.rs @@ -1,9 +1,13 @@ +extern crate std; + use std::ffi::c_void; -use std::io::{Error, Result}; +use std::io::Error; use windows_sys::Win32::System::Diagnostics::Debug::FlushInstructionCache; use windows_sys::Win32::System::Threading::FlushProcessWriteBuffers; use windows_sys::Win32::System::Threading::GetCurrentProcess; +pub use std::io::Result; + /// See docs on [crate::pipeline_flush_mt] for a description of what this function is trying to do. #[inline] pub(crate) fn pipeline_flush_mt() -> Result<()> { diff --git a/crates/test-programs/Cargo.toml b/crates/test-programs/Cargo.toml index 86854364ff43..eae086c8a537 100644 --- a/crates/test-programs/Cargo.toml +++ b/crates/test-programs/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0 WITH LLVM-exception" workspace = true [dependencies] -anyhow = { workspace = true } +anyhow = { workspace = true, features = ['std'] } wasi = "0.11.0" wasi-nn = "0.6.0" wit-bindgen = { workspace = true, features = ['default'] }