A from-scratch C library for WebAssembly. The name comes from Gary Bernhardt's The Birth & Death of JavaScript — a vision of "metal" web applications running at near-native speed. Metallic aims to be the runtime for that world.
# Build the libraries (requires clang with the wasm32 target and llvm-link).
make
# Run the included hello-world example under wasmtime.
cd examples/hello && make run
Metallic builds to a single static archive, metallic.a, that calls
WASI snapshot_preview1 directly. Programs link it like any other library:
clang --target=wasm32-unknown-unknown-wasm -nostdlib \
-I include main.c metallic.a -o app.out
Host I/O lives in src/wasi/wasi.h, where each binding
carries the import_module("wasi_snapshot_preview1") attribute so the
linker emits them as wasm imports without needing --allow-undefined.
Implemented C11 hosted-environment headers:
<assert.h><complex.h><ctype.h><errno.h><fenv.h><float.h><inttypes.h><iso646.h><limits.h><locale.h><math.h><setjmp.h><signal.h><stdalign.h><stdarg.h><stdbool.h><stddef.h><stdint.h><stdio.h><stdlib.h><stdnoreturn.h><string.h><tgmath.h><time.h><uchar.h><wchar.h><wctype.h>
Opted out via __STDC_NO_THREADS__: <threads.h> is intentionally not
shipped. <stdatomic.h> comes from clang's freestanding headers and
lowers to plain operations on single-threaded WASI.
Correct rounding is the math library's goal, and every real float and double
transcendental now reaches it (the complex functions are composed from those
kernels and inherit their accuracy).
A function is correctly rounded when its result is the true value rounded to
the nearest representable number (error ≤ 0.5 ulp); faithfully rounded is the
weaker guarantee of one of the two nearest (error < 1 ulp). For float, correct
rounding is proven by an exhaustive sweep of all 2³² bit patterns against an
MPFR or CORE-MATH oracle; for double it is strong evidence from a sampler that
hammers the published hard-to-round cases plus a broad random sample. See
test/oracle/ and make check.oracle (native; not part of the wasm CI gate).
float, correctly rounded (≤ 0.5 ulp). Unary, proven by exhaustive sweep:expfexp2fexpm1flogflog2flog10flog1pfsinfcosftanfasinfacosfatanfasinhfacoshfatanhfsinhfcoshftanhfcbrtferfferfcflgammaftgammaf. Bivariate (sampler evidence, since the 2⁶⁴ domain cannot be swept):atan2fhypotfpowf.double, correctly rounded (≤ 0.5 ulp), sampler evidence. Unary:expexp2expm1loglog2log10log1psincostanasinacosatanasinhacoshatanhsinhcoshtanhcbrterferfclgammatgamma. Bivariate (sampler evidence, since the 2⁶⁴ domain cannot be swept):atan2hypotpow.- Complex
float, correctly rounded (≤ 0.5 ulp per part), sampler evidence. Each of the real and imaginary parts is the correctly-roundedfloatof the exact value (the 2⁶⁴ domain cannot be swept, so this is a random + near-axis MPFR sampler, as for the bivariate floats):cabsfcargfcsqrtfcexpfclogf. Seetest/oracle/math/float/complex/andmake check.oracle.complex. The remaining complexfloatfunctions (the trig/hyperbolic and inverse families,cpowf) are still composed from the real kernels and faithful. - Complex
double(cabs,cexp,clog,csqrt, the trig/hyperbolic families, …) is composed from the real kernels and inherits their accuracy.
longjmpaborts the process. WebAssembly has no native stack unwinding; programs that need real setjmp/longjmp should compile with clang's-mllvm -wasm-enable-sjlj, which lowerssetjmp/longjmpto clang intrinsics and bypasses libc.signal/raisetrack handlers but do not asynchronously dispatch — WASI preview1 delivers no signals.raise(SIGABRT)is correctly routed.localtimealiasesgmtime— WASI preview1 has no timezone info.- Only the
Clocale is supported. - No threads.
__STDC_NO_THREADS__is predefined, so<threads.h>is absent and feature-test code routes around the C11 thread API. Atomics use clang's freestanding<stdatomic.h>; on single-threaded WASI they lower to plain loads and stores.
make check.native— native tests (some pre-existing math accuracy failures against the host libm).make check.wasm.fast— wasm tests underwasmtime, excluding the 11 pre-existing soft-float/integer/long-double failures. CI runs this.make check.wasm— full wasm suite including the known-broken tests.
If wasmtime is installed but not on PATH (for example via
$HOME/.wasmtime/bin/wasmtime), the Makefile will use that location
automatically. You can also select another runner explicitly:
make WASMRUN=/path/to/wasmtime check.wasm.fast
11 pre-existing test failures in the soft-float / 128-bit integer / long-double
sqrt code paths. These are not regressions and are excluded from
check.wasm.fast. See Makefile KNOWN_BROKEN_WASM.
This was originally Chen-Pang He's libc-for-WebAssembly experiment. Revival work brought it up to a hosted C11 + WASI snapshot_preview1 runtime; the math kernels predate the revival.
See LICENSE.