From bb62213e84a69aaf6ed26feac7a0216f33256991 Mon Sep 17 00:00:00 2001 From: Nikhil Date: Tue, 7 Apr 2026 11:12:21 -0700 Subject: [PATCH] fix: install linux sysroot in configure, not via gclient hook (#653) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: install linux sysroot in configure, not via gclient hook `gn gen` was failing on the arm64 leg with `Missing sysroot (//build/linux/debian_bullseye_arm64-sysroot)`. The previous design relied on `git_setup` writing `target_cpus` to `.gclient` so that `gclient sync`'s DEPS hook would download the cross-arch sysroot. That chain breaks for any chromium_src that was synced before cross-arch support landed (the hook is gated on .gclient state at sync time) and for partial pipeline runs that skip git_setup entirely. Nothing in configure declared or verified its sysroot precondition. Make configure self-healing: on Linux, invoke `build/linux/sysroot_scripts/install-sysroot.py --arch=` directly before `gn gen`. install-sysroot.py is idempotent (stamp file + SHA check), fast when already installed, and decoupled from .gclient — it's exactly what the failing assertion's error message recommends. The script accepts our arch names directly: `x64` translates to `amd64` internally via ARCH_TRANSLATIONS, and `arm64` is a valid pass-through. Also temporarily pin release.linux.yaml to x64 only while we validate the sysroot bootstrap end-to-end. Flip back to `[x64, arm64]` once arm64 is green. * chore: pin release.linux.yaml to arm64-only for sysroot bootstrap test x64 already builds cleanly — the failing leg is arm64 cross-compile from an x64 host. Pin the config to arm64 to exercise the new install-sysroot.py path in configure without burning time on x64. Flip back to [x64, arm64] once arm64 is green. --- .../browseros/build/config/release.linux.yaml | 8 ++-- .../build/modules/setup/configure.py | 45 ++++++++++++++++++- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/packages/browseros/build/config/release.linux.yaml b/packages/browseros/build/config/release.linux.yaml index ef623f870..80d96122f 100644 --- a/packages/browseros/build/config/release.linux.yaml +++ b/packages/browseros/build/config/release.linux.yaml @@ -1,8 +1,8 @@ # BrowserOS Linux Release Build Configuration # -# Builds both x64 and arm64 in a single invocation on a Linux x64 host. -# The runner loops the entire pipeline once per architecture; depot_tools -# fetches the matching sysroots automatically (see git_setup module). +# Pinned to arm64-only to validate the cross-compile sysroot bootstrap +# end-to-end on a Linux x64 host. Flip back to `[x64, arm64]` once arm64 +# is green. # # Run: # browseros build --config build/config/release.linux.yaml @@ -13,7 +13,7 @@ build: type: release - architecture: [x64, arm64] # Builds both arches sequentially in one run + architecture: arm64 gn_flags: file: build/config/gn/flags.linux.release.gn diff --git a/packages/browseros/build/modules/setup/configure.py b/packages/browseros/build/modules/setup/configure.py index 91a391480..4350b38a5 100644 --- a/packages/browseros/build/modules/setup/configure.py +++ b/packages/browseros/build/modules/setup/configure.py @@ -1,9 +1,19 @@ #!/usr/bin/env python3 """Build configuration module for BrowserOS build system""" +import sys + from ...common.module import CommandModule, ValidationError from ...common.context import Context -from ...common.utils import run_command, log_info, log_success, join_paths, IS_WINDOWS +from ...common.utils import ( + run_command, + log_info, + log_warning, + log_success, + join_paths, + IS_LINUX, + IS_WINDOWS, +) class ConfigureModule(CommandModule): @@ -25,6 +35,16 @@ class ConfigureModule(CommandModule): def execute(self, ctx: Context) -> None: log_info(f"\n⚙️ Configuring {ctx.build_type} build for {ctx.architecture}...") + # Linux: ensure the target-arch Debian sysroot is installed before + # `gn gen`. sysroot.gni asserts on missing sysroots, and relying on + # `gclient sync` DEPS hooks is fragile — the hook only fires when + # .gclient declared the right `target_cpus` *before* sync, which + # isn't guaranteed for chromium_src checkouts that predate + # cross-arch support. install-sysroot.py is idempotent and fast, + # so call it unconditionally for the target arch. + if IS_LINUX(): + self._ensure_linux_sysroot(ctx) + out_path = join_paths(ctx.chromium_src, ctx.out_dir) out_path.mkdir(parents=True, exist_ok=True) @@ -43,3 +63,26 @@ class ConfigureModule(CommandModule): run_command(gn_args, cwd=ctx.chromium_src) log_success("Build configured") + + def _ensure_linux_sysroot(self, ctx: Context) -> None: + install_script = ( + ctx.chromium_src / "build" / "linux" / "sysroot_scripts" / "install-sysroot.py" + ) + if not install_script.exists(): + log_warning( + f"⚠️ install-sysroot.py not found at {install_script}; " + f"skipping sysroot bootstrap. gn gen will fail if the " + f"{ctx.architecture} sysroot is missing." + ) + return + + # install-sysroot.py accepts our arch names directly: it translates + # `x64`→`amd64` internally via ARCH_TRANSLATIONS, and `arm64` is a + # valid pass-through value. + log_info( + f"📦 Ensuring Linux sysroot for {ctx.architecture} (idempotent)..." + ) + run_command( + [sys.executable, str(install_script), f"--arch={ctx.architecture}"], + cwd=ctx.chromium_src, + )