build-and-release #13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: build-and-release | |
| # Builds the full Gecko->wasm engine and the gecko.js package, then attaches the | |
| # packaged library (dist/gecko.js + dist/gecko.wasm + the wasm/ engine artifacts) | |
| # to a GitHub Release. (embed-xul/ + embed-chrome/ are legacy stubs and are NOT built | |
| # here -- the maintained package is gecko.js/.) | |
| # | |
| # !!! HEAVY BUILD β READ FIRST !!! | |
| # A full Gecko->wasm build is enormous: ~26 GB objdir, a ~3.4 GB (relocatable) libxul.so, | |
| # a ~245 MB gecko.wasm, and 25-50 min on 12 cores. On a standard hosted runner | |
| # (4 vCPU / 16 GB RAM / ~14 GB free disk) this is marginal on ALL THREE axes: | |
| # - disk: we free ~30 GB below; still tight. Prefer a larger/self-hosted runner. | |
| # - ram: the final emcc relink (wasm-opt over the 245 MB module) + engine LTO link | |
| # spike past 16 GB and OOM-kill, so we add a 32 GB swapfile on /mnt below. | |
| # - time: on 4 vCPU expect ~2-4 h (job cap is 6 h). | |
| # If it doesn't fit, switch `runs-on` to a larger runner (e.g. a self-hosted one | |
| # or GitHub larger runners) β the steps are otherwise unchanged. | |
| # | |
| # This workflow is a STARTING POINT; the local upgrade to emscripten 6.0.1 was | |
| # verified with a DEBUG build (the RELEASE/LTO path here is not yet CI-verified). | |
| on: | |
| push: | |
| tags: ['v*'] | |
| workflow_dispatch: | |
| permissions: | |
| contents: write # create releases / upload assets | |
| env: | |
| EMSDK_VERSION: '6.0.1' # emcc 6.0.1 / clang 23 (bundles binaryen v130) | |
| RUST_VERSION: '1.95.0' | |
| PNPM_VERSION: '9.12.0' # matches root package.json "packageManager" | |
| MOZBUILD_STATE_PATH: ${{ github.workspace }}/.mozbuild | |
| MACH_NO_TERMINAL_FOOTER: '1' | |
| jobs: | |
| build: | |
| runs-on: firefox | |
| timeout-minutes: 350 | |
| steps: | |
| - name: Checkout the embedder + build harness (this repo) | |
| uses: actions/checkout@v4 | |
| # - name: Free up disk space (Gecko objdir is ~26 GB) | |
| # uses: jlumbroso/free-disk-space@main | |
| # with: | |
| # tool-cache: true | |
| # android: true | |
| # dotnet: true | |
| # haskell: true | |
| # large-packages: true | |
| # swap-storage: true | |
| - name: Install build prerequisites (clang/libclang for bindgen, etc.) | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y --no-install-recommends \ | |
| clang llvm-dev libclang-dev libpulse-dev python3 mercurial unzip zstd | |
| # mozconfig.full.emscripten reads $LIBCLANG_PATH for --with-libclang-path. | |
| echo "LIBCLANG_PATH=$(llvm-config --libdir)" >> "$GITHUB_ENV" | |
| # Install emscripten from a FRESH emsdk clone (its bundled tags know 6.0.x; an | |
| # older/cached emsdk may not). em_config reads $EMSDK and resolves binaryen at | |
| # $EMSDK/upstream -- emsdk 6.0.1 bundles binaryen v130, which accepts the wasm | |
| # features rust/LLVM emit, so NO separate binaryen install is needed anymore. | |
| - name: Set up emscripten ${{ env.EMSDK_VERSION }} | |
| run: | | |
| git clone --depth 1 https://github.com/emscripten-core/emsdk.git "$HOME/emsdk" | |
| "$HOME/emsdk/emsdk" install "${EMSDK_VERSION}" | |
| "$HOME/emsdk/emsdk" activate "${EMSDK_VERSION}" | |
| echo "EMSDK=$HOME/emsdk" >> "$GITHUB_ENV" | |
| echo "$HOME/emsdk/upstream/emscripten" >> "$GITHUB_PATH" | |
| echo "$HOME/emsdk" >> "$GITHUB_PATH" | |
| "$HOME/emsdk/upstream/emscripten/emcc" --version | head -1 | |
| "$HOME/emsdk/upstream/bin/wasm-opt" --version | head -1 | |
| - name: Set up Rust ${{ env.RUST_VERSION }} (+ rust-src, wasm target) | |
| uses: dtolnay/rust-toolchain@master | |
| with: | |
| toolchain: ${{ env.RUST_VERSION }} | |
| components: rust-src | |
| targets: wasm32-unknown-emscripten | |
| # gecko.js's package build (rspack bundle) runs under pnpm; the repo pins | |
| # pnpm via package.json "packageManager", so let corepack provide it. | |
| - name: Set up Node + pnpm ${{ env.PNPM_VERSION }} | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Enable corepack/pnpm | |
| run: | | |
| corepack enable | |
| corepack prepare "pnpm@${PNPM_VERSION}" --activate | |
| pnpm --version | |
| # em_config is committed and portable (reads $EMSDK; binaryen defaults to the | |
| # emsdk's bundled $EMSDK/upstream), so no shim or config generation is needed. | |
| - name: Clone the pinned Gecko engine fork (depth 1) | |
| run: make firefox | |
| # No path rewriting needed: mozconfig.full.emscripten derives its objdir and | |
| # FreeType include from $topsrcdir, and libclang from $LIBCLANG_PATH (set above). | |
| - name: "Build the engine + gecko.js (release: LTO + zstd; wasm-opt TEMPORARILY disabled) β long" | |
| env: | |
| NO_WASM_OPT: '1' # TEMP: skip the whole-module wasm-opt pass (OOMs/SIGSEGVs in CI); remove to re-enable | |
| run: | | |
| # wasm-opt's recursive passes overflow the default 8MB stack on the | |
| # ~250MB module and die with SIGSEGV. Raise the stack limit for the whole | |
| # make -> mach -> em++ -> wasm-opt subprocess tree (ulimit is inherited). | |
| # Also needed for the libxul.so relink: emscripten 6.0.1's wasm-ld SIGSEGVs | |
| # on the `-shared` link, so `make build` relinks the engine libs as `-r` | |
| # relocatable objects (gecko.js/build/relink-engine-r.sh, run between two | |
| # `mach build` passes) -- handled inside `make`, no extra step here. | |
| ulimit -s unlimited || ulimit -s 524288 || true | |
| make libxul RELEASE=1 # firefox cloned; vendor -> mach build (+relink) -> build-lib.sh -> rspack | |
| - name: Show link errors on failure | |
| if: failure() | |
| run: | | |
| echo "=== gecko.js/build/link.err (tail) ===" | |
| tail -n 60 gecko.js/build/link.err 2>/dev/null || echo "(no link.err)" | |
| - name: Package the gecko.js library (the runnable ESM bundle) | |
| run: | | |
| PKG=stage/gecko.js | |
| mkdir -p "$PKG" | |
| # The runnable/publishable artifact is dist/ (the ESM bundle + the single | |
| # served gecko.wasm[.zst]) + package.json. The wasm/ dir is build intermediates | |
| # -- gecko.js/worker.js/gecko.data are INLINED into dist/gecko.js, so only | |
| # dist/gecko.wasm[.zst] is served separately; no need to ship wasm/. | |
| cp -r gecko.js/dist gecko.js/package.json "$PKG/" | |
| cp gecko.js/README.md "$PKG/" 2>/dev/null || true | |
| cat > "$PKG/RELEASE.txt" <<'TXT' | |
| gecko.js β embeddable Gecko (the Firefox engine) compiled to WebAssembly (emscripten 6.0.1). | |
| The ESM bundle (dist/gecko.js) inlines the glue + gecko.data; consumers serve only the wasm | |
| (dist/gecko.wasm or, in this release build, dist/gecko.wasm.zst β decompressed in-browser). | |
| Must be served cross-origin-isolated (COOP: same-origin + COEP: require-corp) for SharedArrayBuffer. | |
| See README / the embed-demo for usage: `new Gecko({ canvas, wispUrl }); await g.init(); g.load(url)`. | |
| TXT | |
| tar -C stage -czf gecko.js-${{ github.ref_name }}.tar.gz gecko.js | |
| ls -la gecko.js-*.tar.gz | |
| - name: Upload build artifact (always) | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: gecko.js-${{ github.ref_name }} | |
| path: gecko.js-*.tar.gz | |
| if-no-files-found: error | |
| - name: Publish GitHub Release (tag pushes only) | |
| if: startsWith(github.ref, 'refs/tags/') | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: gecko.js-*.tar.gz | |
| generate_release_notes: true |