Skip to content

Commit

Permalink
jiff: add robust WASM support
Browse files Browse the repository at this point in the history
This PR basically makes the `wasm{32,64}-unknown-unknown` targets work
_almost_ out of the box. All you need to do is enable Jiff's new `js`
crate feature. This will cause Jiff to depend on `js-sys` and
`wasm-bindgen`. Jiff will then use Javascript APIs to determine the
current time and time zone.

This PR also includes a new long form guide, `PLATFORM.md`, which
describes Jiff's platform support in one central location. (Most
information is already in Jiff's API docs, but it's scattered in a
variety of places.)

Finally, this adds a `wasm32-unknown-unknown` test to CI courtesy of
`wasm-pack`. It just does a basic sanity check that the current time and
time zone can be retrieved.

Fixes #56
  • Loading branch information
BurntSushi committed Jul 31, 2024
1 parent f4b7636 commit a44e494
Show file tree
Hide file tree
Showing 22 changed files with 737 additions and 78 deletions.
163 changes: 101 additions & 62 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,6 @@ permissions:

jobs:
test:
env:
# For some builds, we use cross to test on 32-bit and big-endian
# systems.
CARGO: cargo
# When CARGO is set to CROSS, TARGET is set to `--target matrix.target`.
# Note that we only use cross on Linux, so setting a target on a
# different OS will just use normal cargo.
TARGET:
# Bump this as appropriate. We pin to a version to make sure CI
# continues to work as cross releases in the past have broken things
# in subtle ways.
CROSS_VERSION: v0.2.5
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
Expand All @@ -49,22 +37,6 @@ jobs:
- build: stable
os: ubuntu-latest
rust: stable
- build: stable-x86
os: ubuntu-latest
rust: stable
target: i686-unknown-linux-gnu
- build: stable-aarch64
os: ubuntu-latest
rust: stable
target: aarch64-unknown-linux-gnu
- build: stable-powerpc64
os: ubuntu-latest
rust: stable
target: powerpc64-unknown-linux-gnu
- build: stable-s390x
os: ubuntu-latest
rust: stable
target: s390x-unknown-linux-gnu
- build: beta
os: ubuntu-latest
rust: beta
Expand All @@ -87,38 +59,12 @@ jobs:
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
- name: Install and configure Cross
if: matrix.os == 'ubuntu-latest' && matrix.target != ''
run: |
# In the past, new releases of 'cross' have broken CI. So for now, we
# pin it. We also use their pre-compiled binary releases because cross
# has over 100 dependencies and takes a bit to compile.
dir="$RUNNER_TEMP/cross-download"
mkdir "$dir"
echo "$dir" >> $GITHUB_PATH
cd "$dir"
curl -LO "https://github.com/cross-rs/cross/releases/download/$CROSS_VERSION/cross-x86_64-unknown-linux-musl.tar.gz"
tar xf cross-x86_64-unknown-linux-musl.tar.gz
# We used to install 'cross' from master, but it kept failing. So now
# we build from a known-good version until 'cross' becomes more stable
# or we find an alternative. Notably, between v0.2.1 and current
# master (2022-06-14), the number of Cross's dependencies has doubled.
echo "CARGO=cross" >> $GITHUB_ENV
echo "TARGET=--target ${{ matrix.target }}" >> $GITHUB_ENV
- name: Show command used for Cargo
run: |
echo "cargo command is: ${{ env.CARGO }}"
echo "target flag is: ${{ env.TARGET }}"
- run: ${{ env.CARGO }} build --verbose $TARGET
- run: ${{ env.CARGO }} doc --verbose $TARGET
- if: matrix.build == 'pinned'
run: ${{ env.CARGO }} test
- if: matrix.build != 'pinned'
run: ${{ env.CARGO }} test --all --verbose $TARGET
- if: matrix.build != 'pinned'
run: ${{ env.CARGO }} test -p jiff-cli --verbose $TARGET
- if: matrix.target == ''
- run: cargo build --verbose
- run: cargo doc --verbose
- run: cargo test --verbose --all
- run: cargo test --verbose -p jiff-cli
# Skip on Windows because it takes freaking forever.
- if: matrix.build != 'win-msvc' && matrix.build != 'win-gnu'
run: ./test

