Skip to content

Commit 923672f

Browse files
committed
Add no_std support
- Through `no_std` support, we now also support `wasm32v1-none`. - Introduced a new `std` crate feature that is enabled by default. Without it `#[no_std]` is enabled, but only on Web! This allows Web target to build without std, which is now supported by `wasm-bindgen` as well. Additionally, various changes had to be done to support `no_std`: - `no_std` does not support `thread_local!`, we use `once_cell` to polyfill this gap. `once_cell` is not a new dependency, it is already a dependency of `wasm-bindgen`. - With `feature = "std"`, we use `thread_local!` as before. - Without std and without `target_feature = "atomics"`, we use a `static mut` with `once_cell::unsync::Lazy`. - Without std and with atomics, we use [`#[thread_local]`](https://doc.rust-lang.org/1.83.0/unstable-book/language-features/thread-local.html?highlight=thread_l#thread_local) with `once_cell::unsync::Lazy`. - Some `f64` instructions are not available on `no_std` and had to be polyfilled. For this code from [`libm`](https://crates.io/crates/libm) was copied. Which is used by std as well. - `SystemTimeError` now only implements `Error` with `feature = "std"`. - `no_std` testing requires to refrain from using the default test harness. The problem was that native tests still needed to use the default test harness. To solve this, integration tests were removed from root crate and two workspace members added, that manually define all integration tests as test targets. The `tests-web` crate has `harness = false` on all tests, while `tests-native` functions regularly. This allow us to use the default test harness for native tests while disabling it for Web. Additionally, every test target requires the `run` crate feature, which are enabled by default depending on the target by the root crate. This way regular testing can function correctly for each target as long as `--all-features` is not used. E.g. `cargo test --workspace` and `cargo test --workspace --target wasm32-unknown-unknown` will work correctly. The `tests-web` library is used to implement the `panic_handler`, `global_allocator` and `critical_section`. It is always imported to reduce code duplication in all tests. - Used [`serde-json-core`](https://crates.io/crates/serde-json-core) to cover tests with `no_std` as well. - All links to std documentation had to be supplemented with manual link when `std` is not present. - Improvements to CI: - Refactored all matrices for simplification and covering `--no-default-features`. - Split regular and minimal versions building off tests. - Split doctests from regular tests. - Update Rust toolchain when testing `cargo publish`. - Test coverage improvements: - The new `wasm-bindgen` update allows us to refrain from having to pass `cfg` flags to the `wasm-bindgen` proc-macros. - Use Rust `llvm-tools` instead of the official LLVM package. - Remove invalid `script` tag from coverage report. - Retain coverage artifact instead of limiting it to one day. - Refactor large environment variables into global level ones. - Small fixes that were stumbled upon: - Expose `web_time::web` with `cfg(docsrs)` on native as well. - `Serialize` and `Deserialize` implementation are now marked with `doc(cfg(feature = "serde"))`. - Std docs.rs link unnecessarily including `stable`. - Recommendation for `-Ctarget-feature=+nontrapping-fptoint` was moved from the top-level to the "Usage" section. - The minimal version of Serde is now fully specified as v1.0.0. - Fix some typos in internal documentation.
1 parent f1fa50c commit 923672f

40 files changed

Lines changed: 1725 additions & 488 deletions

.cargo/config.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
[target.wasm32-unknown-unknown]
1+
[target.'cfg(target_family = "wasm")']
22
runner = "wasm-bindgen-test-runner"

.config/topic.dic

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
23
1+
25
22
1G
33
1M
44
1ns
5+
allocator
56
APIs
67
Atomics
78
de
@@ -12,6 +13,7 @@ io
1213
JS
1314
MDN
1415
MSRV
16+
representable
1517
Serde
1618
Serde's
1719
timestamps

.github/workflows/build.yaml

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
name: Build
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
pull_request:
7+
8+
concurrency:
9+
group: ${{ github.workflow }}-${{ github.ref_name }}
10+
cancel-in-progress: true
11+
12+
env:
13+
CARGO_TERM_COLOR: always
14+
15+
jobs:
16+
build:
17+
name:
18+
Build ${{ matrix.target.description }} ${{ matrix.rust.description }} ${{
19+
matrix.features.description }}
20+
21+
runs-on: ubuntu-latest
22+
23+
strategy:
24+
fail-fast: false
25+
matrix:
26+
target:
27+
- { target: x86_64-unknown-linux-gnu, description: Native }
28+
- { target: wasm32-unknown-unknown, description: Web }
29+
- { target: wasm32v1-none, description: Wasm v1 }
30+
rust:
31+
- { version: "1.60", description: MSRV, atomics: false }
32+
- { version: stable, atomics: false }
33+
- { version: nightly, atomics: false }
34+
- {
35+
version: nightly,
36+
description: with Atomics,
37+
atomics: true,
38+
component: --component rust-src,
39+
flags: "-Ctarget-feature=+atomics,+bulk-memory",
40+
build-std: true,
41+
}
42+
features:
43+
- { features: "", no_std: false }
44+
- { features: --features serde, no_std: false, description: (`serde`) }
45+
- { features: --no-default-features, no_std: true, description: (`no_std`) }
46+
- {
47+
features: --no-default-features --features serde,
48+
no_std: true,
49+
description: "(`no_std`, `serde`)",
50+
}
51+
exclude:
52+
- target: { target: x86_64-unknown-linux-gnu, description: Native }
53+
rust: { version: nightly }
54+
- target: { target: wasm32-unknown-unknown, description: Web }
55+
rust: { version: nightly, atomics: false }
56+
- target: { target: wasm32v1-none, description: Wasm v1 }
57+
rust: { version: "1.60" }
58+
- target: { target: wasm32v1-none, description: Wasm v1 }
59+
rust: { version: stable }
60+
- target: { target: wasm32v1-none, description: Wasm v1 }
61+
features: { no_std: false }
62+
63+
steps:
64+
- name: Checkout
65+
uses: actions/checkout@v4
66+
- name: Install Rust
67+
run: |
68+
rustup toolchain install ${{ matrix.rust.version }} --profile minimal ${{ matrix.rust.component }} --target ${{ matrix.target.target }}
69+
rustup default ${{ matrix.rust.version }}
70+
- name: Set `build-std` components
71+
if: matrix.rust.build-std == true && matrix.features.no_std == false
72+
run: echo "BUILD_STD_COMPONENTS=-Zbuild-std=panic_abort,std" >> $GITHUB_ENV
73+
- name: Set `build-std` `no_std` components
74+
if: matrix.rust.build-std == true && matrix.features.no_std == true
75+
run: echo "BUILD_STD_COMPONENTS=-Zbuild-std=core,alloc" >> $GITHUB_ENV
76+
- name: Fix MSRV dependencies
77+
if: matrix.rust.version == '1.60'
78+
run: |
79+
cargo update -p bumpalo --precise 3.14.0
80+
cargo update -p serde --precise 1.0.210
81+
cargo update -p syn --precise 2.0.67
82+
- name: Build
83+
env:
84+
RUSTFLAGS: ${{ matrix.rust.flags }}
85+
run:
86+
cargo build ${{ matrix.features.features }} --target ${{ matrix.target.target }}
87+
$BUILD_STD_COMPONENTS
88+
89+
minimal-versions:
90+
name:
91+
Minimal Versions ${{ matrix.target.description }} ${{ matrix.rust.description }} ${{
92+
matrix.features.description }}
93+
94+
runs-on: ubuntu-latest
95+
96+
defaults:
97+
run:
98+
working-directory: minimal-versions
99+
100+
strategy:
101+
fail-fast: false
102+
matrix:
103+
target:
104+
- { target: x86_64-unknown-linux-gnu, description: Native }
105+
- { target: wasm32-unknown-unknown, description: Web }
106+
- { target: wasm32v1-none, description: Wasm v1 }
107+
rust:
108+
- { version: "1.60", description: MSRV }
109+
- { version: stable }
110+
- { version: nightly }
111+
features:
112+
- { features: "", no_std: false }
113+
- { features: --features serde, no_std: false, description: (`serde`) }
114+
- { features: --no-default-features, no_std: true, description: (`no_std`) }
115+
- {
116+
features: --no-default-features --features serde,
117+
no_std: true,
118+
description: "(`no_std`, `serde`)",
119+
}
120+
exclude:
121+
- target: { target: x86_64-unknown-linux-gnu, description: Native }
122+
rust: { version: nightly }
123+
- target: { target: wasm32-unknown-unknown, description: Web }
124+
rust: { version: nightly }
125+
- target: { target: wasm32v1-none, description: Wasm v1 }
126+
rust: { version: "1.60" }
127+
- target: { target: wasm32v1-none, description: Wasm v1 }
128+
rust: { version: stable }
129+
- target: { target: wasm32v1-none, description: Wasm v1 }
130+
features: { no_std: false }
131+
132+
steps:
133+
- name: Checkout
134+
uses: actions/checkout@v4
135+
- name: Install Rust
136+
run: |
137+
rustup toolchain install ${{ matrix.rust.version }} --profile minimal --target ${{ matrix.target.target }}
138+
rustup default ${{ matrix.rust.version }}
139+
- name: Downgrade to minimal versions
140+
run: |
141+
rustup toolchain install nightly --profile minimal
142+
cargo +nightly update -Z minimal-versions
143+
- name: Fix Rust nightly incompatible dependencies
144+
if: matrix.rust.version == 'nightly'
145+
run: |
146+
cargo update -p proc-macro2 --precise 1.0.60
147+
- name: Build
148+
run: cargo build ${{ matrix.features.features }} --target ${{ matrix.target.target }}

.github/workflows/coverage-documentation.yaml

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ env:
1515

1616
jobs:
1717
coverage:
18-
name: Test Coverage ${{ matrix.mt.description }}
18+
name: Test Coverage ${{ matrix.mt.description }} ${{ matrix.features.description }}
1919

2020
runs-on: ubuntu-latest
2121

@@ -24,15 +24,24 @@ jobs:
2424
strategy:
2525
matrix:
2626
mt:
27-
- { id: 0 }
27+
- { id: "st" }
2828
- {
29-
id: 1,
29+
id: "mt",
3030
description: with Atomics,
3131
component: --component rust-src,
3232
cflags: -matomics -mbulk-memory,
3333
flags: "-Ctarget-feature=+atomics,+bulk-memory",
34-
args: "-Zbuild-std=panic_abort,std",
34+
build-std: true,
3535
}
36+
features:
37+
- { id: "", features: "", no_std: false }
38+
- { id: -no_std, features: --no-default-features, no_std: true, description: (`no_std`) }
39+
40+
env:
41+
CFLAGS_wasm32_unknown_unknown: ${{ matrix.mt.cflags }}
42+
RUSTFLAGS:
43+
-Cinstrument-coverage -Zcoverage-options=condition -Zno-profiler-runtime --emit=llvm-ir
44+
--cfg=wasm_bindgen_unstable_test_coverage ${{ matrix.mt.flags }}
3645

3746
steps:
3847
- name: Checkout
@@ -50,31 +59,25 @@ jobs:
5059
run: |
5160
rustup toolchain install nightly --profile minimal --target wasm32-unknown-unknown ${{ matrix.mt.component }}
5261
rustup default nightly
62+
- name: Set `build-std` components
63+
if: matrix.mt.build-std == true && matrix.features.no_std == false
64+
run: echo "BUILD_STD_COMPONENTS=-Zbuild-std=panic_abort,std" >> $GITHUB_ENV
65+
- name: Set `build-std` `no_std` components
66+
if: matrix.mt.build-std == true && matrix.features.no_std == true
67+
run: echo "BUILD_STD_COMPONENTS=-Zbuild-std=core,alloc" >> $GITHUB_ENV
5368
- name: Test
5469
env:
5570
CHROMEDRIVER: chromedriver
56-
CFLAGS_wasm32_unknown_unknown: ${{ matrix.mt.cflags }}
57-
CARGO_HOST_RUSTFLAGS: --cfg=wasm_bindgen_unstable_test_coverage
58-
RUSTFLAGS:
59-
-Cinstrument-coverage -Zcoverage-options=condition -Zno-profiler-runtime --emit=llvm-ir
60-
--cfg=wasm_bindgen_unstable_test_coverage ${{ matrix.mt.flags }}
61-
WASM_BINDGEN_UNSTABLE_TEST_PROFRAW_OUT: coverage-output
6271
run: |
6372
mkdir coverage-output
64-
cargo test --all-features --target wasm32-unknown-unknown -Ztarget-applies-to-host -Zhost-config ${{ matrix.mt.args }} --tests
73+
WASM_BINDGEN_UNSTABLE_TEST_PROFRAW_OUT=$(realpath coverage-output) cargo test --workspace --features serde --target wasm32-unknown-unknown $BUILD_STD_COMPONENTS ${{ matrix.features.features }} --tests
6574
- name: Prepare Object Files
66-
env:
67-
CFLAGS_wasm32_unknown_unknown: ${{ matrix.mt.cflags }}
68-
CARGO_HOST_RUSTFLAGS: --cfg=wasm_bindgen_unstable_test_coverage
69-
RUSTFLAGS:
70-
-Cinstrument-coverage -Zcoverage-options=condition -Zno-profiler-runtime --emit=llvm-ir
71-
--cfg=wasm_bindgen_unstable_test_coverage ${{ matrix.mt.flags }}
7275
run: |
7376
mkdir coverage-input
7477
crate_name=web_time
7578
IFS=$'\n'
7679
for file in $(
77-
cargo test --all-features --target wasm32-unknown-unknown -Ztarget-applies-to-host -Zhost-config ${{ matrix.mt.args }} --tests --no-run --message-format=json | \
80+
cargo test --workspace --features serde --target wasm32-unknown-unknown $BUILD_STD_COMPONENTS ${{ matrix.features.features }} --tests --no-run --message-format=json | \
7881
jq -r "select(.reason == \"compiler-artifact\") | (select(.target.kind == [\"test\"]) // select(.target.name == \"$crate_name\")) | .filenames[0]"
7982
)
8083
do
@@ -90,7 +93,7 @@ jobs:
9093
- name: Upload Test Coverage Artifact
9194
uses: actions/upload-artifact@v4
9295
with:
93-
name: test-coverage-${{ matrix.mt.id }}
96+
name: test-coverage-${{ matrix.mt.id }}${{ matrix.features.id }}
9497
path: coverage-output
9598
retention-days: 1
9699
if-no-files-found: error
@@ -105,20 +108,22 @@ jobs:
105108
steps:
106109
- name: Checkout
107110
uses: actions/checkout@v4
108-
- name: Install LLVM v19
111+
- name: Install Rust nightly
109112
run: |
110-
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
111-
sudo add-apt-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main"
112-
sudo apt-get install llvm-19
113+
rustup toolchain install nightly --profile minimal --component llvm-tools
114+
rustup default nightly
115+
- name: Install `cargo-binutils`
116+
uses: taiki-e/install-action@v2
117+
with:
118+
tool: cargo-binutils
113119
- name: Download Test Coverage
114120
uses: actions/download-artifact@v4
115121
with:
116122
pattern: test-coverage-*
117123
path: coverage-input
118124
- name: Merge Profile Data
119125
run:
120-
llvm-profdata-19 merge -sparse coverage-input/*/*.profraw -o
121-
coverage-input/coverage.profdata
126+
rust-profdata merge -sparse coverage-input/*/*.profraw -o coverage-input/coverage.profdata
122127
- name: Export Code Coverage Report
123128
run: |
124129
mkdir coverage-output
@@ -127,16 +132,15 @@ jobs:
127132
do
128133
objects+=(-object $file)
129134
done
130-
llvm-cov-19 show -show-instantiations=false -output-dir coverage-output -format=html -instr-profile=coverage-input/coverage.profdata ${objects[@]} -sources src
131-
llvm-cov-19 export -format=text -summary-only -instr-profile=coverage-input/coverage.profdata ${objects[@]} -sources src | \
135+
rust-cov show -show-instantiations=false -output-dir coverage-output -format=html -instr-profile=coverage-input/coverage.profdata ${objects[@]} -sources src
136+
rust-cov export -format=text -summary-only -instr-profile=coverage-input/coverage.profdata ${objects[@]} -sources src | \
132137
printf '{ "coverage": "%.2f%%" }' $(jq '.data[0].totals.functions.percent') > coverage-output/coverage.json
133-
sed 's/<!doctype html>//' coverage-output/index.html | perl -p0e 's/<a[^>]*>((?!here).*?)<\/a>/$1/g' >> $GITHUB_STEP_SUMMARY
138+
sed 's/<!doctype html>//' coverage-output/index.html | sed "s/<script src='control.js'><\/script>//" | perl -p0e 's/<a[^>]*>((?!here).*?)<\/a>/$1/g' >> $GITHUB_STEP_SUMMARY
134139
- name: Upload Test Coverage Artifact
135140
uses: actions/upload-artifact@v4
136141
with:
137142
name: test-coverage
138143
path: coverage-output
139-
retention-days: 1
140144
if-no-files-found: error
141145

142146
document:
@@ -158,7 +162,7 @@ jobs:
158162
RUSTDOCFLAGS: --crate-version main --cfg=docsrs
159163
run:
160164
cargo doc --no-deps -Z rustdoc-map -Z rustdoc-scrape-examples --target
161-
wasm32-unknown-unknown --all-features
165+
wasm32-unknown-unknown --features serde
162166
- name: Setup Pages
163167
uses: actions/configure-pages@v5
164168
- name: Fix permissions

0 commit comments

Comments
 (0)