Library / SDK
WebAssembly/wasi-libc avatar
WebAssembly/wasi-libc

wasi-libc: a POSIX libc for WebAssembly programs running on WASI

WASI libc implementation for WebAssembly

1,040 stars260 forksCNOASSERTION

At a glance

What is it?
wasi-libc is the C library that lets ordinary C code compile to WebAssembly and run against WASI system calls, providing standard I/O, file and filesystem handling, memory management, time, strings, environment variables and program startup. Its build is a CMake project that emits a sysroot, and its pthread story differs per target, which is the part that surprises people.
Who is it for?
Adopt wasi-libc if you are compiling C to WebAssembly and want a real libc rather than a freestanding program with a handful of imports, and if you are willing to build a sysroot or use wasi-sdk to get one.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A libc layered on system calls, not a freestanding runtime

wasi-libc is described as a libc for WebAssembly programs built on top of WASI system calls, and it provides a wide array of POSIX-compatible C APIs, including support for standard I/O, file I/O, filesystem manipulation, memory management, time, strings, environment variables, program startup and many other APIs. The distinction from a freestanding build matters more than it first appears. A freestanding WebAssembly program gets a linear memory and a set of imported functions, and the programmer writes the runtime. A program linked against wasi-libc gets a `main`, a `printf`, a `fopen` and a `malloc`, with the platform calls underneath provided by WASI. The repository layout shows how the implementation is split, with a `wasi/` directory holding the platform layer, `libc-top-half/` and `libc-bottom-half/` separating the interface from the implementation, the `dlmalloc/` and `emmalloc/` allocators, and `fts/` for the file traversal support the API needs.

Stable enough to use, still moving

The README's own status line is measured and worth quoting in substance, that wasi-libc is sufficiently stable and usable for many purposes since most of the POSIX-compatible APIs are stable, though it is continuing to evolve to better align with wasm and WASI. That is a useful distinction for an adopter, because the POSIX surface you depend on is not going to move underneath you, while the platform integration underneath it will. The specific example given is pthread support, which is provided experimentally via the wasi-threads proposal. The direction of travel is also visible in the targets the build supports, with `wasm32-wasip1`, `wasm32-wasip2` and `wasm32-wasip1-threads` listed as the target triples, and the newer `wasm32-wasip3` appearing in the threading section. In other words the library tracks the evolving WASI specification rather than freezing on one version of it, which is the right call for an infrastructure project and the reason the sysroot gets rebuilt.

Building a sysroot with CMake

The README recommends using wasi-sdk, which includes a build of wasi-libc in its sysroot, as the easiest way to get started. Building from source needs a WebAssembly-supporting C compiler, and the README is direct that this is currently only clang 10 or later, with a note that they would like to support other compilers as well. The build is configured with a standard CMake invocation, and the generator can be chosen with the `-G` argument, for example Ninja.

sh
cmake -S . -B build
cd build && make -j$(nproc)

The configuration options are the interesting part, because they are the knobs a target platform cares about. You pick the compiler and the archiver with `-DCMAKE_C_COMPILER` and `-DCMAKE_AR`, the install location with `-DCMAKE_INSTALL_PREFIX`, the target with `-DTARGET_TRIPLE` and the allocator with `-DMALLOC`, where the choices are dlmalloc, emmalloc or none. The remaining options tune behaviour, with `-DBULK_MEMORY_THRESHOLD` for the bulk memory copying functions, `-DSETJMP` to build libsetjmp, `-DBUILD_TESTS`, `-DSIMD` to enable the SIMD related string routines, and `-DBUILD_SHARED` to force shared library building on or off. After the build, the install target places the sysroot where the `-DCMAKE_INSTALL_PREFIX` pointed, and that directory is then passed to the compiler with `--sysroot`.

The missing compiler-rt library, and the error it produces

There is one failure mode the README spends a paragraph on, because it catches people out. Clang packages typically do not include cross-compiled builds of compiler-rt, libcxx or libcxxabi, which are the WebAssembly equivalents of `libclang_rt.builtins-wasm32.a`, `libc++.a` and `libc++abi.a`. That means passing `--sysroot` alone may not be enough, because Clang will also look for some of those libraries by default. The README says this is one of the things wasi-sdk simplifies, since it includes cross-compiled builds of compiler-rt, libc++ and libc++abi. The build of wasi-libc itself depends on compiler-rt, and that dependency shows up as an error message such as `undefined symbol: __muloti4`, where the position independent code build of wasi-libc requires Clang to be able to locate `libclang_rt.builtins-wasm32.a`, so `libc.so` requires that library to be present. It is downloaded automatically as part of the build, and it can also be pointed at manually with the `-DBUILTINS_LIB` option.

Three different answers to the same pthread question

