diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 665591ec..5f088736 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -192,3 +192,17 @@ jobs: cargo +nightly-2022-11-17 run --target=${{ matrix.host_target }} env: RUST_BACKTRACE: 1 + + - name: test mustang-no-std as program + working-directory: test-crates/origin-as-just-a-library + run: | + cargo +nightly-2022-11-17 run -Zbuild-std=core,alloc --target=../../mustang/target-specs/${{ matrix.host_target }}.json + env: + RUST_BACKTRACE: 1 + + - name: test mustang-no-std as tests + working-directory: test-crates/origin-as-just-a-library + run: | + cargo +nightly-2022-11-17 test -Zbuild-std=core,alloc,test,std --target=../../mustang/target-specs/${{ matrix.host_target }}.json + env: + RUST_BACKTRACE: 1 diff --git a/test-crates/mustang-nostd/Cargo.toml b/test-crates/mustang-nostd/Cargo.toml new file mode 100644 index 00000000..0ee7d271 --- /dev/null +++ b/test-crates/mustang-nostd/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "mustang-nostd" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +# The mustang crate provides the `can_run_this!()` macro. +mustang = { path = "../../mustang", default-features = false, features = ["threads", "default-alloc"] } + +[workspace] diff --git a/test-crates/mustang-nostd/README.md b/test-crates/mustang-nostd/README.md new file mode 100644 index 00000000..53aefa91 --- /dev/null +++ b/test-crates/mustang-nostd/README.md @@ -0,0 +1,21 @@ +This crate demonstrates the use of mustang with no_std. Specifying `-Zbuild-std=core,alloc` lets you skip compiling std as it will not be used: + +``` +cargo run --target=x86_64-mustang-linux-gnu -Zbuild-std=core,alloc +``` + +This line: + +```toml +mustang = { path = "../../mustang", default-features = false, features = ["threads", "default-alloc"] } +``` + +tells cargo to not enable the "std" feature which results in no dependencies on std. c-gull will re-export the no-std version of c-scape. c-scape is still necessary because `dlmalloc` and `unwinding` rely on some libc functionality. `dlmalloc` uses libc for syscalls and needs a pthread implementation for `GlobalAlloc`. `unwinding` uses the libc `dl_iterate_phdr` function, see [comment](https://github.com/sunfishcode/mustang/blob/bf6b53a4c5edd1dec71fa65f468b2c76ff96eb62/mustang/Cargo.toml#L19). + +You can use either `#[start]` or replacing the C shim as in the example. See the unstable book for more [details](https://doc.rust-lang.org/unstable-book/language-features/lang-items.html#writing-an-executable-without-stdlib). It may or may not be undefined behavior to call `panic!()` from the function as no catch_unwind has been set, see the start feature [tracking issue](https://github.com/rust-lang/rust/issues/29633) and [following issue](https://github.com/rust-lang/rust/issues/107381). + +To use tests, make sure to also compile test and std: + +``` +cargo test --target=x86_64-mustang-linux-gnu -Zbuild-std=core,alloc,std,test +``` diff --git a/test-crates/mustang-nostd/src/main.rs b/test-crates/mustang-nostd/src/main.rs new file mode 100644 index 00000000..c3597f87 --- /dev/null +++ b/test-crates/mustang-nostd/src/main.rs @@ -0,0 +1,38 @@ +#![feature(lang_items)] +#![no_std] +// When testing we do not want to use our main function +#![cfg_attr(not(test), no_main)] + +mustang::can_run_this!(); + +use core::ffi::c_int; + +#[cfg(not(test))] +#[panic_handler] +fn panic(_panic: &core::panic::PanicInfo<'_>) -> ! { + loop {} +} + +#[cfg(not(test))] +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +// Small hack for rust-analyzer. +// +// If we do `#[cfg(not(test))]` then rust-analyzer will say the code is inactive and we +// lose the ability to use rust-analyzer. +// By disabling `no_mangle` during test, we do not get the two main functions defined error. +// This function ends up just behaving like any other (unused) function in the binary during +// test compilation. +// +// Using `#[start]` would not require us to use this hack but then we lose `_envp` +// function parameter. +#[cfg_attr(not(test), no_mangle)] +extern "C" fn main(_argc: c_int, _argv: *mut *mut u8, _envp: *mut *mut u8) -> c_int { + 0 +} + +#[test] +fn test_tests() { + assert_eq!(1, 1) +}