Skip to content

Commit ec2fd54

Browse files
authored
Mustang nostd support (#156)
* do not use std exp2 * nostd support: passthrough from c-gull to c-scape * add nostd test crate
1 parent bf6b53a commit ec2fd54

File tree

9 files changed

+106
-13
lines changed

9 files changed

+106
-13
lines changed

.github/workflows/main.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,17 @@ jobs:
192192
cargo +nightly-2022-11-17 run --target=${{ matrix.host_target }}
193193
env:
194194
RUST_BACKTRACE: 1
195+
196+
- name: test mustang-nostd as program
197+
working-directory: test-crates/mustang-nostd
198+
run: |
199+
cargo +nightly-2022-11-17 run -Zbuild-std=core,alloc --target=../../mustang/target-specs/${{ matrix.mustang_target }}.json
200+
env:
201+
RUST_BACKTRACE: 1
202+
203+
- name: test mustang-nostd as tests
204+
working-directory: test-crates/mustang-nostd
205+
run: |
206+
cargo +nightly-2022-11-17 test -Zbuild-std=core,alloc,test,std --target=../../mustang/target-specs/${{ matrix.mustang_target }}.json
207+
env:
208+
RUST_BACKTRACE: 1

c-gull/Cargo.toml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,20 @@ repository = "https://github.com/sunfishcode/mustang"
1111
edition = "2021"
1212

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

2424
[dev-dependencies]
2525
libc = "0.2.138"
2626

2727
[features]
28-
default = ["threads"]
28+
default = ["threads", "std"]
2929
threads = ["c-scape/threads"]
30+
std = ["c-scape/default", "rustix", "log", "printf-compat", "tz-rs", "errno"]

c-gull/src/lib.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#![feature(c_variadic)]
55
#![deny(fuzzy_provenance_casts)]
66
#![deny(lossy_provenance_casts)]
7+
#![cfg_attr(not(feature = "std"), no_std)]
78

89
extern crate c_scape;
910

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

18+
#[cfg(feature = "std")]
1719
mod nss;
20+
#[cfg(feature = "std")]
1821
mod printf;
22+
#[cfg(feature = "std")]
1923
mod strtod;
24+
#[cfg(feature = "std")]
2025
mod strtol;
26+
#[cfg(feature = "std")]
2127
mod time;
2228

23-
use std::ffi::CStr;
24-
29+
#[cfg(feature = "std")]
2530
#[no_mangle]
2631
unsafe extern "C" fn __assert_fail(
2732
expr: *const c_char,
2833
file: *const c_char,
2934
line: c_int,
3035
func: *const c_char,
3136
) -> ! {
37+
use std::ffi::CStr;
3238
//libc!(libc::__assert_fail(expr, file, line, func));
3339

3440
eprintln!(

c-scape/src/rand48.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ unsafe extern "C" fn erand48(x_subi: *mut c_ushort) -> c_double {
5858

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

61-
(next_integral >> 11) as f64 * f64::exp2(-53.0)
61+
(next_integral >> 11) as f64 * libm::exp2(-53.0)
6262
}
6363

6464
#[no_mangle]

mustang/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ features = [
3333

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

3838
# A general-purpose `global_allocator` implementation.
3939
dlmalloc = { version = "0.2", features = ["global"], optional = true }
@@ -47,4 +47,4 @@ threads = ["origin/threads", "c-gull/threads"]
4747
env_logger = ["origin/env_logger"]
4848
log = ["origin/log"]
4949
max_level_off = ["origin/max_level_off"]
50-
std = ["c-gull"]
50+
std = ["c-gull/default"]

mustang/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ macro_rules! can_run_this {
2525
() => {};
2626
}
2727

28-
#[cfg(feature = "std")]
2928
#[cfg(target_vendor = "mustang")]
3029
extern crate c_gull;
3130
#[cfg(target_vendor = "mustang")]

test-crates/mustang-nostd/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "mustang-nostd"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
# The mustang crate provides the `can_run_this!()` macro.
10+
mustang = { path = "../../mustang", default-features = false, features = ["threads", "default-alloc"] }
11+
12+
[workspace]

test-crates/mustang-nostd/README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
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:
2+
3+
```
4+
cargo run --target=x86_64-mustang-linux-gnu -Zbuild-std=core,alloc
5+
```
6+
7+
This line:
8+
9+
```toml
10+
mustang = { path = "../../mustang", default-features = false, features = ["threads", "default-alloc"] }
11+
```
12+
13+
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).
14+
15+
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).
16+
17+
To use tests, make sure to also compile test and std:
18+
19+
```
20+
cargo test --target=x86_64-mustang-linux-gnu -Zbuild-std=core,alloc,std,test
21+
```

test-crates/mustang-nostd/src/main.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#![feature(lang_items)]
2+
// TODO: Remove when updating toolchain for tests
3+
#![feature(default_alloc_error_handler)]
4+
#![no_std]
5+
// When testing we do not want to use our main function
6+
#![cfg_attr(not(test), no_main)]
7+
8+
mustang::can_run_this!();
9+
10+
use core::ffi::c_int;
11+
12+
#[cfg(not(test))]
13+
#[panic_handler]
14+
fn panic(_panic: &core::panic::PanicInfo<'_>) -> ! {
15+
loop {}
16+
}
17+
18+
#[cfg(not(test))]
19+
#[lang = "eh_personality"]
20+
extern "C" fn eh_personality() {}
21+
22+
// Small hack for rust-analyzer.
23+
//
24+
// If we do `#[cfg(not(test))]` then rust-analyzer will say the code is inactive and we
25+
// lose the ability to use rust-analyzer.
26+
// By disabling `no_mangle` during test, we do not get the two main functions defined error.
27+
// This function ends up just behaving like any other (unused) function in the binary during
28+
// test compilation.
29+
//
30+
// Using `#[start]` would not require us to use this hack but then we lose `_envp`
31+
// function parameter.
32+
#[cfg_attr(not(test), no_mangle)]
33+
extern "C" fn main(_argc: c_int, _argv: *mut *mut u8, _envp: *mut *mut u8) -> c_int {
34+
0
35+
}
36+
37+
#[test]
38+
fn test_tests() {
39+
assert_eq!(1, 1)
40+
}

0 commit comments

Comments
 (0)