diff --git a/architecture/build.md b/architecture/build.md index 393eb9e468..18f1561f50 100644 --- a/architecture/build.md +++ b/architecture/build.md @@ -120,13 +120,12 @@ and the supervisor image from `deploy/docker/Dockerfile.supervisor`. Neither Dockerfile compiles Rust — both copy a staged binary out of `deploy/docker/.build/prebuilt-binaries//` into the final image. -Local binary staging is driven by `tasks/scripts/stage-prebuilt-binaries.sh`. Because -staging cross-compiles on the host, it sources `tasks/scripts/build-env.sh` and -raises the per-process open-file limit before invoking `cargo zigbuild` on -macOS — the static musl link opens hundreds of `.rlib` files at once and would -otherwise fail with `ProcessFdQuotaExceeded` under macOS's default soft limit of -256. The guard is a no-op on Linux and when `cargo-zigbuild` is absent. Gateway -binaries use `cargo zigbuild` with GNU targets pinned to glibc 2.28, including +Local binary staging is driven by `tasks/scripts/stage-prebuilt-binaries.sh`. +It and the local gateway tasks source `tasks/scripts/build-env.sh` before host +Rust builds on macOS. The helper raises the per-process open-file limit because +sccache and static musl linking can each open hundreds of files, exceeding the +default soft limit of 256. The guard is a no-op on Linux. Gateway binaries use +`cargo zigbuild` with GNU targets pinned to glibc 2.28, including native-architecture builds, so the gateway image, standalone tarballs, and Linux packages share the same host portability floor. The gateway build enables `bundled-z3`. Linux VM driver release artifacts use the same glibc floor so diff --git a/tasks/gateway.toml b/tasks/gateway.toml index bbf309c459..89a42eebc3 100644 --- a/tasks/gateway.toml +++ b/tasks/gateway.toml @@ -5,7 +5,7 @@ ["build:gateway"] description = "Build the standalone openshell-gateway binary" -run = "cargo build -p openshell-gateway --bin openshell-gateway" +run = "bash -c 'source tasks/scripts/build-env.sh && ensure_build_nofile_limit && cargo build -p openshell-gateway --bin openshell-gateway'" hide = true ["gateway"] diff --git a/tasks/scripts/build-env.sh b/tasks/scripts/build-env.sh index e2396d68f6..74da6009bd 100644 --- a/tasks/scripts/build-env.sh +++ b/tasks/scripts/build-env.sh @@ -3,21 +3,19 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -# Shared build-environment helpers for host-side cross-compilation. +# Shared build-environment helpers for host-side Rust builds. # # Source this file (do not execute it) and call the helpers before invoking -# cargo-zigbuild on the host. +# Cargo on the host. # ensure_build_nofile_limit raises the per-process open-file limit before a -# host cargo-zigbuild cross-compile. The static *-unknown-linux-musl link opens -# hundreds of .rlib files simultaneously, which exceeds macOS's default soft -# limit of 256 and fails with ProcessFdQuotaExceeded. The raised limit -# propagates to the cargo/zig children the caller spawns. +# host Rust build. Sccache and static *-unknown-linux-musl links can each open +# hundreds of files simultaneously, exceeding macOS's default soft limit of +# 256. The raised limit propagates to the Cargo children the caller spawns. # # The limit is read from OPENSHELL_BUILD_NOFILE_LIMIT (default 8192), honoring -# the legacy OPENSHELL_VM_BUILD_NOFILE_LIMIT for back-compat. This is a no-op on -# Linux and when cargo-zigbuild is not installed (native builds, CI Linux -# runners), so it must be safe to call unconditionally. +# the legacy OPENSHELL_VM_BUILD_NOFILE_LIMIT for back-compat. This is a no-op +# on Linux, so it must be safe to call unconditionally. ensure_build_nofile_limit() { local desired="${OPENSHELL_BUILD_NOFILE_LIMIT:-${OPENSHELL_VM_BUILD_NOFILE_LIMIT:-8192}}" local minimum=1024 @@ -26,8 +24,6 @@ ensure_build_nofile_limit() { local target="" [ "$(uname -s)" = "Darwin" ] || return 0 - command -v cargo-zigbuild >/dev/null 2>&1 || return 0 - current="$(ulimit -n 2>/dev/null || echo "")" case "${current}" in ''|*[!0-9]*) @@ -54,7 +50,7 @@ ensure_build_nofile_limit() { esac if [ "${target}" -gt "${current}" ] && ulimit -n "${target}" 2>/dev/null; then - echo "==> Raised open file limit for cargo-zigbuild: ${current} -> $(ulimit -n)" + echo "==> Raised open file limit for host Cargo build: ${current} -> $(ulimit -n)" fi current="$(ulimit -n 2>/dev/null || echo "${current}")" @@ -65,11 +61,11 @@ ensure_build_nofile_limit() { esac if [ "${current}" -lt "${desired}" ]; then - echo "WARNING: Open file limit is ${current}; cargo-zigbuild is more reliable at ${desired}+ on macOS." + echo "WARNING: Open file limit is ${current}; host Cargo builds are more reliable at ${desired}+ on macOS." fi if [ "${current}" -lt "${minimum}" ]; then - echo "ERROR: Open file limit (${current}) is too low for cargo-zigbuild on macOS." >&2 + echo "ERROR: Open file limit (${current}) is too low for host Cargo builds on macOS." >&2 echo " Run: ulimit -n ${desired}" >&2 echo " Then re-run this script." >&2 exit 1 diff --git a/tasks/scripts/gateway-docker.sh b/tasks/scripts/gateway-docker.sh index 6826829fd8..e561e3a906 100644 --- a/tasks/scripts/gateway-docker.sh +++ b/tasks/scripts/gateway-docker.sh @@ -24,6 +24,10 @@ set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +# shellcheck source=tasks/scripts/build-env.sh +source "${ROOT}/tasks/scripts/build-env.sh" +ensure_build_nofile_limit + PORT="${OPENSHELL_SERVER_PORT:-18080}" GATEWAY_NAME="${OPENSHELL_DOCKER_GATEWAY_NAME:-docker-dev}" STATE_DIR="${OPENSHELL_DOCKER_GATEWAY_STATE_DIR:-${ROOT}/.cache/gateway-docker}" diff --git a/tasks/scripts/gateway-podman.sh b/tasks/scripts/gateway-podman.sh index ab166865ef..3acd6b7089 100644 --- a/tasks/scripts/gateway-podman.sh +++ b/tasks/scripts/gateway-podman.sh @@ -21,6 +21,10 @@ set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +# shellcheck source=tasks/scripts/build-env.sh +source "${ROOT}/tasks/scripts/build-env.sh" +ensure_build_nofile_limit + PORT="${OPENSHELL_SERVER_PORT:-18080}" GATEWAY_NAME="${OPENSHELL_PODMAN_GATEWAY_NAME:-podman-dev}" STATE_DIR="${OPENSHELL_PODMAN_GATEWAY_STATE_DIR:-${OPENSHELL_GATEWAY_STATE_DIR:-${ROOT}/.cache/gateway-podman}}" diff --git a/tasks/scripts/gateway-vm.sh b/tasks/scripts/gateway-vm.sh index 3818dca364..f8020a238f 100755 --- a/tasks/scripts/gateway-vm.sh +++ b/tasks/scripts/gateway-vm.sh @@ -33,6 +33,10 @@ set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +# shellcheck source=tasks/scripts/build-env.sh +source "${ROOT}/tasks/scripts/build-env.sh" +ensure_build_nofile_limit + PORT="${OPENSHELL_SERVER_PORT:-18081}" GATEWAY_NAME="${OPENSHELL_VM_GATEWAY_NAME:-vm-dev}" STATE_DIR="${OPENSHELL_VM_GATEWAY_STATE_DIR:-${ROOT}/.cache/gateway-vm}" diff --git a/tasks/scripts/gateway.sh b/tasks/scripts/gateway.sh index 019d1b1b63..b1ad650e0b 100644 --- a/tasks/scripts/gateway.sh +++ b/tasks/scripts/gateway.sh @@ -18,6 +18,10 @@ set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" GATEWAY_BIN="${ROOT}/target/debug/openshell-gateway" +# shellcheck source=tasks/scripts/build-env.sh +source "${ROOT}/tasks/scripts/build-env.sh" +ensure_build_nofile_limit + usage() { cat <<'EOF' Usage: mise run gateway [-- --driver DRIVER] diff --git a/tasks/scripts/test-build-env.sh b/tasks/scripts/test-build-env.sh index 049ad369d1..be989a70e9 100755 --- a/tasks/scripts/test-build-env.sh +++ b/tasks/scripts/test-build-env.sh @@ -38,28 +38,14 @@ if [ "${os}" != "Darwin" ]; then exit 0 fi -# Darwin below. -if ! command -v cargo-zigbuild >/dev/null 2>&1; then - # Without cargo-zigbuild the helper must be a no-op even on macOS. - ( - ulimit -Sn 256 2>/dev/null || true - before="$(ulimit -n)" - ensure_build_nofile_limit >/dev/null - after="$(ulimit -n)" - [ "${before}" = "${after}" ] || fail "limit changed on macOS without cargo-zigbuild (${before} -> ${after})" - ) - pass "no-op on macOS without cargo-zigbuild" - echo "All build-env tests passed." - exit 0 -fi - -# Darwin + cargo-zigbuild: the helper should raise a low soft limit. +# Darwin native Cargo builds need the same protection even when +# cargo-zigbuild is unavailable. ( if ! ulimit -Sn 256 2>/dev/null; then echo "SKIP: unable to lower soft limit to 256 for test" exit 0 fi - ensure_build_nofile_limit >/dev/null + PATH="/usr/bin:/bin" ensure_build_nofile_limit >/dev/null after="$(ulimit -n)" hard="$(ulimit -Hn 2>/dev/null || echo unlimited)" case "${hard}" in @@ -76,7 +62,7 @@ fi ;; esac ) -pass "raises low soft limit on macOS with cargo-zigbuild" +pass "raises low soft limit for native Cargo builds on macOS" # Idempotent: when the current limit already meets the desired value, the helper # leaves it unchanged (drive this via the env override so it holds regardless of