# This job runs a stripped down version of CI to test the MSRV. The specific
Expand Down Expand Up @@ -150,8 +96,44 @@ jobs:
- name: Run integration tests
run: cargo test --test integration

# Setup and run tests on the wasm32-wasi target via wasmtime.
wasm:
# Generic testing for most cross targets. Some get special treatment in
# other jobs.
cross:
env:
# Bump this as appropriate. We pin to a version to make sure CI
# continues to work as cross releases in the past have broken things
# in subtle ways.
CROSS_VERSION: v0.2.5
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
- i686-unknown-linux-gnu
- aarch64-unknown-linux-gnu
- powerpc-unknown-linux-gnu
- powerpc64-unknown-linux-gnu
- s390x-unknown-linux-gnu
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install and configure Cross
run: |
# In the past, new releases of 'cross' have broken CI. So for now, we
# pin it. We also use their pre-compiled binary releases because cross
# has over 100 dependencies and takes a bit to compile.
dir="$RUNNER_TEMP/cross-download"
mkdir "$dir"
echo "$dir" >> $GITHUB_PATH
cd "$dir"
curl -LO "https://github.com/cross-rs/cross/releases/download/$CROSS_VERSION/cross-x86_64-unknown-linux-musl.tar.gz"
tar xf cross-x86_64-unknown-linux-musl.tar.gz
- run: cross build --verbose --target ${{ matrix.target }}
- run: cross test --verbose --target ${{ matrix.target }} --all
- run: cross test --verbose --target ${{ matrix.target }} -p jiff-cli

# Test the wasm32-wasip1 target via wasmtime.
wasm32-wasip1:
runs-on: ubuntu-latest
env:
# The version of wasmtime to download and install.
Expand Down Expand Up @@ -185,6 +167,62 @@ jobs:
- name: Run integration tests
run: cargo test --test integration -- --nocapture

# Test the wasm32-unknown-emscripten target.
#
# Regretably, `insta` doesn't work on emscripten, so we just do a basic
# sanity check here.
wasm32-unknown-emscripten:
runs-on: ubuntu-latest
env:
# Bump this as appropriate. We pin to a version to make sure CI
# continues to work as cross releases in the past have broken things
# in subtle ways.
CROSS_VERSION: v0.2.5
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- name: Install and configure Cross
run: |
dir="$RUNNER_TEMP/cross-download"
mkdir "$dir"
echo "$dir" >> $GITHUB_PATH
cd "$dir"
curl -LO "https://github.com/cross-rs/cross/releases/download/$CROSS_VERSION/cross-x86_64-unknown-linux-musl.tar.gz"
tar xf cross-x86_64-unknown-linux-musl.tar.gz
- name: Build jiff
run: cross build --verbose --target wasm32-unknown-emscripten -p jiff
- name: Build jiff-tzdb
run: cargo build --verbose --target wasm32-unknown-emscripten -p jiff-tzdb
- name: Build jiff-tzdb-platform
run: cargo build --verbose --target wasm32-unknown-emscripten -p jiff-tzdb-platform
- name: Run library tests
run: cross test --verbose --target wasm32-unknown-emscripten --features logging --lib now_works -- --nocapture

# Tests wasm32-unknown-unknown integration via wasm-pack.
wasm32-unknown-uknown:
runs-on: ubuntu-latest
env:
# Set the time zone to something so that there's some kind of interesting
# output to scrutinize. The test below doesn't actually assert anything
# about the time zone, but we can at least visually inspect it in the CI
# logs.
TZ: America/New_York
steps:
- uses: dtolnay/rust-toolchain@stable
- uses: actions/checkout@v4
- name: Install wasm-pack
run: |
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Test wasm-pack project
run: |
cd jiff-wasm
wasm-pack test --node
# Run benchmarks as tests.
testbench:
runs-on: ubuntu-latest
steps:
Expand All @@ -198,6 +236,7 @@ jobs:
run: |
cargo bench --manifest-path bench/Cargo.toml -- --test
# Check that all files are formatted properly.
rustfmt:
runs-on: ubuntu-latest
steps:
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
0.1.3 (2024-07-30)
==================
This release features support for `wasm32-unknown-unknown`. That is, when
Jiff's new `js` crate feature is enabled, Jiff will automatically use
JavaScript APIs to determine the current time and time zone.

