# Building box2d for wasm32

**URL:** <https://ziggit.dev/t/building-box2d-for-wasm32/9760>\
**Category:** Help\
**Tags:** build-system\
**Created:** [April 22, 2025, 8:02pm UTC](https://ziggit.dev/t/building-box2d-for-wasm32/9760 "2025-04-22T20:02:15Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![danielchooper](https://ziggit.dev/user_avatar/ziggit.dev/danielchooper/32/896_2.png) [@danielchooper](https://ziggit.dev/u/danielchooper)\
**Post date:** [April 22, 2025, 8:02pm UTC](https://ziggit.dev/t/building-box2d-for-wasm32/9760/1 "2025-04-22T20:02:15Z")

</div>

I’m trying to use the [allyourcodebase package of box2d](https://github.com/allyourcodebase/box2d) to build a wasm32 static library that emscripten can link to when building my main project (that is written in C).

this is the command I’m running:

```zig
git clone https://github.com/allyourcodebase/box2d
cd box2d
cat >build.zig <<EOF 
const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const box2d_dep = b.dependency("box2d", .{});

    const lib = b.addStaticLibrary(.{
        .name = "box2d",
        .target = target,
        .optimize = optimize,
    });
    lib.linkLibC();
    lib.addIncludePath(box2d_dep.path("include"));
    lib.installHeadersDirectory(box2d_dep.path("include"), "", .{});
    lib.addCSourceFiles(.{
        .root = box2d_dep.path("src"),
        .flags = &.{
            "-std=c17",
        },
        .files = &.{
            "aabb.c",
            "array.c",
            "bitset.c",
            "body.c",
            "broad_phase.c",
            "constraint_graph.c",
            "contact.c",
            "contact_solver.c",
            "core.c",
            "distance.c",
            "distance_joint.c",
            "dynamic_tree.c",
            "geometry.c",
            "hull.c",
            "id_pool.c",
            "island.c",
            "joint.c",
            "manifold.c",
            "math_functions.c",
            "motor_joint.c",
            "mouse_joint.c",
            "prismatic_joint.c",
            "revolute_joint.c",
            "shape.c",
            "solver.c",
            "solver_set.c",
            "stack_allocator.c",
            "table.c",
            "timer.c",
            "types.c",
            "weld_joint.c",
            "wheel_joint.c",
            "world.c",
        },
    });
    b.installArtifact(lib);
}
EOF
zig build -Dtarget=wasm32-emscripten

```

which produces the error:

```zig
install
└─ install box2d
   └─ zig build-lib box2d Debug wasm32-freestanding 32 errors
/Users/daniel/.cache/zig/p/1220c6750412ebc698694cd08aca4fe87fda8e2df0d4ffa7d33e7de5b8ca5bebb643/include/box2d/math_functions.h:9:10: error: 'math.h' file not found
#include <math.h>
         ^ ~~~~~~~~
/Users/daniel/.cache/zig/p/1220c6750412ebc698694cd08aca4fe87fda8e2df0d4ffa7d33e7de5b8ca5bebb643/src/math_functions.c:4:10: note: in file included from /Users/daniel/.cache/zig/p/1220c6750412ebc698694cd08aca4fe87fda8e2df0d4ffa7d33e7de5b8ca5bebb643/src/math_functions.c:4:
#include "box2d/math_functions.h"

```

Any ideas how to get a wasm32 library built of box2d?

---

<div class="post-metadata">

**Author:** ![marler8997](https://ziggit.dev/user_avatar/ziggit.dev/marler8997/32/77_2.png) [@marler8997](https://ziggit.dev/u/marler8997)\
**Post date:** [April 22, 2025, 8:25pm UTC](https://ziggit.dev/t/building-box2d-for-wasm32/9760/2 "2025-04-22T20:25:40Z")

</div>

I believe Alex is working on a libc for zig that would work in this instance (see [Remove `wasm32-freestanding-musl` by alexrp · Pull Request #22240 · ziglang/zig · GitHub](https://github.com/ziglang/zig/pull/22240)).

I guess there use to be `wasm32-freestanding-musl` which would give access to the musl libc headers, but, it was removed since it was pretty broken.

You could make this work without changes to Zig if you’re up for the task. You can provide your own libc by calling `setLibCFile` on the box2d library. You could hook this up to your own implementation or even my ziglibc project, or just copy code from it if you like. I might be willing to pair with you on this via Discord if you like as well, I have same username on the various zig servers. (we could probably upstream this to the box2d repo as well)

---

<div class="post-metadata">

**Author:** ![Sze](https://ziggit.dev/user_avatar/ziggit.dev/sze/32/496_2.png) [@Sze](https://ziggit.dev/u/Sze)\
**Post date:** [April 22, 2025, 8:53pm UTC](https://ziggit.dev/t/building-box2d-for-wasm32/9760/3 "2025-04-22T20:53:35Z")

</div>

Why do you use `wasm32-freestanding` when you are using emscripten?  
Have you tried using `wasm32-emscripten`?

---

<div class="post-metadata">

**Author:** ![danielchooper](https://ziggit.dev/user_avatar/ziggit.dev/danielchooper/32/896_2.png) [@danielchooper](https://ziggit.dev/u/danielchooper)\
**Post date:** [April 22, 2025, 8:55pm UTC](https://ziggit.dev/t/building-box2d-for-wasm32/9760/4 "2025-04-22T20:55:14Z")

</div>

That doesn’t work either

---

<div class="post-metadata">

**Author:** ![Sze](https://ziggit.dev/user_avatar/ziggit.dev/sze/32/496_2.png) [@Sze](https://ziggit.dev/u/Sze)\
**Post date:** [April 22, 2025, 9:01pm UTC](https://ziggit.dev/t/building-box2d-for-wasm32/9760/5 "2025-04-22T21:01:25Z")

</div>

Have you specified the `--sysroot` include to the emscripten sysroot?  
In what way does it fail, what are the error messages?

For this game I had to manually add the sysroot include folder to the include pathes so that zig finds the header files for things like `math.h` when compiling for `wasm32-emscripten`: [zig15game/build.zig at 5d0a33d753528df890f0ab5dd56cd04ff6d0e1c2 · SimonLSchlee/zig15game · GitHub](https://github.com/SimonLSchlee/zig15game/blob/5d0a33d753528df890f0ab5dd56cd04ff6d0e1c2/build.zig#L100)

My guess would be that some similar variation could work for a library, that is linked later.

---

<div class="post-metadata">

**Author:** ![danielchooper](https://ziggit.dev/user_avatar/ziggit.dev/danielchooper/32/896_2.png) [@danielchooper](https://ziggit.dev/u/danielchooper)\
**Post date:** [April 22, 2025, 9:12pm UTC](https://ziggit.dev/t/building-box2d-for-wasm32/9760/6 "2025-04-22T21:12:51Z")

</div>

Here is the exact command I’m running so you can give it a try:

```zig
git clone https://github.com/allyourcodebase/box2d
cd box2d
cat >build.zig <<EOF 
const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const box2d_dep = b.dependency("box2d", .{});

    const lib = b.addStaticLibrary(.{
        .name = "box2d",
        .target = target,
        .optimize = optimize,
    });
    lib.linkLibC();
    lib.addIncludePath(box2d_dep.path("include"));
    lib.installHeadersDirectory(box2d_dep.path("include"), "", .{});
    lib.addCSourceFiles(.{
        .root = box2d_dep.path("src"),
        .flags = &.{
            "-std=c17",
        },
        .files = &.{
            "aabb.c",
            "array.c",
            "bitset.c",
            "body.c",
            "broad_phase.c",
            "constraint_graph.c",
            "contact.c",
            "contact_solver.c",
            "core.c",
            "distance.c",
            "distance_joint.c",
            "dynamic_tree.c",
            "geometry.c",
            "hull.c",
            "id_pool.c",
            "island.c",
            "joint.c",
            "manifold.c",
            "math_functions.c",
            "motor_joint.c",
            "mouse_joint.c",
            "prismatic_joint.c",
            "revolute_joint.c",
            "shape.c",
            "solver.c",
            "solver_set.c",
            "stack_allocator.c",
            "table.c",
            "timer.c",
            "types.c",
            "weld_joint.c",
            "wheel_joint.c",
            "world.c",
        },
    });
    b.installArtifact(lib);
}
EOF
zig build -Dtarget=wasm32-emscripten

```

and the first error I get:

```zig
/Users/daniel/.cache/zig/p/1220c6750412ebc698694cd08aca4fe87fda8e2df0d4ffa7d33e7de5b8ca5bebb643/include/box2d/math_functions.h:9:10: error: 'math.h' file not found
#include <math.h>
         ^ ~~~~~~~~
/Users/daniel/.cache/zig/p/1220c6750412ebc698694cd08aca4fe87fda8e2df0d4ffa7d33e7de5b8ca5bebb643/src/table.c:6:10: note: in file included from /Users/daniel/.cache/zig/p/1220c6750412ebc698694cd08aca4fe87fda8e2df0d4ffa7d33e7de5b8ca5bebb643/src/table.c:6:
#include "core.h"
         ^
/Users/daniel/.cache/zig/p/1220c6750412ebc698694cd08aca4fe87fda8e2df0d4ffa7d33e7de5b8ca5bebb643/src/core.h:6:10: note: in file included from /Users/daniel/.cache/zig/p/1220c6750412ebc698694cd08aca4fe87fda8e2df0d4ffa7d33e7de5b8ca5bebb643/src/core.h:6:
#include "box2d/math_functions.h"
         ^

```

---

<div class="post-metadata">

**Author:** ![whitehexagon](https://ziggit.dev/user_avatar/ziggit.dev/whitehexagon/32/5917_2.png) [@whitehexagon](https://ziggit.dev/u/whitehexagon)\
**Post date:** [April 23, 2025, 4:13pm UTC](https://ziggit.dev/t/building-box2d-for-wasm32/9760/7 "2025-04-23T16:13:01Z")

</div>

I’ve hit the same regression porting my project from 0.8.1 to ‘0.14.0-dev.3217+5b9b5e45c’ whilst building LVGL for freestanding wasm.  
The only hack I’ve found so far is to reference the linux C headers (in my case Asahi) directly.

`wasm_lib.addIncludePath(b.path("../../../../../usr/include"));`

Referencing the headers with an absolute path caused an error something about not being allowed to reference stuff above the build folder. I cant check exactly what the errors are, because today I’m getting some strange ‘failed to check cache’ error.

However I think the above hack works because in the case of LVGL the C dependencies are probably resolved via macros in the headers, ie simple std and string stuff.

---

<div class="post-metadata">

**Author:** ![floooh](https://ziggit.dev/user_avatar/ziggit.dev/floooh/32/2989_2.png) [@floooh](https://ziggit.dev/u/floooh)\
**Post date:** [April 23, 2025, 5:12pm UTC](https://ziggit.dev/t/building-box2d-for-wasm32/9760/8 "2025-04-23T17:12:10Z")

</div>

I’ve encountered that problem too in my WASM Zig experiments - I guess Zig simply doesn’t have any C library support for wasm32-emscripten and wasm32-freestanding (wasm32-wasi works fine).

Since I’m depending on the Emscripten SDK anyway for linking and Emscripten-specific APIs, I basically use the Emsdk as a complete C sysroot and inject the Emscripten system include path into the C code that’s compiled via Zig, e.g.:

> <https://github.com/floooh/sokol-zig/blob/8e2583ffe758a27a1a156a14347a75b8126828d1/build.zig#L179-L180>

~~…and since include paths propagate through the dependency tree, other C dependencies just need to depend on the sokol C library to find the Emscripten C headers.~~

…oops I might have been wrong on that propagation thing… because this is how I inject the Emscripten sysroot into other C dependencies:

> <https://github.com/floooh/sokol-zig-imgui-sample/blob/6c0d1313a84ede2849c6172cbe52c48b9b047db8/build.zig#L65-L69>

---

<div class="post-metadata">

**Author:** ![castholm](https://ziggit.dev/user_avatar/ziggit.dev/castholm/32/1330_2.png) [@castholm](https://ziggit.dev/u/castholm)\
**Post date:** [April 23, 2025, 6:09pm UTC](https://ziggit.dev/t/building-box2d-for-wasm32/9760/9 "2025-04-23T18:09:21Z")

</div>

The only Wasm target Zig provides a libc for is `wasm32-wasi-musl` (it used to claim to support `wasm32-freestanding-musl` but this never really worked in practice). For all other targets you have to explicitly supply the headers yourself and make sure they are added to the header search paths.

For Emscripten specifically the headers are located in the `sysroot/include` subpath of the Emscripten cache, which you can print the path to by running `em-config CACHE`. If you don’t want to hard-code the path I suggest using `b.sysroot` and requiring the user invoking `zig build` to explicitly provide a sysroot by passing `--sysroot "$(em-config CACHE)/sysroot"`.

```zig
var emscripten_system_include_path: ?std.Build.LazyPath = null;
switch (target.result.os.tag) {
    .emscripten => {
        if (b.sysroot) |sysroot| {
            emscripten_system_include_path = .{ .cwd_relative = b.pathJoin(&.{ sysroot, "include" }) };
        } else {
            std.log.err("'--sysroot' is required when building for Emscripten", .{});
            std.process.exit(1);
        }
    },
    else => {},
}

// ...

if (emscripten_system_include_path) |path| {
    lib.addSystemIncludePath(path);
}

```

One caveat is that there’s unfortunately no catch-all way to add default header search paths for all artifacts (including those from dependencies), meaning that any packages you depend on will also need to explicitly handle `--sysroot` the same way in their build.zig files.

This should be enough to build Box2D. If you get errors like `error: call to undeclared function 'clock_gettime'` it’s because `-std=c17` is disabling non-standards compliant features. Changing it to `-std=gnu17` should fix it.

---

<div class="post-metadata">

**Author:** ![danielchooper](https://ziggit.dev/user_avatar/ziggit.dev/danielchooper/32/896_2.png) [@danielchooper](https://ziggit.dev/u/danielchooper)\
**Post date:** [May 16, 2025, 10:30pm UTC](https://ziggit.dev/t/building-box2d-for-wasm32/9760/10 "2025-05-16T22:30:00Z")

</div>

I was finally able to get zig to compile box2d for `wasm32-emscripten` using:

```sh
BOX2D_PATH=$HOME/box2d-3.1.0
BOX2D_SRC_FILES=($BOX2D_PATH/src/*.c(N))
zig build-lib $BOX2D_SRC_FILES \
-DBOX2D_DISABLE_SIMD \
-cflags -std=c17 -mbulk-memory -matomics -msimd128 -msse2 -- \
-I$BOX2D_PATH/include \
-lc -OReleaseFast --name box2d -static \
-target wasm32-emscripten -mcpu baseline \
-isystem $EMSDK/upstream/emscripten/cache/sysroot/include

```

The `-DBOX2D_DISABLE_SIMD` is required because it seems like zig’s SIMD headers don’t support wasm32?:

```zig
zig-macos-aarch64-0.13.0/lib/include/emmintrin.h:14:2: 
error: "This header is only meant to be used on x86 and x64 architecture"

box2d-3.1.0/src/contact_solver.c:527:10: note: in file included from box2d-3.1.0/src/contact_solver.c:527:
#include <emmintrin.h>

```

emcc is able to compile box2d with simd enabled.

```make
BOX2D_OBJ_FILES := $(notdir $(BOX2D_SRC_FILES:.c=.o))
emcc-box2d:
    emcc -mbulk-memory -matomics -msimd128 -msse2 -I$(BOX2D_PATH)/include -c $(BOX2D_SRC_FILES) && \
    emar qc libbox2d.a $(BOX2D_OBJ_FILES) && \
    emranlib libbox2d.a

```

If anyone knows how to compile SIMD for wasm32-emscripten, I’d appreciate your advice!

---

<div class="post-metadata">

**Author:** ![floooh](https://ziggit.dev/user_avatar/ziggit.dev/floooh/32/2989_2.png) [@floooh](https://ziggit.dev/u/floooh)\
**Post date:** [May 21, 2025, 12:18pm UTC](https://ziggit.dev/t/building-box2d-for-wasm32/9760/11 "2025-05-21T12:18:59Z")

</div>

Following the bread crumb trail (Box2D source code and Emscripten docs), you seem to do everything right (e.g. `-msimd128 -msse2` should do the right thing and allow Emscripten - or rather Clang/‘zig-cc’ to compile code that includes `emmintrin.h`).

_But_ this looks wrong:

`zig-macos-aarch64-0.13.0/lib/include/emmintrin.h`

~~…here the code uses a macOS include instead of an Emscripten include.~~ =\> also wrong assumption, see @alexrp’s comment below - I think it’s still the wrong header though.

~~AFAIK `-isystem` isn’t enough to redirect system includes to the Emscripten toolchain, you’ll also explicitly need to pass a regular header search path via `-I $EMSDK/upstream/emscripten/cache/sysroot/include`… or maybe `-isystem $EMSDK/upstream/emscripten/cache/sysroot/include`~~

…disregard the above, somehow my mind was confusing `-isystem` with `-isysroot`… so the `-isystem` is already pointing to the Emscripten headers, however:

The `emmintrin.h` header seems to be under `.../include/compat/` in the Emscripten sysroot cache, so maybe you also need to add another search path that includes the `compat/` subdir.

PS: it’s also weird that Zig seems to fallback to the ~~macOS~~ zig toolchain headers when compiling with `-target wasm32-emscripten`, not sure if this is a Zig bug or inherited from Clang. I would actually expect a compiler error that `emmintrin.h` cannot be found (since it is in the `compat/` subdir in the Emscripten SDK.

---

<div class="post-metadata">

**Author:** ![alexrp](https://ziggit.dev/user_avatar/ziggit.dev/alexrp/32/2793_2.png) [@alexrp](https://ziggit.dev/u/alexrp)\
**Post date:** [May 21, 2025, 1:55pm UTC](https://ziggit.dev/t/building-box2d-for-wasm32/9760/12 "2025-05-21T13:55:12Z")

</div>

Here, `zig-macos-aarch64-0.13.0` is the name of the directory containing the `zig` binary, not the location of the macOS headers. That would be `zig-macos-aarch64-0.13.0/lib/libc/include/any-macos-any`.

---

<div class="post-metadata">

**Author:** ![floooh](https://ziggit.dev/user_avatar/ziggit.dev/floooh/32/2989_2.png) [@floooh](https://ziggit.dev/u/floooh)\
**Post date:** [May 21, 2025, 2:50pm UTC](https://ziggit.dev/t/building-box2d-for-wasm32/9760/13 "2025-05-21T14:50:25Z")

</div>

> [@alexrp](#):
>
> Here, `zig-macos-aarch64-0.13.0` is the name of the directory containing the `zig` binary, not the location of the macOS headers.

…ah ok, it still looks wrong to me though, I think when compiling for wasm32-emscripten it needs to pick the emmintrin.h header from the Emscripten SDK, because that uses wasm-specific SIMD intrinsics for ‘emulation’:

> <https://github.com/emscripten-core/emscripten/blob/main/system/include/compat/emmintrin.h>

…while the header in the Zig toolchain indeed requires x86:

> <https://github.com/ziglang/zig/blob/master/lib/include/emmintrin.h>

(tbf: Emscripten providing a header which emulates x86 intrinsics on WASM is kinda ‘special’ for cross-compiling)
