diff --git a/.github/actions/build-native/action.yml b/.github/actions/build-native/action.yml index 7a0da342a..97926f64e 100644 --- a/.github/actions/build-native/action.yml +++ b/.github/actions/build-native/action.yml @@ -125,6 +125,9 @@ runs: run: | sudo apt-get update sudo apt-get install -y build-essential + # audiopus_sys builds bundled libopus via CMake (Ninja generator for MSVC + # cross); GitHub-hosted images ship cmake/ninja, the omp-kata pods do not. + - uses: ./.github/actions/ensure-cmake - name: Prepend rustup toolchain bin to PATH (GitHub-hosted) if: steps.detect.outputs.on_infra == 'false' shell: bash @@ -161,7 +164,13 @@ runs: echo "Using caller-provided RUSTFLAGS=$RUSTFLAGS" exit 0 fi - rustflags="-C target-cpu=native" + # Non-x64 native builds (darwin arm64) keep the target's default + # CPU features. `-C target-cpu=native` both baked the CI host's + # CPU features into shipped artifacts and trips ring 0.17's + # aarch64-apple const assertion (CAPS_STATIC == MIN_STATIC_FEATURES) + # once extra static features are enabled. + echo "Using default target CPU features (no RUSTFLAGS)" + exit 0 ;; esac diff --git a/.github/actions/ensure-cmake/action.yml b/.github/actions/ensure-cmake/action.yml new file mode 100644 index 000000000..4ff374481 --- /dev/null +++ b/.github/actions/ensure-cmake/action.yml @@ -0,0 +1,80 @@ +name: "ensure cmake" +description: >- + Ensure cmake (and ninja on Linux) are on PATH for native builds that compile + bundled C libraries (audiopus_sys builds libopus via CMake; MSVC cross builds + generate with Ninja). No-op when the runner image already ships them + (GitHub-hosted images do); self-heals on the omp-kata pods by installing + pinned binaries into ~/.local. + +inputs: + cmake-version: + required: false + default: "4.1.2" + description: CMake release version installed when cmake is missing + ninja-version: + required: false + default: "1.13.1" + description: Ninja release version installed when ninja is missing (Linux only) + +runs: + using: composite + steps: + - shell: bash + env: + CMAKE_VERSION: ${{ inputs.cmake-version }} + NINJA_VERSION: ${{ inputs.ninja-version }} + run: | + set -euo pipefail + destdir="${HOME}/.local" + mkdir -p "$destdir" + + if command -v cmake >/dev/null 2>&1 && cmake --version >/dev/null 2>&1; then + echo "Using preinstalled $(cmake --version | head -n1)" + else + case "$(uname -s)-$(uname -m)" in + Linux-x86_64) archive="cmake-${CMAKE_VERSION}-linux-x86_64" ;; + Linux-aarch64) archive="cmake-${CMAKE_VERSION}-linux-aarch64" ;; + Darwin-*) archive="cmake-${CMAKE_VERSION}-macos-universal" ;; + *) + echo "Unsupported cmake host: $(uname -s)-$(uname -m)" >&2 + exit 1 + ;; + esac + rm -rf "${destdir:?}/${archive}" + curl -fsSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${archive}.tar.gz" -o "${destdir}/cmake.tar.gz" + tar -xzf "${destdir}/cmake.tar.gz" -C "$destdir" + rm -f "${destdir}/cmake.tar.gz" + case "$archive" in + *macos*) bindir="${destdir}/${archive}/CMake.app/Contents/bin" ;; + *) bindir="${destdir}/${archive}/bin" ;; + esac + echo "$bindir" >> "$GITHUB_PATH" + echo "Installed $("${bindir}/cmake" --version | head -n1)" + fi + + # Ninja is only needed on Linux hosts: cmake-rs generates MSVC cross + # builds (cargo-xwin) with the Ninja generator. macOS images ship it. + if [ "$(uname -s)" = "Linux" ] && ! command -v ninja >/dev/null 2>&1; then + case "$(uname -m)" in + x86_64) zip="ninja-linux.zip" ;; + aarch64) zip="ninja-linux-aarch64.zip" ;; + *) + echo "Unsupported ninja host: $(uname -m)" >&2 + exit 1 + ;; + esac + bindir="${destdir}/ninja-${NINJA_VERSION}" + mkdir -p "$bindir" + curl -fsSL "https://github.com/ninja-build/ninja/releases/download/v${NINJA_VERSION}/${zip}" -o "${bindir}/ninja.zip" + if command -v unzip >/dev/null 2>&1; then + unzip -oq "${bindir}/ninja.zip" -d "$bindir" + elif command -v bsdtar >/dev/null 2>&1; then + bsdtar -xf "${bindir}/ninja.zip" -C "$bindir" + else + python3 -m zipfile -e "${bindir}/ninja.zip" "$bindir" + fi + rm -f "${bindir}/ninja.zip" + chmod +x "${bindir}/ninja" + echo "$bindir" >> "$GITHUB_PATH" + echo "Installed ninja $("${bindir}/ninja" --version)" + fi diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c8aa4aa15..7d0a69165 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,6 +36,10 @@ env: # cargo-zigbuild against this floor keeps them portable. Bump to raise the # minimum supported glibc. GLIBC_FLOOR: "2.17" + # audiopus_sys bundles an opus tree whose CMakeLists declares a + # cmake_minimum_required below 3.5; CMake 4.x refuses to configure it + # without this override (macOS runner images ship CMake 4). + CMAKE_POLICY_VERSION_MINIMUM: "3.5" permissions: contents: read @@ -510,6 +514,7 @@ jobs: - uses: ./.github/actions/ensure-rust-toolchain with: toolchain: nightly-2026-04-29 + - uses: ./.github/actions/ensure-cmake - name: Detect runner environment id: detect shell: bash diff --git a/packages/natives/CHANGELOG.md b/packages/natives/CHANGELOG.md index 73a5a6a5e..a06f9ac94 100644 --- a/packages/natives/CHANGELOG.md +++ b/packages/natives/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed native addon builds with CMake 4.x (bundled opus policy floor) and stopped passing `-C target-cpu=native` on darwin arm64, which baked build-host CPU features into shipped addons and broke `ring` compilation. + ## [17.1.1] - 2026-07-24 ### Added diff --git a/packages/natives/scripts/build-native.ts b/packages/natives/scripts/build-native.ts index 06760d4d3..df54f8f23 100644 --- a/packages/natives/scripts/build-native.ts +++ b/packages/natives/scripts/build-native.ts @@ -8,6 +8,11 @@ import { generateEnumExports } from "./gen-enums"; // must not retain host Homebrew paths such as /opt/homebrew/opt/pcre2/*.dylib. process.env.PCRE2_SYS_STATIC ??= "1"; +// audiopus_sys builds its bundled opus via CMake; that opus tree declares a +// cmake_minimum_required below 3.5, which CMake 4.x refuses without this +// policy override. +process.env.CMAKE_POLICY_VERSION_MINIMUM ??= "3.5"; + const repoRoot = path.join(import.meta.dir, "../../.."); const rustDir = path.join(repoRoot, "crates/pi-natives"); const nativeDir = path.join(import.meta.dir, "../native"); @@ -44,14 +49,15 @@ const effectiveVariant = resolveEffectiveVariant(); const variantSuffix = effectiveVariant ? `-${effectiveVariant}` : ""; // Pin Rust target-cpu so x64 baseline/modern variants get a reproducible ISA floor -// instead of inheriting the host CPU when RUSTFLAGS is unset. +// instead of inheriting the host CPU when RUSTFLAGS is unset. Non-x64 builds keep +// the target's default CPU features: `-C target-cpu=native` would bake the build +// host's CPU features into shipped artifacts and trips ring 0.17's aarch64-apple +// const assertion (CAPS_STATIC == MIN_STATIC_FEATURES). if (!isCrossCompile && !Bun.env.RUSTFLAGS) { if (effectiveVariant === "modern") { Bun.env.RUSTFLAGS = "-C target-cpu=x86-64-v3"; } else if (effectiveVariant === "baseline") { Bun.env.RUSTFLAGS = "-C target-cpu=x86-64-v2"; - } else { - Bun.env.RUSTFLAGS = "-C target-cpu=native"; } }