Skip to content

Commit

Permalink
Mustang nostd support (#156)
Browse files Browse the repository at this point in the history
* do not use std exp2

* nostd support: passthrough from c-gull to c-scape

* add nostd test crate
  • Loading branch information
jordanisaacs authored Feb 6, 2023
1 parent bf6b53a commit ec2fd54
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 13 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,17 @@ jobs:
cargo +nightly-2022-11-17 run --target=${{ matrix.host_target }}
env:
RUST_BACKTRACE: 1

- name: test mustang-nostd as program
working-directory: test-crates/mustang-nostd
run: |
cargo +nightly-2022-11-17 run -Zbuild-std=core,alloc --target=../../mustang/target-specs/${{ matrix.mustang_target }}.json
env:
RUST_BACKTRACE: 1

- name: test mustang-nostd as tests
working-directory: test-crates/mustang-nostd
run: |
cargo +nightly-2022-11-17 test -Zbuild-std=core,alloc,test,std --target=../../mustang/target-specs/${{ matrix.mustang_target }}.json
env:
RUST_BACKTRACE: 1
15 changes: 8 additions & 7 deletions c-gull/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@ repository = "https://github.com/sunfishcode/mustang"
edition = "2021"

[dependencies]
rustix = { version = "0.36.1", default-features = false, features = ["fs", "itoa", "net", "param", "process", "rand", "termios", "thread", "time"] }
# We use the libc crate for C ABI types and constants, but we don't depend on
# the actual platform libc.
libc = { version = "0.2.138", default-features = false }
errno = { version = "0.2.8", default-features = false }
c-scape = { path = "../c-scape", version = "0.6.1", features = ["std"] }
tz-rs = "0.6.11"
printf-compat = "0.1.1"
log = { version = "0.4.14", default-features = false }
c-scape = { path = "../c-scape", version = "0.6.1", default-features = false }
errno = { version = "0.2.8", default-features = false, optional = true }
tz-rs = { version = "0.6.11", optional = true }
printf-compat = { version = "0.1.1", optional = true}
log = { version = "0.4.14", default-features = false, optional = true }
rustix = { version = "0.36.1", default-features = false, optional = true, features = ["fs", "itoa", "net", "param", "process", "rand", "termios", "thread", "time"] }

[dev-dependencies]
libc = "0.2.138"

[features]
default = ["threads"]
default = ["threads", "std"]
threads = ["c-scape/threads"]
std = ["c-scape/default", "rustix", "log", "printf-compat", "tz-rs", "errno"]
10 changes: 8 additions & 2 deletions c-gull/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#![feature(c_variadic)]
#![deny(fuzzy_provenance_casts)]
#![deny(lossy_provenance_casts)]
#![cfg_attr(not(feature = "std"), no_std)]

extern crate c_scape;

Expand All @@ -14,21 +15,26 @@ pub use libc::*;
#[macro_use]
mod use_libc;

#[cfg(feature = "std")]
mod nss;
#[cfg(feature = "std")]
mod printf;
#[cfg(feature = "std")]
mod strtod;
#[cfg(feature = "std")]
mod strtol;
#[cfg(feature = "std")]
mod time;

use std::ffi::CStr;

#[cfg(feature = "std")]
#[no_mangle]
unsafe extern "C" fn __assert_fail(
expr: *const c_char,
file: *const c_char,
line: c_int,
func: *const c_char,
) -> ! {
use std::ffi::CStr;
//libc!(libc::__assert_fail(expr, file, line, func));

eprintln!(
Expand Down
2 changes: 1 addition & 1 deletion c-scape/src/rand48.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ unsafe extern "C" fn erand48(x_subi: *mut c_ushort) -> c_double {

let next_integral = next_lcong(x_subi, addr_of!((*STORAGE.get()).data));

(next_integral >> 11) as f64 * f64::exp2(-53.0)
(next_integral >> 11) as f64 * libm::exp2(-53.0)
}

#[no_mangle]
Expand Down
4 changes: 2 additions & 2 deletions mustang/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ features = [

[target.'cfg(target_vendor = "mustang")'.dependencies]
origin = { path = "../origin", default-features = false, version = "^0.6.1" }
c-gull = { path = "../c-gull", version = "^0.6.1", optional = true }
c-gull = { path = "../c-gull", version = "^0.6.1", default-features = false }

# A general-purpose `global_allocator` implementation.
dlmalloc = { version = "0.2", features = ["global"], optional = true }
Expand All @@ -47,4 +47,4 @@ threads = ["origin/threads", "c-gull/threads"]
env_logger = ["origin/env_logger"]
log = ["origin/log"]
max_level_off = ["origin/max_level_off"]
std = ["c-gull"]
std = ["c-gull/default"]
1 change: 0 additions & 1 deletion mustang/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ macro_rules! can_run_this {
() => {};
}

#[cfg(feature = "std")]
#[cfg(target_vendor = "mustang")]
extern crate c_gull;
#[cfg(target_vendor = "mustang")]
Expand Down
12 changes: 12 additions & 0 deletions test-crates/mustang-nostd/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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]
21 changes: 21 additions & 0 deletions test-crates/mustang-nostd/README.md
Original file line number Diff line number Diff line change
@@ -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
```
40 changes: 40 additions & 0 deletions test-crates/mustang-nostd/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#![feature(lang_items)]
// TODO: Remove when updating toolchain for tests
#![feature(default_alloc_error_handler)]
#![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)
}

0 comments on commit ec2fd54

Please sign in to comment.