Skip to content

Windows build (x86_64) #27

Windows build (x86_64)

Windows build (x86_64) #27

Workflow file for this run

name: Windows build (x86_64)
# CROSS-COMPILED FROM LINUX — not native on a Windows runner. This is how
# zen-browser and librewolf actually ship Windows builds, and it sidesteps the
# entire native-Windows failure class (reserved `con.clj` checkout, the
# beagle-build bash shebang, CRLF line endings, MozillaBuild, "Windows App SDK
# dir not present") because the host OS is Linux — which gjoa already builds
# green. We add the Windows cross toolchain (Visual Studio + SDK via Mozilla's
# get_vs.py + WINSYSROOT, wine for MIDL/widl, the win rust target) and a cross
# mozconfig (--target=x86_64-pc-windows-msvc). Recipe adapted from
# zen-browser/.github/workflows/windows-release-build.yml + configs/windows/mozconfig.
on:
workflow_dispatch:
inputs:
fast:
description: "Use the Blacksmith fast runner (paid) instead of free GitHub-hosted"
type: boolean
default: false
workflow_call:
inputs:
fast:
type: boolean
default: false
jobs:
build:
runs-on: ${{ inputs.fast && 'blacksmith-16vcpu-ubuntu-2404' || 'ubuntu-24.04' }}
timeout-minutes: 360
env:
FF_VERSION: "152.0"
steps:
- uses: actions/checkout@v4
- name: Free disk space
if: ${{ !inputs.fast }}
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/opt/hostedtoolcache/CodeQL /usr/local/share/boost \
/usr/lib/jvm /usr/share/swift "${AGENT_TOOLSDIRECTORY:-/opt/hostedtoolcache}" || true
sudo docker image prune --all --force || true
df -h /
- name: Install bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install dependencies
run: bun install
- name: Install system deps (host + Windows cross)
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential clang lld llvm m4 \
nasm yasm unzip zip \
python3 python3-pip \
aria2 msitools p7zip-full cabextract dos2unix \
xvfb mesa-utils libgl1-mesa-dri libnvidia-egl-wayland1 x11-utils \
pkg-config nodejs
- name: Maximize build space
if: ${{ !inputs.fast }}
run: |
sudo swapoff -a
sudo rm -f /swapfile
sudo fallocate -l 16G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
- name: Download Firefox source
run: |
mkdir -p ~/.cache/gjoa/sources
curl -L -o ~/.cache/gjoa/sources/firefox-${FF_VERSION}.source.tar.xz \
"https://archive.mozilla.org/pub/firefox/releases/${FF_VERSION}/source/firefox-${FF_VERSION}.source.tar.xz"
ls -lh ~/.cache/gjoa/sources/firefox-${FF_VERSION}.source.tar.xz
- name: Verify tarball checksum (pinned)
run: |
PIN="configs/firefox-${FF_VERSION}.sha256"
test -f "$PIN" || { echo "missing pinned checksum: $PIN"; exit 1; }
expected=$(grep -v '^#' "$PIN" | awk 'NF{print $1; exit}')
actual=$(sha256sum ~/.cache/gjoa/sources/firefox-${FF_VERSION}.source.tar.xz | awk '{print $1}')
if [ "$expected" != "$actual" ]; then
echo "::error::Firefox tarball SHA-256 does not match pinned $PIN"; exit 1
fi
echo "tarball checksum OK"
- name: Extract source
run: |
mkdir -p engine
tar -xJf ~/.cache/gjoa/sources/firefox-${FF_VERSION}.source.tar.xz -C engine --strip-components=1
- name: Install Racket (beagle compiler runtime)
uses: Bogdanp/setup-racket@v1.15
with:
version: 'stable'
- name: Checkout beagle (sibling compiler)
run: git clone --depth 1 https://github.com/tompassarelli/beagle.git ../beagle
- name: Register beagle collection
run: raco pkg install --link --batch --no-docs ../beagle/beagle-lib
- name: Apply overlays and patches
run: bun run import
# --- Windows cross toolchain (adapted from zen windows-release-build.yml) ---
- name: Setup Windows cross toolchain
working-directory: engine
run: |
set -x
mkdir -p ~/win-cross
# wine — runs MIDL/widl during the build. Download to an ABSOLUTE path:
# aria2c -o is relative to cwd (engine/ here), so `-o /tmp/...` wrote to
# engine/tmp/ and the tar then missed it. Use --dir + a bare filename,
# and don't mask a tar failure behind `&&` (bash -e ignores it).
aria2c --dir="$HOME" -o wine.tar.zst "https://firefox-ci-tc.services.mozilla.com/api/index/v1/task/gecko.cache.level-1.toolchains.v3.linux64-wine.latest/artifacts/public%2Fbuild%2Fwine.tar.zst"
tar --zstd -xf "$HOME/wine.tar.zst" -C ~/win-cross
rm -f "$HOME/wine.tar.zst"
test -x ~/win-cross/wine/bin/wine || { echo "::error::wine not at ~/win-cross/wine/bin/wine"; ls -R ~/win-cross/wine 2>/dev/null | head -20; exit 1; }
# Headless wine: select the NULL display driver so fxc2 + d3dcompiler's
# window/OLE-apartment init succeeds with NO X server. The Mozilla wine
# artifact's winex11.drv can't load on a bare runner even with Xvfb up
# ("no driver could be loaded" → fxc2 dies); Mozilla's own builders only
# work because their docker ships a full X stack. null avoids X entirely.
# This first wine call also boots the default prefix (~/.wine) — the
# 'explorer failed to start' warning is non-fatal — and persists the key
# for the Build step (same HOME, same prefix).
WINEDEBUG=-all "$HOME/win-cross/wine/bin/wine" reg add 'HKCU\Software\Wine\Drivers' /v Graphics /d null /f 2>/dev/null || true
# Visual Studio + Windows SDK (+ App SDK) via Mozilla's fetcher. This is
# the SAME setup zen-browser uses (windows-release-build.yml:156-161):
# fetch wine, get_vs.py → WINSYSROOT, chmod +x. No fxc/d3dcompiler hacks —
# the SDK's fxc.exe compiles the D3D shaders fine under this wine, headless.
./mach python --virtualenv build taskcluster/scripts/misc/get_vs.py build/vs/vs2026.yaml ~/win-cross/vs2026
chmod -R +x ~/win-cross/vs2026 || true
# fxc2 — Mozilla's HLSL compiler for Linux→Windows cross. The SDK fxc.exe
# under wine falls back to builtin vkd3d, which can't parse FF's shaders
# (CompositorD3D11.hlsl E5000 syntax error). fxc2.exe bundles the REAL
# d3dcompiler_47.dll (build-mingw-fxc2-x86.sh:16-17) and is exactly what
# Mozilla's own cross build uses (browser/config/mozconfigs/win64/mingwclang).
aria2c --dir="$HOME" -o fxc2.tar.zst "https://firefox-ci-tc.services.mozilla.com/api/index/v1/task/gecko.cache.level-1.toolchains.v3.linux64-mingw-fxc2-x86.latest/artifacts/public%2Fbuild%2Ffxc2.tar.zst"
tar --zstd -xf "$HOME/fxc2.tar.zst" -C ~/win-cross
rm -f "$HOME/fxc2.tar.zst"
test -f ~/win-cross/fxc2/bin/fxc2.exe || { echo "::error::fxc2.exe missing after extract"; ls -R ~/win-cross/fxc2 2>/dev/null | head -20; exit 1; }
chmod -R +x ~/win-cross/fxc2 || true
ls ~/win-cross
- name: Write mozconfig (cross)
run: |
cat > engine/mozconfig <<'MOZCONFIG'
ac_add_options --with-branding=browser/branding/gjoa
ac_add_options --with-distribution-id=org.gjoa
ac_add_options --with-app-name=gjoa
ac_add_options --with-app-basename=Gjoa
ac_add_options --target=x86_64-pc-windows-msvc
ac_add_options --enable-bootstrap
ac_add_options --without-wasm-sandboxed-libraries
ac_add_options --disable-updater
ac_add_options --disable-tests
ac_add_options --enable-optimize
ac_add_options --enable-release
ac_add_options --disable-debug-symbols
# Mirror zen-browser/configs/windows/mozconfig exactly — the proven
# cross env. No WINEDLLOVERRIDES: zen sets none and the SDK fxc compiles
# the shaders correctly. MOZ_PKG_FORMAT=TAR avoids needing NSIS/makensis
# at package time. CROSS_COMPILE=1 + CROSS_BUILD=1 as zen sets them.
export WINSYSROOT="$HOME/win-cross/vs2026"
export WINE="$HOME/win-cross/wine/bin/wine"
export WINEDEBUG=-all
# Force the shader compiler to fxc2 (bundles the real d3dcompiler_47.dll),
# overriding moz.configure's check_prog which would pick the SDK fxc.exe
# → builtin vkd3d → can't compile FF's HLSL.
export FXC="$HOME/win-cross/fxc2/bin/fxc2.exe"
# Make wine load fxc2's BUNDLED native d3dcompiler_47.dll (next to fxc2.exe)
# rather than builtin vkd3d, which can't compile FF's HLSL. Use
# mk_add_options so these land in the MAKE environment and reach the
# genshaders subprocess that actually runs wine — a plain `export` is
# configure-time only and does NOT propagate to the build. (The diagnostic
# step proved fxc2 compiles the shader cleanly with this override set;
# Mozilla's mingwclang uses mk_add_options for its fxc2 PATH for the same reason.)
mk_add_options "export WINEDLLOVERRIDES=d3dcompiler_47=n"
mk_add_options "export WINEPREFIX=$HOME/.wine"
export WINEDLLOVERRIDES="d3dcompiler_47=n"
export MOZ_STUB_INSTALLER=1
export MOZ_PKG_FORMAT=TAR
export CROSS_BUILD=1
CROSS_COMPILE=1
export WIN32_REDIST_DIR="$(ls -d $HOME/win-cross/vs2026/VC/Redist/MSVC/*/x64/Microsoft.VC*.CRT 2>/dev/null | head -1)"
MOZCONFIG
sed -i 's/^ //' engine/mozconfig
cat engine/mozconfig
- name: Bootstrap mach (+ clang Windows LIB)
working-directory: engine
run: |
export MOZBUILD_STATE_PATH="$HOME/.mozbuild"
echo 1 | ./mach bootstrap --application-choice=browser 2>&1 || true
# clang's Windows runtime lib dir must be on LIB for the cross link
# (zen windows-release-build.yml:184). Append after bootstrap fetches clang.
LIBDIR="$(ls -d $HOME/.mozbuild/clang/lib/clang/*/lib/windows 2>/dev/null | head -1)"
echo "export LIB=\"$LIBDIR\"" >> mozconfig
tail -4 mozconfig
- name: Add Rust Windows target
run: |
[ -f "$HOME/.cargo/env" ] && . "$HOME/.cargo/env" || true
rustup target add x86_64-pc-windows-msvc
- name: Build
working-directory: engine
run: |
export MOZBUILD_STATE_PATH="$HOME/.mozbuild"
[ -f "$HOME/.cargo/env" ] && . "$HOME/.cargo/env" || true
# Headless: fxc2 runs under wine with the NULL display driver selected in
# Setup (~/.wine), so no X server is needed — its window/OLE init is a
# no-op and the shader compile proceeds.
./mach build -j${{ inputs.fast && '16' || '2' }}
- name: Package
working-directory: engine
run: |
export MOZBUILD_STATE_PATH="$HOME/.mozbuild"
./mach package
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: gjoa-windows-x86_64
path: |
engine/obj-*/dist/gjoa-*.zip
engine/obj-*/dist/gjoa-*.tar*
if-no-files-found: error