Skip to content
Merged
109 changes: 109 additions & 0 deletions .github/workflows/build-browser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: Build browser runtime

permissions:
contents: write

on:
workflow_dispatch:
push:
paths:
- "os/main.c"
- "os/wasm-rtos"
- ".gitmodules"
- "build-browser.sh"
- ".github/workflows/build-browser.yml"
pull_request:
paths:
- "os/main.c"
- "os/wasm-rtos"
- ".gitmodules"
- "build-browser.sh"
- ".github/workflows/build-browser.yml"

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref || github.ref_name }}
fetch-depth: 0
submodules: false

- name: Update wasm-rtos and nested wasm3 submodules
run: |
git submodule sync --recursive
git submodule update --init --remote --recursive
git submodule status --recursive

test -f os/wasm-rtos/os.c
test -f os/wasm-rtos/wasm3/source/wasm3.h

echo "wasm-rtos commit: $(git -C os/wasm-rtos rev-parse HEAD)"
echo "wasm3 commit: $(git -C os/wasm-rtos/wasm3 rev-parse HEAD)"

if ! git -C os/wasm-rtos diff --quiet -- wasm3; then
echo "::warning::The nested wasm3 checkout is newer than the gitlink recorded by wasm-rtos. It is used by this build, but must be committed in the wasm-rtos repository to become permanent."
fi

- name: Install latest Emscripten SDK
run: |
git clone --depth 1 https://github.com/emscripten-core/emsdk.git "$RUNNER_TEMP/emsdk" >/dev/null
"$RUNNER_TEMP/emsdk/emsdk" install latest >"$RUNNER_TEMP/emsdk-install.log"
"$RUNNER_TEMP/emsdk/emsdk" activate latest >>"$RUNNER_TEMP/emsdk-install.log"
source "$RUNNER_TEMP/emsdk/emsdk_env.sh" >/dev/null
emcc --version

- name: Build JavaScript and WebAssembly runtime
run: |
source "$RUNNER_TEMP/emsdk/emsdk_env.sh" >/dev/null
if ! bash ./build-browser.sh >build-browser.log 2>&1; then
echo "Browser runtime compilation failed:"
tail -n 100 build-browser.log
exit 1
fi
tail -n 100 build-browser.log

- name: Upload browser build log
if: always()
uses: actions/upload-artifact@v4
with:
name: browser-build-log
path: build-browser.log
if-no-files-found: warn

- name: Verify browser runtime outputs
run: |
test -s os/wasm-rtos.js
test -s os/wasm-rtos.wasm
test "$(od -An -tx1 -N4 os/wasm-rtos.wasm | tr -d ' \n')" = "0061736d"
grep -q "createWasmRtosModule" os/wasm-rtos.js
ls -lh os/wasm-rtos.js os/wasm-rtos.wasm

- name: Persist updated wasm-rtos submodule
if: github.event_name == 'push'
run: |
branch="${{ github.ref_name }}"

git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add os/wasm-rtos

if git diff --cached --quiet; then
echo "No wasm-rtos submodule pointer changed"
exit 0
fi

git commit -m "Update wasm-rtos submodule"
git push origin "HEAD:$branch"

- name: Upload browser runtime
uses: actions/upload-artifact@v4
with:
name: wasm-rtos-browser
path: |
os/wasm-rtos.js
os/wasm-rtos.wasm
if-no-files-found: error
82 changes: 82 additions & 0 deletions build-browser.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env bash
set -euo pipefail

ROOT="$(cd "$(dirname "$0")" && pwd)"
cd "$ROOT"

EMCC_BIN="${EMCC:-emcc}"
OUTPUT_JS="os/wasm-rtos.js"
OUTPUT_WASM="os/wasm-rtos.wasm"
WASM_RTOS_DIR="os/wasm-rtos"
WASM3_SOURCE_DIR="$WASM_RTOS_DIR/wasm3/source"

if ! command -v "$EMCC_BIN" >/dev/null 2>&1; then
echo "FAIL Emscripten compiler not found: $EMCC_BIN"
exit 1
fi

required_files=(
"os/main.c"
"$WASM_RTOS_DIR/os.c"
"$WASM_RTOS_DIR/os.h"
"$WASM_RTOS_DIR/hal.h"
)

for required_file in "${required_files[@]}"; do
if [ ! -f "$required_file" ]; then
echo "FAIL required source file is missing: $required_file"
exit 1
fi
done

if [ ! -d "$WASM3_SOURCE_DIR" ]; then
echo "FAIL wasm3 source directory is missing: $WASM3_SOURCE_DIR"
exit 1
fi

mapfile -t wasm3_sources < <(find "$WASM3_SOURCE_DIR" -maxdepth 1 -type f -name '*.c' -print | sort)
if [ "${#wasm3_sources[@]}" -eq 0 ]; then
echo "FAIL no wasm3 C sources found in $WASM3_SOURCE_DIR"
exit 1
fi

exported_functions='["_main","_malloc","_free","_browser_runtime_init","_browser_runtime_shutdown","_browser_task_create","_browser_task_delete","_browser_task_suspend","_browser_task_resume","_browser_task_set_priority","_browser_runtime_step","_browser_runtime_set_slices_per_frame","_browser_task_get_state","_browser_task_get_priority","_browser_task_get_run_count","_browser_task_get_exit_reason","_browser_task_get_exit_code","_browser_runtime_get_task_count","_browser_runtime_get_ready_task_count","_browser_runtime_get_waiting_task_count","_browser_runtime_get_last_error"]'
exported_runtime_methods='["ccall","cwrap","UTF8ToString"]'

rm -f "$OUTPUT_JS" "$OUTPUT_WASM"

"$EMCC_BIN" \
-std=c11 \
-O2 \
-Wall \
-Wextra \
-D_GNU_SOURCE \
-Dd_m3HasWASI \
-I. \
-I"$WASM_RTOS_DIR" \
-I"$WASM3_SOURCE_DIR" \
os/main.c \
"$WASM_RTOS_DIR/os.c" \
"${wasm3_sources[@]}" \
-sWASM=1 \
-sALLOW_MEMORY_GROWTH=1 \
-sNO_EXIT_RUNTIME=1 \
-sMODULARIZE=1 \
-sEXPORT_NAME=createWasmRtosModule \
-sENVIRONMENT=web \
-sEXPORTED_FUNCTIONS="$exported_functions" \
-sEXPORTED_RUNTIME_METHODS="$exported_runtime_methods" \
-o "$OUTPUT_JS"

if [ ! -s "$OUTPUT_JS" ]; then
echo "FAIL generated JavaScript loader is missing or empty: $OUTPUT_JS"
exit 1
fi

if [ ! -s "$OUTPUT_WASM" ]; then
echo "FAIL generated WebAssembly runtime is missing or empty: $OUTPUT_WASM"
exit 1
fi

echo "Generated browser runtime:"
ls -lh "$OUTPUT_JS" "$OUTPUT_WASM"
Loading
Loading