WebAssembly (Wasm) arch support for the Linux kernel
1,228
stars
43
commits
JavaScript
primary language
May 14, 2026
updated
This project contains scripts to download, build and run a Linux system that can be executed on the web, using native WebAssembly (Wasm).
These scripts can be run in the following way:
The initial release of this Wasm port was made by me, Joel. After the release I got into contact with Tom, who had also been working on an independent Wasm port, even during the same time frame as me. You should check out Tom's port at https://github.com/tombl/linux . We have both arrived at very similar solutions, sometimes even eerily similar, but there are also some important differences in detail. Both ports were based on early 6.x-era kernels and I've since worked on trying to pick the best parts out of both and rebase on Linux 7.0. This is still work in progress but it has the basics and is now the default build target of this repo. Important parts that are in Tom's port that have not been added yet are virtio and device tree support. However, the 7.0 release does see 64-bit kernel support (the user space part for this is still quite experimental, the kernel part seems to work quite well). On top of this, the 7.0 release sees quite a few bug fixes and can now build allnoconfig and allyesconfig. All kunit tests also pass for both wasm32 and wasm64 (you may see a few spurious errors for tests that completely hog the CPU in kernel mode and timeout).
Apart from bug fixes and improvements, this is in the pipeline:
The project is built and assembled from the following pieces of software:
Hint: MVP Wasm lacks an MMU (edit: now available as an early proposal), meaning that Linux needs to be built in a NOMMU configuration. Wasm programs thus need to be built using -fPIC/-shared. Alternatively, existing Wasm programs can run together with a proxy that does syscalls towards the kernel. In such a case, each thread that wishes to independently execute syscalls should map to a thread in the proxy. The drawback of such an approach is that memory cannot be mapped and shared between processes. However, from a memory protection standpoint, this property could also be beneficial.
Run ./linux-wasm.sh to see usage. Downloads happen first, building afterwards. You may partially select what to download or (re)-build.
Due to a bug in LLVM's build system, building LLVM a second time fails when building runtimes (complaining that clang fails to build a simple test program). A workaround is to build it yet again (it works each other time, i.e. the 1st, 3rd, 5th etc. time).
Due to limitations in the Linux kernel's build system, the absolute path of the cross compiler (install path of LLVM) cannot contain spaces. Since LLVM is built by linux-wasm.sh, it more or less means its workspace directory (or at least install directory) has to be in a space-free path.
linux-wasm.sh takes some environment variables that affect its inner workings. Refer to the source for a full list. You do not need to set any of these, they will default to sane defaults.
# A path (relative or absolute) to where everything ends up. The default is a directory workspace/ in the repo root. Not used directly but derives LW_SRC (downloads), LW_BUILD (build files) and LW_INSTALL (final artifacts). For maximum flexibility, LW_SRC/LW_BUILD/LW_INSTALL can be set directly instead.
# Examples: my_workspace, workspaces/my_workspace, /absolute/path
LW_WORKSPACE=
# Currently supports wasm32_nommu and wasm64_nommu.
LW_VARIANT=
# One of:
# (empty) - Default: build the Wasm-default defconfig.
# rebuild - Re-create the Wasm-default defconfig (for developers).
# dev - Development config (WERROR=y is added).
# yes - allyesconfig (every kernel feature enabled, WERROR=y already default).
# no - allnoconfig (very minimal build, WERROR=y is added for convenience).
# ubsan - Find undefined behavior in kernel code.
# kunit - Build and run KUnit tests at boot.
LW_KERNEL_CONFIG=
# If set to exactly 1, open menuconfig. NOTE: linux-wasm.sh always overwrites the config according to LW_KERNEL_CONFIG first, on every run. Thus, any changes must be saved before re-running. See how LW_KERNEL_CONFIG=rebuild works to see how you may want to save it. You may want to add special case if you really want to work with a fragile full .config file. Any real changes should modify base.config or $LW_ARCH.config instead to allow the automatic generation of defconfigs.
LW_KERNEL_MENUCONFIG=
# Build parallelism:
LW_JOBS_LLVM_LINK
LW_JOBS_LLVM_COMPILE
LW_JOBS_KERNEL_COMPILE
LW_JOBS_MUSL_COMPILE
LW_JOBS_BUSYBOX_COMPILE
The following commands should be executed in this repo root.
There are two containers:
Create the containers:
docker build -t linux-wasm-base:dev ./docker/linux-wasm-base
docker build -t linux-wasm-contained:dev -f ./docker/linux-wasm-contained/Dockerfile .
Note that the latter command will copy linux-wasm.sh, in its current state, into the container.
To launch a simple docker container with a mapping to host (recommended for development):
docker run -it --name my-linux-wasm --mount type=bind,src="$(pwd)",target=/linux-wasm linux-wasm-base:dev bash
(Inside the bash prompt, run for example:) /linux-wasm/linux-wasm.sh all
To actually build everything inside the container (mostly useful for build servers):
docker run -it --name full-linux-wasm linux-wasm-contained:dev /linux-wasm/linux-wasm.sh all
To change workspace folder, docker run -e LW_WORKSPACE=/path/to/workspace ...blah... can be used. This may be useful together with docker volumes.
Hacker News (1)
JavaScript
46.9%
Shell
24.8%
Python
11.6%
CSS
8.4%
HTML
6.7%
Dockerfile
1.6%
WebAssembly (Wasm) arch support for the Linux kernel
1,228
stars
43
commits
JavaScript
primary language
May 14, 2026
updated
This project contains scripts to download, build and run a Linux system that can be executed on the web, using native WebAssembly (Wasm).
These scripts can be run in the following way:
The initial release of this Wasm port was made by me, Joel. After the release I got into contact with Tom, who had also been working on an independent Wasm port, even during the same time frame as me. You should check out Tom's port at https://github.com/tombl/linux . We have both arrived at very similar solutions, sometimes even eerily similar, but there are also some important differences in detail. Both ports were based on early 6.x-era kernels and I've since worked on trying to pick the best parts out of both and rebase on Linux 7.0. This is still work in progress but it has the basics and is now the default build target of this repo. Important parts that are in Tom's port that have not been added yet are virtio and device tree support. However, the 7.0 release does see 64-bit kernel support (the user space part for this is still quite experimental, the kernel part seems to work quite well). On top of this, the 7.0 release sees quite a few bug fixes and can now build allnoconfig and allyesconfig. All kunit tests also pass for both wasm32 and wasm64 (you may see a few spurious errors for tests that completely hog the CPU in kernel mode and timeout).
Apart from bug fixes and improvements, this is in the pipeline:
The project is built and assembled from the following pieces of software:
Hint: MVP Wasm lacks an MMU (edit: now available as an early proposal), meaning that Linux needs to be built in a NOMMU configuration. Wasm programs thus need to be built using -fPIC/-shared. Alternatively, existing Wasm programs can run together with a proxy that does syscalls towards the kernel. In such a case, each thread that wishes to independently execute syscalls should map to a thread in the proxy. The drawback of such an approach is that memory cannot be mapped and shared between processes. However, from a memory protection standpoint, this property could also be beneficial.
Run ./linux-wasm.sh to see usage. Downloads happen first, building afterwards. You may partially select what to download or (re)-build.
Due to a bug in LLVM's build system, building LLVM a second time fails when building runtimes (complaining that clang fails to build a simple test program). A workaround is to build it yet again (it works each other time, i.e. the 1st, 3rd, 5th etc. time).
Due to limitations in the Linux kernel's build system, the absolute path of the cross compiler (install path of LLVM) cannot contain spaces. Since LLVM is built by linux-wasm.sh, it more or less means its workspace directory (or at least install directory) has to be in a space-free path.
linux-wasm.sh takes some environment variables that affect its inner workings. Refer to the source for a full list. You do not need to set any of these, they will default to sane defaults.
# A path (relative or absolute) to where everything ends up. The default is a directory workspace/ in the repo root. Not used directly but derives LW_SRC (downloads), LW_BUILD (build files) and LW_INSTALL (final artifacts). For maximum flexibility, LW_SRC/LW_BUILD/LW_INSTALL can be set directly instead.
# Examples: my_workspace, workspaces/my_workspace, /absolute/path
LW_WORKSPACE=
# Currently supports wasm32_nommu and wasm64_nommu.
LW_VARIANT=
# One of:
# (empty) - Default: build the Wasm-default defconfig.
# rebuild - Re-create the Wasm-default defconfig (for developers).
# dev - Development config (WERROR=y is added).
# yes - allyesconfig (every kernel feature enabled, WERROR=y already default).
# no - allnoconfig (very minimal build, WERROR=y is added for convenience).
# ubsan - Find undefined behavior in kernel code.
# kunit - Build and run KUnit tests at boot.
LW_KERNEL_CONFIG=
# If set to exactly 1, open menuconfig. NOTE: linux-wasm.sh always overwrites the config according to LW_KERNEL_CONFIG first, on every run. Thus, any changes must be saved before re-running. See how LW_KERNEL_CONFIG=rebuild works to see how you may want to save it. You may want to add special case if you really want to work with a fragile full .config file. Any real changes should modify base.config or $LW_ARCH.config instead to allow the automatic generation of defconfigs.
LW_KERNEL_MENUCONFIG=
# Build parallelism:
LW_JOBS_LLVM_LINK
LW_JOBS_LLVM_COMPILE
LW_JOBS_KERNEL_COMPILE
LW_JOBS_MUSL_COMPILE
LW_JOBS_BUSYBOX_COMPILE
The following commands should be executed in this repo root.
There are two containers:
Create the containers:
docker build -t linux-wasm-base:dev ./docker/linux-wasm-base
docker build -t linux-wasm-contained:dev -f ./docker/linux-wasm-contained/Dockerfile .
Note that the latter command will copy linux-wasm.sh, in its current state, into the container.
To launch a simple docker container with a mapping to host (recommended for development):
docker run -it --name my-linux-wasm --mount type=bind,src="$(pwd)",target=/linux-wasm linux-wasm-base:dev bash
(Inside the bash prompt, run for example:) /linux-wasm/linux-wasm.sh all
To actually build everything inside the container (mostly useful for build servers):
docker run -it --name full-linux-wasm linux-wasm-contained:dev /linux-wasm/linux-wasm.sh all
To change workspace folder, docker run -e LW_WORKSPACE=/path/to/workspace ...blah... can be used. This may be useful together with docker volumes.
Hacker News (1)
JavaScript
46.9%
Shell
24.8%
Python
11.6%
CSS
8.4%
HTML
6.7%
Dockerfile
1.6%