Enhancements:

* [#58](https://github.com/BurntSushi/jiff/pull/58):
Add WASM support and a new `PLATFORM.md` guide.


0.1.2 (2024-07-28)
==================
This release features a few new APIs that a need for arose while experimenting
Expand Down
33 changes: 28 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,26 @@ tzdb-bundle-always = ["dep:jiff-tzdb", "alloc"]
# database that is typically found at /usr/share/zoneinfo on macOS and Linux.
tzdb-zoneinfo = ["std"]

# This enables bindings to web browser APIs for retrieving the current time
# and configured time zone. This ONLY applies on wasm32-unknown-unknown and
# wasm64-unknown-unknown targets. Specifically, *not* on wasm32-wasi or
# wasm32-unknown-emscripten targets.
#
# This is an "ecosystem" compromise due to the fact that there is no general
# way to determine at compile time whether a wasm target is intended for use
# on the "web." In practice, only wasm{32,64}-unknown-unknown targets are used
# on the web, but wasm{32,64}-unknown-unknown targets can be used in non-web
# contexts as well. Thus, the `js` feature should be enabled only by binaries,
# tests or benchmarks when it is *known* that the application will be used in a
# web context.
#
# Libraries that depend on Jiff should not need to define their own `js`
# feature just to forward it to Jiff. Instead, application authors can depend
# on Jiff directly and enable the `js` feature themselves.
#
# (This is the same dependency setup that the `getrandom` crate uses.)
js = ["wasm-bindgen", "js-sys"]

[dependencies]
jiff-tzdb = { version = "0.1.0", path = "jiff-tzdb", optional = true }
log = { version = "0.4.21", optional = true }
Expand All @@ -62,8 +82,8 @@ serde = { version = "1.0.203", optional = true }
# Note that the `cfg` gate for the `tzdb-bundle-platform` must repeat the
# target gate on this dependency. The intent is that `tzdb-bundle-platform`
# is enabled by default, but that the `tzdb-bundle-platform` crate is only
# actually used on platforms without a system tzdb (i.e., Windows).
[target.'cfg(windows)'.dependencies]
# actually used on platforms without a system tzdb (i.e., Windows and wasm).
[target.'cfg(any(windows, target_family = "wasm"))'.dependencies]
jiff-tzdb-platform = { version = "0.1.0", path = "jiff-tzdb-platform", optional = true }

[target.'cfg(windows)'.dependencies.windows-sys]
Expand All @@ -72,6 +92,10 @@ default-features = false
features = ["Win32_Foundation", "Win32_System_Time"]
optional = true

[target.'cfg(all(any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dependencies]
js-sys = { version = "0.3.50", optional = true }
wasm-bindgen = { version = "0.2.70", optional = true }

[dev-dependencies]
anyhow = "1.0.81"
chrono = { version = "0.4.38", features = ["serde"] }
Expand All @@ -88,9 +112,8 @@ time = { version = "0.3.36", features = ["local-offset", "macros", "parsing"] }
tzfile = "0.1.3"
walkdir = "2.5.0"

# hifitime doesn't build on wasm32-wasip1 for some reason, so only
# depend on it on Unix or Windows.
[target.'cfg(any(unix, windows))'.dev-dependencies.hifitime]
# hifitime doesn't build on wasm for some reason, so exclude it there.
[target.'cfg(not(target_family = "wasm"))'.dev-dependencies.hifitime]
version = "3.9.0"

[[test]]
Expand Down
6 changes: 6 additions & 0 deletions Cross.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[build.env]
passthrough = [
"TZ",
"RUST_LOG",
"RUST_BACKTRACE",
]
Loading

0 comments on commit a44e494

Please sign in to comment.