diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7adaaa2..0a9023d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,3 +29,13 @@ jobs: - name: Test run: ctest --test-dir build_test_ci --output-on-failure --build-config Debug + wasm32-emscripten: + name: wasm32-emscripten + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: build + run: docker build -f src/targets/wasm32-emscripten/Dockerfile -t wasm32-emscripten-pe . + diff --git a/src/targets/wasm32-emscripten/Dockerfile b/src/targets/wasm32-emscripten/Dockerfile new file mode 100644 index 0000000..0122080 --- /dev/null +++ b/src/targets/wasm32-emscripten/Dockerfile @@ -0,0 +1,12 @@ +FROM emscripten/emsdk:4.0.22 + +WORKDIR /app + +COPY ../../../ . + +WORKDIR /app/src/targets/wasm32-emscripten +# TODO: fix permissions +RUN chmod +x build.sh && ./build.sh + +WORKDIR / +RUN tar cJf wasm32-emscripten-pe-release.tar.xz /wasm32-emscripten-pe-release diff --git a/src/targets/wasm32-emscripten/README.md b/src/targets/wasm32-emscripten/README.md new file mode 100644 index 0000000..b6bbae0 --- /dev/null +++ b/src/targets/wasm32-emscripten/README.md @@ -0,0 +1,4 @@ +```sh +docker build -f src/targets/wasm32-emscripten/Dockerfile -t wasm32-emscripten-pe . +docker run --rm wasm32-emscripten-pe cat /wasm32-emscripten-pe-release.tar.xz > wasm32-emscripten-pe-release.tar.xz +``` diff --git a/src/targets/wasm32-emscripten/build.sh b/src/targets/wasm32-emscripten/build.sh new file mode 100644 index 0000000..953c09e --- /dev/null +++ b/src/targets/wasm32-emscripten/build.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# Only for Dockerfile +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" +ENGINE_DIR="$ROOT_DIR" +OUT_DIR="/wasm32-emscripten-pe-release" + +mkdir -p "$OUT_DIR" +export EM_CACHE="${EM_CACHE:-$ROOT_DIR/.cache/emscripten}" +mkdir -p "$EM_CACHE" + +em++ \ + -std=c++23 \ + -O3 \ + -I"$ENGINE_DIR/include" \ + "$ENGINE_DIR/src/dll_main.cpp" \ + -fno-rtti \ + -fno-exceptions \ + -fno-cxx-exceptions \ + -fno-unwind-tables \ + -s MODULARIZE=1 \ + -s EXPORT_ES6=1 \ + -s ENVIRONMENT=web \ + -s ALLOW_MEMORY_GROWTH=1 \ + -s FILESYSTEM=0 \ + -s EXPORTED_RUNTIME_METHODS='["cwrap"]' \ + -s EXPORTED_FUNCTIONS='["_malloc","_free","_create_circuit","_create_circuit_ex","_destroy_circuit","_circuit_set_analyze_type","_circuit_set_tr","_circuit_set_ac_omega","_circuit_analyze","_circuit_digital_clk","_circuit_sample_u8","_circuit_set_model_digital"]' \ + -o "$OUT_DIR/phy_engine.js" + +# The generated ESModule does not expose HEAP views on the returned Module by default. +# Patch `updateMemoryViews()` so callers can access `Module.HEAPU8/HEAPU32/HEAPF64` and `Module.wasmMemory`. +node - <<'NODE' +import { readFileSync, writeFileSync } from "node:fs"; +import path from "node:path"; + +const file = "/wasm32-emscripten-pe-release/phy_engine.js"; +let s = readFileSync(file, "utf8"); + +const needle = "HEAPU64=new BigUint64Array(b)}"; +if (!s.includes(needle)) { + console.error("patch failed: updateMemoryViews() signature not found"); + process.exit(1); +} + +const inject = + "HEAPU64=new BigUint64Array(b);Module.HEAP8=HEAP8;Module.HEAPU8=HEAPU8;Module.HEAP32=HEAP32;Module.HEAPU32=HEAPU32;Module.HEAPF64=HEAPF64;Module.wasmMemory=wasmMemory}"; + +s = s.replace(needle, inject); +writeFileSync(file, s); +NODE + +echo "Built:" +ls -la "$OUT_DIR/phy_engine.js" "$OUT_DIR/phy_engine.wasm" \ No newline at end of file