All targets in wasi-libc define the `pthread_*` related symbols, but what those symbols do depends on the target, and the README spells out each case. On `wasm32-wasip1` and `wasm32-wasip2` the symbols return an error or trap as appropriate, so spawning a thread returns an error and blocking on a condition variable traps, because it cannot possibly be woken. On `wasm32-wasip1-threads` spawning uses the now largely deprecated wasi-threads proposal, and blocking uses the WebAssembly `memory.atomic.*` instructions. On `wasm32-wasip3` the behaviour matches the first pair by default, but when wasi-libc is built with `-DENABLE_COOP_THREADS=ON` it uses the cooperative multithreading intrinsics of the component model, in which all the `pthread_*` symbols are implemented and work as expected, with scheduling implemented through cooperative switches, that is explicit yields or the synchronisation points in the pthread primitives. The README points at the wasi-sdk documentation on cooperative threading for how to use a pre-built copy and avoid building a sysroot at all.

The tree, the licence files and the packaging

The repository root is compact and tells you what is in the box. There is the `wasi/` platform directory, the two halves of the library implementation, the two allocators, `fts/`, a `cmake/` directory, a `tools/` directory, a `test/` directory with an `expected/` directory beside it that presumably holds the expected outputs, and a `linker-provided-symbols.txt` that records the symbols the linker supplies rather than the library. The licence situation is expressed as four files, a `LICENSE` alongside `LICENSE-APACHE`, `LICENSE-APACHE-LLVM` and `LICENSE-MIT`, which is the normal arrangement for code that mixes upstream-derived and original parts. The project also has a `CODE_OF_CONDUCT.md` and a `.gitmodules` file, since some of the sources are pulled in as submodules. For distribution, the README points at an official Arch Linux package that tracks the repository, and at the wasi.dev site as the entry point for WASI itself, with the wasi-sdk repository and the Arch package for other WASI related packages.

A mature codebase with a thin release history

The last push was on 2026-10-01, so the code is being maintained, but the release history in the repository is a single tag, v0.1-alpha with the description compiled sysroot, from March 2019. That is not a contradiction. A sysroot is a build artefact consumed by a toolchain, and the wasi-sdk project bundles a build of wasi-libc in its sysroot. The practical consequence is that you should not look for a wasi-libc version to pin in the way you would pin a library, and you should take the sysroot from wasi-sdk unless you have a reason to build your own, which the README agrees with by recommending exactly that. The reasons to build your own are narrow, and they are the ones the README lists, a target triple that wasi-sdk does not ship, a different allocator, or SIMD string routines turned on or off.

Editorial conclusion

Adopt wasi-libc if you are compiling C to WebAssembly and want a real libc rather than a freestanding program with a handful of imports, and if you are willing to build a sysroot or use wasi-sdk to get one. Do not adopt it if your program needs real POSIX threads today, because the README is explicit that the pthread behaviour differs by target, with the plain WASI targets returning an error or trapping, and with true support only arriving through the cooperative threading intrinsics of the component model. Before you build, make sure your clang can find the WebAssembly builtins library, because a missing `libclang_rt.builtins-wasm32.a` shows up as an undefined symbol error such as `__muloti4` and is the most common way this build fails. The licence set is Apache, Apache with LLVM exceptions and MIT, the last push was on 2026-10-01, and the repository publishes a single release tag from 2019.

Frequently asked questions

What is wasi-libc and what does it provide?

It is a libc for WebAssembly programs built on top of WASI system calls, providing POSIX-compatible C APIs including standard I/O, file I/O, filesystem manipulation, memory management, time, strings, environment variables and program startup, with the platform layer in the `wasi/` directory and the implementation split between the top and bottom halves.

How do I build wasi-libc from source?

You need a WebAssembly-supporting C compiler, currently clang 10 or later. Configure with `cmake -S . -B build`, optionally with a generator such as Ninja, build with `make -j$(nproc)`, and install with the install target into the directory given by `-DCMAKE_INSTALL_PREFIX`. The sysroot is then passed to the compiler with `--sysroot`.

Why does building wasi-libc fail with an undefined symbol such as __muloti4?

Because the build depends on compiler-rt. Clang packages typically do not include cross-compiled builds of `libclang_rt.builtins-wasm32.a`, `libc++.a` and `libc++abi.a`, so the position independent code build of wasi-libc cannot resolve it. The library is downloaded automatically during the build, or you can point at it with `-DBUILTINS_LIB`.

Does wasi-libc support threads?

All targets define the `pthread_*` symbols but behave differently. The plain `wasm32-wasip1` and `wasm32-wasip2` targets return an error or trap, `wasm32-wasip1-threads` uses the largely deprecated wasi-threads proposal with the `memory.atomic.*` instructions, and `wasm32-wasip3` behaves like the first pair unless built with `-DENABLE_COOP_THREADS=ON`, which uses the component model's cooperative threading intrinsics so the pthread APIs work with cooperative scheduling.

Official sources

  1. Issues
  2. Project website
  3. README
  4. Releases
  5. WebAssembly/wasi-libc on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/webassembly-wasi-libc.svg)](https://hysenlabs.com/projects/webassembly-wasi-libc)

Was this useful?