Build locally, run on brintOS
The end-to-end loop: build the toolchain once, compile your program, mount a machine's drive over the network with the FUSE client, drop the binary onto it, then launch the machine in your browser and run it on brintos.io.
.wasm file. It must be produced
by the brintOS toolchain (hwjs-cc), which emits a small versioned
header in a custom wasm section so the kernel can execve it. A binary built with Emscripten
or wasi-libc will not run on a brintOS machine.Prerequisites
You need the brintOS toolchain installed: the pinned LLVM, the HwjsCoroutinize pass
and the wasmcc/wasmld drivers on your PATH, and our musl
built into a sysroot. If you haven't done that yet, work through Install the toolchain first (all three steps — packages need
the musl sysroot), then come back here.
1. Compile your package
wasmcc is a drop-in replacement for cc: it targets wasm32,
links the musl from your sysroot, runs the HwjsCoroutinize pass, and attaches the binfmt_wasm header. Start with a hello-world:
cat > hello.c <<'EOF'
#include <stdio.h>
int main(void) {
printf("hello from a brintOS package\n");
return 0;
}
EOF
# Compile to a wasm-native Linux executable.
# WASMLD_HWJS=1 selects the coroutinizing arm — required for real builds
# (your toolchain env from the setup guide should already export it).
export WASMLD_HWJS=1
wasmcc hello.c -o hello The result is a standard wasm module with one extra custom section. You can inspect it with stock wasm tooling — the custom section is ignored by tools that don't understand it:
wasm-objdump -h hello # the custom binfmt_wasm section is present
file hello # WebAssembly (wasm) binary module Make sure the libc actually linked. A correctly linked package imports the kernel's shared memory and the syscall entry point our musl wrappers call. Confirm both are present:
wasm-objdump -x hello | grep -E 'kernel_memory|wasm_syscall'
# (env) kernel_memory memory ...
# (env) wasm_syscall func ... If those imports are missing, your program didn't link against the brintOS musl — re-check the
driver environment from the toolchain setup (WASMLD_HWJS=1, HWJS_TOOLS_DIR / WASMLD_HWJS_LIBC_BC) and rebuild. Builds are static
by default, so hello bundles
musl and is self-contained. Any build system that respects CC/LD works —
point it at wasmcc/wasmld (e.g. make CC=wasmcc, with the sysroot env
set) to build larger packages.
2. Get a machine and mount its drive
You need a machine you can write to. Fork a userland image that ships a shell — for example a bash + coreutils machine from Explore — into your
own account. Forking gives you a writable copy at <you>/<repo>.
Then install the FUSE client, brintos-fs, which mounts a machine's filesystem as
a local folder. Download a build from the Downloads page (or build it
from source at brintos/brintos-fs). It needs FUSE 3
on Linux/WSL2:
sudo apt install fuse3 libfuse3-3 # Debian / Ubuntu / WSL2
brintos login # opens a browser to authorize
mkdir -p ~/mnt/brintos
brintos mount <you>/<repo> ~/mnt/brintos # read-write because you own the repo --snapshot and --prefetch.3. Copy the package onto the filesystem
The mount looks like an ordinary folder. Drop your binary somewhere on the machine's PATH and make sure it's executable:
cp hello ~/mnt/brintos/usr/local/bin/hello
chmod +x ~/mnt/brintos/usr/local/bin/hello
# Flush to the server before you unmount. brintos-fs is write-back, so a
# plain copy is only locally durable until it drains; fsync/sync/unmount
# are the server-durable barriers.
sync Writes use an asynchronous write-back model (like the Linux page cache): copies finish at local
disk speed and drain to the server in the background. fsync, sync, and
unmount block until your changes are uploaded and attached, so run one of those before you launch
the machine in the browser.
4. Run it in the browser
Open your machine on brintos.io and press Power on. The machine boots its
configured kernel and init (a shell, for a bash/coreutils image) entirely in the tab —
its root filesystem is served from the same cloud storage you just wrote to. When the serial console
shows a prompt, run your program:
$ hello
hello from a brintOS package The kernel's binfmt_wasm loader recognizes the header you compiled in, swaps the
image in on execve, and your process runs as a real Linux task — it can fork, take signals, and block on syscalls like any other binary.
init to your binary's path (e.g. /usr/local/bin/hello) in its
machine spec, and the kernel will exec it as PID 1 on boot. See Machines. Building your own kernel image instead of using a stock
one? See Build the Linux kernel.