From 18279c56256ae5cd393089f3f1ca5daf5cf0da91 Mon Sep 17 00:00:00 2001 From: John Myers <9696606+johntmyers@users.noreply.github.com> Date: Fri, 10 Apr 2026 07:19:50 -0700 Subject: [PATCH 01/16] fix(docker): add openshell-prover to Dockerfile skeleton stages The openshell-prover crate was added as a dependency of openshell-cli in #741 but the Docker build infrastructure was not updated. Cargo workspace resolution requires every crate manifest to be present even when only building a subset of packages. Add openshell-prover Cargo.toml, mkdir, and stub lib.rs to the skeleton stages of all affected Dockerfiles. Also add the previously missing openshell-policy and openshell-tui entries to the python-wheels Dockerfiles where they were absent. --- deploy/docker/Dockerfile.cli-macos | 5 ++++- deploy/docker/Dockerfile.python-wheels | 10 ++++++++-- deploy/docker/Dockerfile.python-wheels-macos | 10 ++++++++-- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/deploy/docker/Dockerfile.cli-macos b/deploy/docker/Dockerfile.cli-macos index 93c5fc716..7d9188e79 100644 --- a/deploy/docker/Dockerfile.cli-macos +++ b/deploy/docker/Dockerfile.cli-macos @@ -61,25 +61,28 @@ COPY crates/openshell-core/Cargo.toml crates/openshell-core/Cargo.toml COPY crates/openshell-policy/Cargo.toml crates/openshell-policy/Cargo.toml COPY crates/openshell-providers/Cargo.toml crates/openshell-providers/Cargo.toml COPY crates/openshell-tui/Cargo.toml crates/openshell-tui/Cargo.toml +COPY crates/openshell-prover/Cargo.toml crates/openshell-prover/Cargo.toml COPY crates/openshell-core/build.rs crates/openshell-core/build.rs COPY proto/ proto/ # Scope workspace to CLI crates only — avoids compiling aws-lc-sys (pulled # by russh in openshell-sandbox/openshell-server) which is difficult to # cross-compile and unnecessary for the CLI binary. -RUN sed -i 's|members = \["crates/\*"\]|members = ["crates/openshell-cli", "crates/openshell-core", "crates/openshell-bootstrap", "crates/openshell-policy", "crates/openshell-providers", "crates/openshell-tui"]|' Cargo.toml +RUN sed -i 's|members = \["crates/\*"\]|members = ["crates/openshell-cli", "crates/openshell-core", "crates/openshell-bootstrap", "crates/openshell-policy", "crates/openshell-prover", "crates/openshell-providers", "crates/openshell-tui"]|' Cargo.toml RUN mkdir -p crates/openshell-cli/src \ crates/openshell-core/src \ crates/openshell-bootstrap/src \ crates/openshell-policy/src \ crates/openshell-providers/src \ + crates/openshell-prover/src \ crates/openshell-tui/src && \ echo "fn main() {}" > crates/openshell-cli/src/main.rs && \ touch crates/openshell-core/src/lib.rs && \ touch crates/openshell-bootstrap/src/lib.rs && \ touch crates/openshell-policy/src/lib.rs && \ touch crates/openshell-providers/src/lib.rs && \ + touch crates/openshell-prover/src/lib.rs && \ touch crates/openshell-tui/src/lib.rs RUN --mount=type=cache,id=cargo-registry-cli-macos,sharing=locked,target=/root/.cargo/registry \ diff --git a/deploy/docker/Dockerfile.python-wheels b/deploy/docker/Dockerfile.python-wheels index 78d4dc827..a36de8648 100644 --- a/deploy/docker/Dockerfile.python-wheels +++ b/deploy/docker/Dockerfile.python-wheels @@ -46,11 +46,14 @@ COPY crates/openshell-router/Cargo.toml crates/openshell-router/Cargo.toml COPY crates/openshell-sandbox/Cargo.toml crates/openshell-sandbox/Cargo.toml COPY crates/openshell-server/Cargo.toml crates/openshell-server/Cargo.toml COPY crates/openshell-bootstrap/Cargo.toml crates/openshell-bootstrap/Cargo.toml +COPY crates/openshell-policy/Cargo.toml crates/openshell-policy/Cargo.toml +COPY crates/openshell-prover/Cargo.toml crates/openshell-prover/Cargo.toml +COPY crates/openshell-tui/Cargo.toml crates/openshell-tui/Cargo.toml COPY crates/openshell-core/build.rs crates/openshell-core/build.rs COPY proto/ proto/ # Create dummy source files to build dependencies. -RUN mkdir -p crates/openshell-cli/src crates/openshell-core/src crates/openshell-ocsf/src crates/openshell-providers/src crates/openshell-router/src crates/openshell-sandbox/src crates/openshell-server/src crates/openshell-bootstrap/src && \ +RUN mkdir -p crates/openshell-cli/src crates/openshell-core/src crates/openshell-ocsf/src crates/openshell-policy/src crates/openshell-providers/src crates/openshell-prover/src crates/openshell-router/src crates/openshell-sandbox/src crates/openshell-server/src crates/openshell-bootstrap/src crates/openshell-tui/src && \ echo "fn main() {}" > crates/openshell-cli/src/main.rs && \ echo "fn main() {}" > crates/openshell-sandbox/src/main.rs && \ echo "fn main() {}" > crates/openshell-server/src/main.rs && \ @@ -58,7 +61,10 @@ RUN mkdir -p crates/openshell-cli/src crates/openshell-core/src crates/openshell touch crates/openshell-ocsf/src/lib.rs && \ touch crates/openshell-providers/src/lib.rs && \ touch crates/openshell-router/src/lib.rs && \ - touch crates/openshell-bootstrap/src/lib.rs + touch crates/openshell-bootstrap/src/lib.rs && \ + touch crates/openshell-policy/src/lib.rs && \ + touch crates/openshell-prover/src/lib.rs && \ + touch crates/openshell-tui/src/lib.rs # Build dependencies only (cached unless Cargo.toml/lock changes). # sccache uses memcached in CI or the local disk cache mount for local dev. diff --git a/deploy/docker/Dockerfile.python-wheels-macos b/deploy/docker/Dockerfile.python-wheels-macos index 9b16ff234..7d581dc83 100644 --- a/deploy/docker/Dockerfile.python-wheels-macos +++ b/deploy/docker/Dockerfile.python-wheels-macos @@ -54,11 +54,14 @@ COPY crates/openshell-router/Cargo.toml crates/openshell-router/Cargo.toml COPY crates/openshell-sandbox/Cargo.toml crates/openshell-sandbox/Cargo.toml COPY crates/openshell-server/Cargo.toml crates/openshell-server/Cargo.toml COPY crates/openshell-bootstrap/Cargo.toml crates/openshell-bootstrap/Cargo.toml +COPY crates/openshell-policy/Cargo.toml crates/openshell-policy/Cargo.toml +COPY crates/openshell-prover/Cargo.toml crates/openshell-prover/Cargo.toml +COPY crates/openshell-tui/Cargo.toml crates/openshell-tui/Cargo.toml COPY crates/openshell-core/build.rs crates/openshell-core/build.rs COPY proto/ proto/ # Create dummy source files to build dependencies. -RUN mkdir -p crates/openshell-cli/src crates/openshell-core/src crates/openshell-ocsf/src crates/openshell-providers/src crates/openshell-router/src crates/openshell-sandbox/src crates/openshell-server/src crates/openshell-bootstrap/src && \ +RUN mkdir -p crates/openshell-cli/src crates/openshell-core/src crates/openshell-ocsf/src crates/openshell-policy/src crates/openshell-providers/src crates/openshell-prover/src crates/openshell-router/src crates/openshell-sandbox/src crates/openshell-server/src crates/openshell-bootstrap/src crates/openshell-tui/src && \ echo "fn main() {}" > crates/openshell-cli/src/main.rs && \ echo "fn main() {}" > crates/openshell-sandbox/src/main.rs && \ echo "fn main() {}" > crates/openshell-server/src/main.rs && \ @@ -66,7 +69,10 @@ RUN mkdir -p crates/openshell-cli/src crates/openshell-core/src crates/openshell touch crates/openshell-ocsf/src/lib.rs && \ touch crates/openshell-providers/src/lib.rs && \ touch crates/openshell-router/src/lib.rs && \ - touch crates/openshell-bootstrap/src/lib.rs + touch crates/openshell-bootstrap/src/lib.rs && \ + touch crates/openshell-policy/src/lib.rs && \ + touch crates/openshell-prover/src/lib.rs && \ + touch crates/openshell-tui/src/lib.rs # Build dependencies only (cached unless Cargo.toml/lock changes). RUN --mount=type=cache,id=cargo-registry-python-wheels-macos-${TARGETARCH},sharing=locked,target=/root/.cargo/registry \ From c07612f4a3d8c030729e8aaa93f47e6ec81b2850 Mon Sep 17 00:00:00 2001 From: John Myers <9696606+johntmyers@users.noreply.github.com> Date: Fri, 10 Apr 2026 07:28:09 -0700 Subject: [PATCH 02/16] fix(docker): provide z3 for CLI-building Dockerfiles The openshell-prover crate depends on z3. For Linux-targeted builds (python-wheels), install libz3-dev to link against the system library. For macOS cross-compilation (python-wheels-macos, cli-macos), compile z3 from source via the bundled-z3 feature since system libz3-dev only provides a Linux .so, not a macOS .dylib. Add a bundled-z3 forwarding feature to openshell-cli so both cargo and maturin can activate it uniformly. --- crates/openshell-cli/Cargo.toml | 1 + deploy/docker/Dockerfile.cli-macos | 4 ++-- deploy/docker/Dockerfile.python-wheels | 1 + deploy/docker/Dockerfile.python-wheels-macos | 5 +++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/openshell-cli/Cargo.toml b/crates/openshell-cli/Cargo.toml index a1c9a0b23..b3a006fdd 100644 --- a/crates/openshell-cli/Cargo.toml +++ b/crates/openshell-cli/Cargo.toml @@ -76,6 +76,7 @@ tracing-subscriber = { workspace = true } workspace = true [features] +bundled-z3 = ["openshell-prover/bundled-z3"] dev-settings = ["openshell-core/dev-settings"] [dev-dependencies] diff --git a/deploy/docker/Dockerfile.cli-macos b/deploy/docker/Dockerfile.cli-macos index 7d9188e79..35be5c6ca 100644 --- a/deploy/docker/Dockerfile.cli-macos +++ b/deploy/docker/Dockerfile.cli-macos @@ -88,7 +88,7 @@ RUN mkdir -p crates/openshell-cli/src \ RUN --mount=type=cache,id=cargo-registry-cli-macos,sharing=locked,target=/root/.cargo/registry \ --mount=type=cache,id=cargo-git-cli-macos,sharing=locked,target=/root/.cargo/git \ --mount=type=cache,id=cargo-target-cli-macos-${CARGO_TARGET_CACHE_SCOPE},sharing=locked,target=/build/target \ - cargo build --release --target aarch64-apple-darwin -p openshell-cli 2>/dev/null || true + cargo build --release --target aarch64-apple-darwin -p openshell-cli --features bundled-z3 2>/dev/null || true # --------------------------------------------------------------------------- # Stage 2: real build @@ -116,7 +116,7 @@ RUN --mount=type=cache,id=cargo-registry-cli-macos,sharing=locked,target=/root/. if [ -n "${OPENSHELL_CARGO_VERSION:-}" ]; then \ sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${OPENSHELL_CARGO_VERSION}"'"/}' Cargo.toml; \ fi && \ - cargo build --release --target aarch64-apple-darwin -p openshell-cli && \ + cargo build --release --target aarch64-apple-darwin -p openshell-cli --features bundled-z3 && \ cp target/aarch64-apple-darwin/release/openshell /openshell FROM scratch AS binary diff --git a/deploy/docker/Dockerfile.python-wheels b/deploy/docker/Dockerfile.python-wheels index a36de8648..325750071 100644 --- a/deploy/docker/Dockerfile.python-wheels +++ b/deploy/docker/Dockerfile.python-wheels @@ -15,6 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ gcc \ libc6-dev \ + libz3-dev \ pkg-config \ libssl-dev \ && rm -rf /var/lib/apt/lists/* diff --git a/deploy/docker/Dockerfile.python-wheels-macos b/deploy/docker/Dockerfile.python-wheels-macos index 7d581dc83..99c967649 100644 --- a/deploy/docker/Dockerfile.python-wheels-macos +++ b/deploy/docker/Dockerfile.python-wheels-macos @@ -23,6 +23,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ ca-certificates \ clang \ + cmake \ curl \ libssl-dev \ pkg-config \ @@ -78,7 +79,7 @@ RUN mkdir -p crates/openshell-cli/src crates/openshell-core/src crates/openshell RUN --mount=type=cache,id=cargo-registry-python-wheels-macos-${TARGETARCH},sharing=locked,target=/root/.cargo/registry \ --mount=type=cache,id=cargo-git-python-wheels-macos-${TARGETARCH},sharing=locked,target=/root/.cargo/git \ --mount=type=cache,id=cargo-target-python-wheels-macos-${TARGETARCH}-${CARGO_TARGET_CACHE_SCOPE},sharing=locked,target=/build/target \ - cargo build --release --target aarch64-apple-darwin -p openshell-cli 2>/dev/null || true + cargo build --release --target aarch64-apple-darwin -p openshell-cli --features bundled-z3 2>/dev/null || true # Copy actual source code and Python packaging files. COPY crates/ crates/ @@ -109,7 +110,7 @@ RUN --mount=type=cache,id=cargo-registry-python-wheels-macos-${TARGETARCH},shari if [ -n "${OPENSHELL_CARGO_VERSION:-}" ]; then \ sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${OPENSHELL_CARGO_VERSION}"'"/}' Cargo.toml; \ fi && \ - maturin build --release --target aarch64-apple-darwin --out /wheels + maturin build --release --target aarch64-apple-darwin --features bundled-z3 --out /wheels FROM scratch AS wheels COPY --from=builder /wheels/*.whl / From c0c0ff279703d12628f5e6e3590891c5fd899c8c Mon Sep 17 00:00:00 2001 From: John Myers <9696606+johntmyers@users.noreply.github.com> Date: Fri, 10 Apr 2026 07:39:24 -0700 Subject: [PATCH 03/16] fix(docker,ci): use bundled-z3 everywhere and add libclang-dev for bindgen Switch all CLI builds to bundled-z3 (compile z3 from source) instead of relying on system libz3-dev. This is required because: - Linux musl CLI builds cannot link against glibc libz3.so - macOS cross-compilation has no system z3 available - Distributable Python wheels should not depend on runtime libz3 Add libclang-dev to all CLI Dockerfiles since z3-sys uses bindgen which requires libclang at compile time. Add openshell-prover to the sed workspace scope in both release workflows so Cargo can resolve the path dependency from openshell-cli. --- .github/workflows/release-dev.yml | 4 ++-- .github/workflows/release-tag.yml | 4 ++-- deploy/docker/Dockerfile.cli-macos | 1 + deploy/docker/Dockerfile.python-wheels | 7 ++++--- deploy/docker/Dockerfile.python-wheels-macos | 1 + 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index 922b514b9..6ccb0cffe 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -211,7 +211,7 @@ jobs: # Remove workspace members that are not needed for openshell-cli. # This avoids Cargo feature-unification pulling in aws-lc-sys (via # russh in openshell-sandbox / openshell-server). - sed -i 's|members = \["crates/\*"\]|members = ["crates/openshell-cli", "crates/openshell-core", "crates/openshell-bootstrap", "crates/openshell-policy", "crates/openshell-providers", "crates/openshell-tui"]|' Cargo.toml + sed -i 's|members = \["crates/\*"\]|members = ["crates/openshell-cli", "crates/openshell-core", "crates/openshell-bootstrap", "crates/openshell-policy", "crates/openshell-prover", "crates/openshell-providers", "crates/openshell-tui"]|' Cargo.toml - name: Patch workspace version if: needs.compute-versions.outputs.cargo_version != '' @@ -220,7 +220,7 @@ jobs: sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${{ needs.compute-versions.outputs.cargo_version }}"'"/}' Cargo.toml - name: Build ${{ matrix.target }} - run: mise x -- cargo build --release --target ${{ matrix.target }} -p openshell-cli + run: mise x -- cargo build --release --target ${{ matrix.target }} -p openshell-cli --features bundled-z3 - name: sccache stats if: always() diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 0d1e3270a..720827860 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -233,7 +233,7 @@ jobs: # Remove workspace members that are not needed for openshell-cli. # This avoids Cargo feature-unification pulling in aws-lc-sys (via # russh in openshell-sandbox / openshell-server). - sed -i 's|members = \["crates/\*"\]|members = ["crates/openshell-cli", "crates/openshell-core", "crates/openshell-bootstrap", "crates/openshell-policy", "crates/openshell-providers", "crates/openshell-tui"]|' Cargo.toml + sed -i 's|members = \["crates/\*"\]|members = ["crates/openshell-cli", "crates/openshell-core", "crates/openshell-bootstrap", "crates/openshell-policy", "crates/openshell-prover", "crates/openshell-providers", "crates/openshell-tui"]|' Cargo.toml - name: Patch workspace version if: needs.compute-versions.outputs.cargo_version != '' @@ -242,7 +242,7 @@ jobs: sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${{ needs.compute-versions.outputs.cargo_version }}"'"/}' Cargo.toml - name: Build ${{ matrix.target }} - run: mise x -- cargo build --release --target ${{ matrix.target }} -p openshell-cli + run: mise x -- cargo build --release --target ${{ matrix.target }} -p openshell-cli --features bundled-z3 - name: sccache stats if: always() diff --git a/deploy/docker/Dockerfile.cli-macos b/deploy/docker/Dockerfile.cli-macos index 35be5c6ca..82e1a83b2 100644 --- a/deploy/docker/Dockerfile.cli-macos +++ b/deploy/docker/Dockerfile.cli-macos @@ -31,6 +31,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ clang \ cmake \ curl \ + libclang-dev \ pkg-config \ && rm -rf /var/lib/apt/lists/* diff --git a/deploy/docker/Dockerfile.python-wheels b/deploy/docker/Dockerfile.python-wheels index 325750071..91e2223c4 100644 --- a/deploy/docker/Dockerfile.python-wheels +++ b/deploy/docker/Dockerfile.python-wheels @@ -12,10 +12,11 @@ ENV PATH="/root/.cargo/bin:${PATH}" RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ + cmake \ curl \ gcc \ libc6-dev \ - libz3-dev \ + libclang-dev \ pkg-config \ libssl-dev \ && rm -rf /var/lib/apt/lists/* @@ -74,7 +75,7 @@ RUN --mount=type=cache,id=cargo-registry-python-wheels-${TARGETARCH},sharing=loc --mount=type=cache,id=cargo-git-python-wheels-${TARGETARCH},sharing=locked,target=/root/.cargo/git \ --mount=type=cache,id=cargo-target-python-wheels-${TARGETARCH}-${CARGO_TARGET_CACHE_SCOPE},sharing=locked,target=/build/target \ --mount=type=cache,id=sccache-python-wheels-${TARGETARCH},sharing=locked,target=/tmp/sccache \ - . cross-build.sh && cargo_cross_build --release -p openshell-cli 2>/dev/null || true + . cross-build.sh && cargo_cross_build --release -p openshell-cli --features bundled-z3 2>/dev/null || true # Copy actual source code and Python packaging files. COPY crates/ crates/ @@ -108,7 +109,7 @@ RUN --mount=type=cache,id=cargo-registry-python-wheels-${TARGETARCH},sharing=loc if [ -n "${OPENSHELL_CARGO_VERSION:-}" ]; then \ sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${OPENSHELL_CARGO_VERSION}"'"/}' Cargo.toml; \ fi && \ - maturin build --release --target "${CARGO_BUILD_TARGET}" --out /wheels + maturin build --release --target "${CARGO_BUILD_TARGET}" --features bundled-z3 --out /wheels FROM scratch AS wheels COPY --from=builder /wheels/*.whl / diff --git a/deploy/docker/Dockerfile.python-wheels-macos b/deploy/docker/Dockerfile.python-wheels-macos index 99c967649..0c0b316c8 100644 --- a/deploy/docker/Dockerfile.python-wheels-macos +++ b/deploy/docker/Dockerfile.python-wheels-macos @@ -25,6 +25,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ clang \ cmake \ curl \ + libclang-dev \ libssl-dev \ pkg-config \ && rm -rf /var/lib/apt/lists/* From 494ca205eeb52bf6fb61dc0b9a9d015321284a17 Mon Sep 17 00:00:00 2001 From: John Myers <9696606+johntmyers@users.noreply.github.com> Date: Fri, 10 Apr 2026 07:47:48 -0700 Subject: [PATCH 04/16] fix(ci): set CXX for musl targets so z3 bundled cmake can find a C++ compiler musl-tools only provides musl-gcc (C compiler wrapper), not musl-g++. The z3 bundled cmake build needs a C++ compiler to compile z3 from source. Use the system g++ since z3 exposes a C-linkage API and libstdc++ is statically linked in the final musl binary. --- .github/workflows/release-dev.yml | 6 ++++++ .github/workflows/release-tag.yml | 3 +++ 2 files changed, 9 insertions(+) diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index 6ccb0cffe..85bfc9a9e 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -220,6 +220,12 @@ jobs: sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${{ needs.compute-versions.outputs.cargo_version }}"'"/}' Cargo.toml - name: Build ${{ matrix.target }} + env: + # musl-tools only provides musl-gcc (C); z3 bundled build needs a + # C++ compiler. The system g++ works because z3's public API uses + # C linkage and libstdc++ is statically linked in the final binary. + CXX_aarch64_unknown_linux_musl: g++ + CXX_x86_64_unknown_linux_musl: g++ run: mise x -- cargo build --release --target ${{ matrix.target }} -p openshell-cli --features bundled-z3 - name: sccache stats diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 720827860..b9f4782e6 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -242,6 +242,9 @@ jobs: sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${{ needs.compute-versions.outputs.cargo_version }}"'"/}' Cargo.toml - name: Build ${{ matrix.target }} + env: + CXX_aarch64_unknown_linux_musl: g++ + CXX_x86_64_unknown_linux_musl: g++ run: mise x -- cargo build --release --target ${{ matrix.target }} -p openshell-cli --features bundled-z3 - name: sccache stats From 907a039f04c2aba09c015f3e707e12cb465d00e0 Mon Sep 17 00:00:00 2001 From: John Myers <9696606+johntmyers@users.noreply.github.com> Date: Fri, 10 Apr 2026 08:06:03 -0700 Subject: [PATCH 05/16] fix(ci): create musl-g++ wrapper so z3 compiles against musl headers Using system g++ directly produces object files with glibc symbols like __printf_chk that don't exist in musl. Instead, create a musl-g++ wrapper that mirrors musl-gcc: it invokes g++ with the musl-gcc.specs file, which redirects include and library paths to musl. This ensures z3 compiles against musl headers and avoids glibc symbol references. --- .github/workflows/release-dev.yml | 17 ++++++++++++----- .github/workflows/release-tag.yml | 11 +++++++++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index 85bfc9a9e..1894088a3 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -202,6 +202,16 @@ jobs: apt-get install -y --no-install-recommends musl-tools rm -rf /var/lib/apt/lists/* + - name: Create musl-g++ wrapper + run: | + set -euo pipefail + # musl-tools ships musl-gcc (C wrapper) but not a C++ equivalent. + # z3's bundled cmake build needs a C++ compiler that targets musl. + # Extract the specs path from musl-gcc and create a parallel g++ wrapper. + SPECS=$(sed -n 's/.*-specs "\([^"]*\)".*/\1/p' "$(which musl-gcc)") + printf '#!/bin/sh\nexec g++ "$@" -specs "%s"\n' "$SPECS" > /usr/local/bin/musl-g++ + chmod +x /usr/local/bin/musl-g++ + - name: Add Rust musl target run: mise x -- rustup target add ${{ matrix.target }} @@ -221,11 +231,8 @@ jobs: - name: Build ${{ matrix.target }} env: - # musl-tools only provides musl-gcc (C); z3 bundled build needs a - # C++ compiler. The system g++ works because z3's public API uses - # C linkage and libstdc++ is statically linked in the final binary. - CXX_aarch64_unknown_linux_musl: g++ - CXX_x86_64_unknown_linux_musl: g++ + CXX_aarch64_unknown_linux_musl: musl-g++ + CXX_x86_64_unknown_linux_musl: musl-g++ run: mise x -- cargo build --release --target ${{ matrix.target }} -p openshell-cli --features bundled-z3 - name: sccache stats diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index b9f4782e6..9d28aa642 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -224,6 +224,13 @@ jobs: apt-get install -y --no-install-recommends musl-tools rm -rf /var/lib/apt/lists/* + - name: Create musl-g++ wrapper + run: | + set -euo pipefail + SPECS=$(sed -n 's/.*-specs "\([^"]*\)".*/\1/p' "$(which musl-gcc)") + printf '#!/bin/sh\nexec g++ "$@" -specs "%s"\n' "$SPECS" > /usr/local/bin/musl-g++ + chmod +x /usr/local/bin/musl-g++ + - name: Add Rust musl target run: mise x -- rustup target add ${{ matrix.target }} @@ -243,8 +250,8 @@ jobs: - name: Build ${{ matrix.target }} env: - CXX_aarch64_unknown_linux_musl: g++ - CXX_x86_64_unknown_linux_musl: g++ + CXX_aarch64_unknown_linux_musl: musl-g++ + CXX_x86_64_unknown_linux_musl: musl-g++ run: mise x -- cargo build --release --target ${{ matrix.target }} -p openshell-cli --features bundled-z3 - name: sccache stats From 4141c7bfb138bb774d1f871b378e029dd93dba4a Mon Sep 17 00:00:00 2001 From: John Myers <9696606+johntmyers@users.noreply.github.com> Date: Fri, 10 Apr 2026 08:13:16 -0700 Subject: [PATCH 06/16] fix(ci): simplify musl-g++ wrapper to only disable FORTIFY_SOURCE The musl-gcc.specs approach strips all system include paths via -nostdinc, which removes C++ standard library headers and breaks std::atomic detection in z3's cmake build. Simpler approach: the only glibc-specific symbols z3 was pulling in were __printf_chk and similar __*_chk functions generated by _FORTIFY_SOURCE hardening. Disabling _FORTIFY_SOURCE makes g++ emit standard printf/memcpy/etc. calls that musl provides, while keeping all C++ headers intact. --- .github/workflows/release-dev.yml | 11 +++++++---- .github/workflows/release-tag.yml | 3 +-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index 1894088a3..bd1004276 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -206,10 +206,13 @@ jobs: run: | set -euo pipefail # musl-tools ships musl-gcc (C wrapper) but not a C++ equivalent. - # z3's bundled cmake build needs a C++ compiler that targets musl. - # Extract the specs path from musl-gcc and create a parallel g++ wrapper. - SPECS=$(sed -n 's/.*-specs "\([^"]*\)".*/\1/p' "$(which musl-gcc)") - printf '#!/bin/sh\nexec g++ "$@" -specs "%s"\n' "$SPECS" > /usr/local/bin/musl-g++ + # z3's cmake build needs a C++ compiler for the musl target. + # Using the musl-gcc.specs with g++ breaks C++ headers (-nostdinc + # strips them). Instead, disable _FORTIFY_SOURCE which is the only + # source of glibc-specific symbols (__printf_chk, __memcpy_chk, etc.) + # that musl doesn't provide. Standard C/C++ symbols are fine — musl + # implements them all. + printf '#!/bin/sh\nexec g++ -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 "$@"\n' > /usr/local/bin/musl-g++ chmod +x /usr/local/bin/musl-g++ - name: Add Rust musl target diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 9d28aa642..57b1f0e77 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -227,8 +227,7 @@ jobs: - name: Create musl-g++ wrapper run: | set -euo pipefail - SPECS=$(sed -n 's/.*-specs "\([^"]*\)".*/\1/p' "$(which musl-gcc)") - printf '#!/bin/sh\nexec g++ "$@" -specs "%s"\n' "$SPECS" > /usr/local/bin/musl-g++ + printf '#!/bin/sh\nexec g++ -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 "$@"\n' > /usr/local/bin/musl-g++ chmod +x /usr/local/bin/musl-g++ - name: Add Rust musl target From e795d550772489da30d38c9d0e29c4e2754c712c Mon Sep 17 00:00:00 2001 From: John Myers <9696606+johntmyers@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:27:54 -0700 Subject: [PATCH 07/16] fix(release): build z3 in release artifacts --- .github/workflows/release-dev.yml | 72 ++++--------- .github/workflows/release-tag.yml | 65 ++++-------- deploy/docker/Dockerfile.cli-macos | 4 + deploy/docker/Dockerfile.cli-musl | 104 +++++++++++++++++++ deploy/docker/Dockerfile.python-wheels-macos | 4 + 5 files changed, 148 insertions(+), 101 deletions(-) create mode 100644 deploy/docker/Dockerfile.cli-musl diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index bd1004276..4c7407808 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -157,9 +157,11 @@ jobs: matrix: include: - arch: amd64 + docker_platform: linux/amd64 runner: build-amd64 target: x86_64-unknown-linux-musl - arch: arm64 + docker_platform: linux/arm64 runner: build-arm64 target: aarch64-unknown-linux-musl runs-on: ${{ matrix.runner }} @@ -170,6 +172,8 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --privileged + volumes: + - /var/run/docker.sock:/var/run/docker.sock env: MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SCCACHE_MEMCACHED_ENDPOINT: ${{ vars.SCCACHE_MEMCACHED_ENDPOINT }} @@ -185,69 +189,29 @@ jobs: - name: Fetch tags run: git fetch --tags --force - - name: Install tools - run: mise install - - - name: Cache Rust target and registry - uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2 - with: - shared-key: cli-musl-${{ matrix.arch }} - cache-directories: .cache/sccache - cache-targets: "true" - - - name: Install musl toolchain - run: | - set -euo pipefail - apt-get update - apt-get install -y --no-install-recommends musl-tools - rm -rf /var/lib/apt/lists/* - - - name: Create musl-g++ wrapper - run: | - set -euo pipefail - # musl-tools ships musl-gcc (C wrapper) but not a C++ equivalent. - # z3's cmake build needs a C++ compiler for the musl target. - # Using the musl-gcc.specs with g++ breaks C++ headers (-nostdinc - # strips them). Instead, disable _FORTIFY_SOURCE which is the only - # source of glibc-specific symbols (__printf_chk, __memcpy_chk, etc.) - # that musl doesn't provide. Standard C/C++ symbols are fine — musl - # implements them all. - printf '#!/bin/sh\nexec g++ -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 "$@"\n' > /usr/local/bin/musl-g++ - chmod +x /usr/local/bin/musl-g++ - - - name: Add Rust musl target - run: mise x -- rustup target add ${{ matrix.target }} - - - name: Scope workspace to CLI crates - run: | - set -euo pipefail - # Remove workspace members that are not needed for openshell-cli. - # This avoids Cargo feature-unification pulling in aws-lc-sys (via - # russh in openshell-sandbox / openshell-server). - sed -i 's|members = \["crates/\*"\]|members = ["crates/openshell-cli", "crates/openshell-core", "crates/openshell-bootstrap", "crates/openshell-policy", "crates/openshell-prover", "crates/openshell-providers", "crates/openshell-tui"]|' Cargo.toml + - name: Set up Docker Buildx + uses: ./.github/actions/setup-buildx - - name: Patch workspace version - if: needs.compute-versions.outputs.cargo_version != '' + - name: Build ${{ matrix.target }} via Docker run: | set -euo pipefail - sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${{ needs.compute-versions.outputs.cargo_version }}"'"/}' Cargo.toml - - - name: Build ${{ matrix.target }} - env: - CXX_aarch64_unknown_linux_musl: musl-g++ - CXX_x86_64_unknown_linux_musl: musl-g++ - run: mise x -- cargo build --release --target ${{ matrix.target }} -p openshell-cli --features bundled-z3 - - - name: sccache stats - if: always() - run: mise x -- sccache --show-stats + docker buildx build \ + --platform "${{ matrix.docker_platform }}" \ + --file deploy/docker/Dockerfile.cli-musl \ + --build-arg TARGET_TRIPLE="${{ matrix.target }}" \ + --build-arg OPENSHELL_CARGO_VERSION="${{ needs.compute-versions.outputs.cargo_version }}" \ + --build-arg OPENSHELL_IMAGE_TAG=dev \ + --build-arg CARGO_TARGET_CACHE_SCOPE="${{ github.sha }}" \ + --target binary \ + --output type=local,dest=out/ \ + . - name: Package binary run: | set -euo pipefail mkdir -p artifacts tar -czf artifacts/openshell-${{ matrix.target }}.tar.gz \ - -C target/${{ matrix.target }}/release openshell + -C out openshell ls -lh artifacts/ - name: Upload artifact diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 57b1f0e77..af938e675 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -178,9 +178,11 @@ jobs: matrix: include: - arch: amd64 + docker_platform: linux/amd64 runner: build-amd64 target: x86_64-unknown-linux-musl - arch: arm64 + docker_platform: linux/arm64 runner: build-arm64 target: aarch64-unknown-linux-musl runs-on: ${{ matrix.runner }} @@ -191,6 +193,8 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --privileged + volumes: + - /var/run/docker.sock:/var/run/docker.sock env: MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SCCACHE_MEMCACHED_ENDPOINT: ${{ vars.SCCACHE_MEMCACHED_ENDPOINT }} @@ -207,62 +211,29 @@ jobs: - name: Fetch tags run: git fetch --tags --force - - name: Install tools - run: mise install - - - name: Cache Rust target and registry - uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2 - with: - shared-key: cli-musl-${{ matrix.arch }} - cache-directories: .cache/sccache - cache-targets: "true" - - - name: Install musl toolchain - run: | - set -euo pipefail - apt-get update - apt-get install -y --no-install-recommends musl-tools - rm -rf /var/lib/apt/lists/* - - - name: Create musl-g++ wrapper - run: | - set -euo pipefail - printf '#!/bin/sh\nexec g++ -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 "$@"\n' > /usr/local/bin/musl-g++ - chmod +x /usr/local/bin/musl-g++ - - - name: Add Rust musl target - run: mise x -- rustup target add ${{ matrix.target }} - - - name: Scope workspace to CLI crates - run: | - set -euo pipefail - # Remove workspace members that are not needed for openshell-cli. - # This avoids Cargo feature-unification pulling in aws-lc-sys (via - # russh in openshell-sandbox / openshell-server). - sed -i 's|members = \["crates/\*"\]|members = ["crates/openshell-cli", "crates/openshell-core", "crates/openshell-bootstrap", "crates/openshell-policy", "crates/openshell-prover", "crates/openshell-providers", "crates/openshell-tui"]|' Cargo.toml + - name: Set up Docker Buildx + uses: ./.github/actions/setup-buildx - - name: Patch workspace version - if: needs.compute-versions.outputs.cargo_version != '' + - name: Build ${{ matrix.target }} via Docker run: | set -euo pipefail - sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${{ needs.compute-versions.outputs.cargo_version }}"'"/}' Cargo.toml - - - name: Build ${{ matrix.target }} - env: - CXX_aarch64_unknown_linux_musl: musl-g++ - CXX_x86_64_unknown_linux_musl: musl-g++ - run: mise x -- cargo build --release --target ${{ matrix.target }} -p openshell-cli --features bundled-z3 - - - name: sccache stats - if: always() - run: mise x -- sccache --show-stats + docker buildx build \ + --platform "${{ matrix.docker_platform }}" \ + --file deploy/docker/Dockerfile.cli-musl \ + --build-arg TARGET_TRIPLE="${{ matrix.target }}" \ + --build-arg OPENSHELL_CARGO_VERSION="${{ needs.compute-versions.outputs.cargo_version }}" \ + --build-arg OPENSHELL_IMAGE_TAG="${{ needs.compute-versions.outputs.semver }}" \ + --build-arg CARGO_TARGET_CACHE_SCOPE="${{ github.sha }}" \ + --target binary \ + --output type=local,dest=out/ \ + . - name: Package binary run: | set -euo pipefail mkdir -p artifacts tar -czf artifacts/openshell-${{ matrix.target }}.tar.gz \ - -C target/${{ matrix.target }}/release openshell + -C out openshell ls -lh artifacts/ - name: Upload artifact diff --git a/deploy/docker/Dockerfile.cli-macos b/deploy/docker/Dockerfile.cli-macos index 82e1a83b2..10982efd1 100644 --- a/deploy/docker/Dockerfile.cli-macos +++ b/deploy/docker/Dockerfile.cli-macos @@ -25,6 +25,8 @@ ENV LD_LIBRARY_PATH="/osxcross/lib" COPY --from=osxcross /osxcross /osxcross +RUN SDKROOT="$(echo /osxcross/SDK/MacOSX*.sdk)" && ln -sfn "${SDKROOT}" /osxcross/SDK/MacOSX.sdk + RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ ca-certificates \ @@ -50,6 +52,8 @@ ENV CXX_aarch64_apple_darwin=oa64-clang++ ENV AR_aarch64_apple_darwin=aarch64-apple-darwin25.1-ar ENV CARGO_TARGET_AARCH64_APPLE_DARWIN_LINKER=oa64-clang ENV CARGO_TARGET_AARCH64_APPLE_DARWIN_AR=aarch64-apple-darwin25.1-ar +ENV SDKROOT=/osxcross/SDK/MacOSX.sdk +ENV BINDGEN_EXTRA_CLANG_ARGS_aarch64_apple_darwin=--target=arm64-apple-macosx\ -isysroot\ ${SDKROOT} # --------------------------------------------------------------------------- # Stage 1: dependency caching — copy only manifests, create dummy sources, diff --git a/deploy/docker/Dockerfile.cli-musl b/deploy/docker/Dockerfile.cli-musl new file mode 100644 index 000000000..5999ac964 --- /dev/null +++ b/deploy/docker/Dockerfile.cli-musl @@ -0,0 +1,104 @@ +# syntax=docker/dockerfile:1.6 + +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +# Build a fully static OpenShell CLI binary inside a native musl environment. +# +# This avoids the glibc contamination that occurs when bundled-z3 is compiled +# with the Debian/Ubuntu host C++ toolchain and then linked into a musl target. + +ARG RUST_IMAGE=rust:1.88-alpine3.22 + +FROM ${RUST_IMAGE} AS builder + +ARG TARGET_TRIPLE +ARG CARGO_TARGET_CACHE_SCOPE=default + +ENV PATH="/usr/local/cargo/bin:${PATH}" +ENV LIBCLANG_PATH="/usr/lib" + +WORKDIR /build + +RUN apk add --no-cache \ + build-base \ + clang20-dev \ + llvm20-dev \ + cmake \ + musl-dev \ + perl \ + pkgconf \ + python3 + +RUN /usr/local/cargo/bin/rustup target add "${TARGET_TRIPLE}" + +# --------------------------------------------------------------------------- +# Stage 1: dependency caching — copy only manifests, create dummy sources, +# build dependencies. This layer is cached unless Cargo.toml/lock changes. +# --------------------------------------------------------------------------- +COPY Cargo.toml Cargo.lock ./ +COPY crates/openshell-bootstrap/Cargo.toml crates/openshell-bootstrap/Cargo.toml +COPY crates/openshell-cli/Cargo.toml crates/openshell-cli/Cargo.toml +COPY crates/openshell-core/Cargo.toml crates/openshell-core/Cargo.toml +COPY crates/openshell-policy/Cargo.toml crates/openshell-policy/Cargo.toml +COPY crates/openshell-providers/Cargo.toml crates/openshell-providers/Cargo.toml +COPY crates/openshell-tui/Cargo.toml crates/openshell-tui/Cargo.toml +COPY crates/openshell-prover/Cargo.toml crates/openshell-prover/Cargo.toml +COPY crates/openshell-core/build.rs crates/openshell-core/build.rs +COPY proto/ proto/ + +# Scope workspace to CLI crates only — avoids compiling unnecessary members. +RUN sed -i 's|members = \["crates/\*"\]|members = ["crates/openshell-cli", "crates/openshell-core", "crates/openshell-bootstrap", "crates/openshell-policy", "crates/openshell-prover", "crates/openshell-providers", "crates/openshell-tui"]|' Cargo.toml + +RUN mkdir -p crates/openshell-cli/src \ + crates/openshell-core/src \ + crates/openshell-bootstrap/src \ + crates/openshell-policy/src \ + crates/openshell-providers/src \ + crates/openshell-prover/src \ + crates/openshell-tui/src && \ + echo "fn main() {}" > crates/openshell-cli/src/main.rs && \ + touch crates/openshell-core/src/lib.rs && \ + touch crates/openshell-bootstrap/src/lib.rs && \ + touch crates/openshell-policy/src/lib.rs && \ + touch crates/openshell-providers/src/lib.rs && \ + touch crates/openshell-prover/src/lib.rs && \ + touch crates/openshell-tui/src/lib.rs + +RUN --mount=type=cache,id=cargo-registry-cli-musl-${TARGET_TRIPLE},sharing=locked,target=/usr/local/cargo/registry \ + --mount=type=cache,id=cargo-git-cli-musl-${TARGET_TRIPLE},sharing=locked,target=/usr/local/cargo/git \ + --mount=type=cache,id=cargo-target-cli-musl-${TARGET_TRIPLE}-${CARGO_TARGET_CACHE_SCOPE},sharing=locked,target=/build/target \ + /usr/local/cargo/bin/cargo build --release --target "${TARGET_TRIPLE}" -p openshell-cli --features bundled-z3 2>/dev/null || true + +# --------------------------------------------------------------------------- +# Stage 2: real build +# --------------------------------------------------------------------------- +COPY crates/ crates/ + +# Touch source files to ensure they're rebuilt (not the cached dummy). +RUN touch crates/openshell-cli/src/main.rs \ + crates/openshell-cli/src/lib.rs \ + crates/openshell-bootstrap/src/lib.rs \ + crates/openshell-core/src/lib.rs \ + crates/openshell-policy/src/lib.rs \ + crates/openshell-providers/src/lib.rs \ + crates/openshell-tui/src/lib.rs \ + crates/openshell-core/build.rs \ + proto/*.proto + +# Declare version ARGs here (not earlier) so the git-hash-bearing values do not +# invalidate the expensive dependency-build layers above on every commit. +ARG OPENSHELL_CARGO_VERSION +ARG OPENSHELL_IMAGE_TAG +RUN --mount=type=cache,id=cargo-registry-cli-musl-${TARGET_TRIPLE},sharing=locked,target=/usr/local/cargo/registry \ + --mount=type=cache,id=cargo-git-cli-musl-${TARGET_TRIPLE},sharing=locked,target=/usr/local/cargo/git \ + --mount=type=cache,id=cargo-target-cli-musl-${TARGET_TRIPLE}-${CARGO_TARGET_CACHE_SCOPE},sharing=locked,target=/build/target \ + if [ -n "${OPENSHELL_CARGO_VERSION:-}" ]; then \ + sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${OPENSHELL_CARGO_VERSION}"'"/}' Cargo.toml; \ + fi && \ + OPENSHELL_IMAGE_TAG="${OPENSHELL_IMAGE_TAG:-dev}" \ + /usr/local/cargo/bin/cargo build --release --target "${TARGET_TRIPLE}" -p openshell-cli --features bundled-z3 && \ + cp "target/${TARGET_TRIPLE}/release/openshell" /openshell + +FROM scratch AS binary +COPY --from=builder /openshell /openshell diff --git a/deploy/docker/Dockerfile.python-wheels-macos b/deploy/docker/Dockerfile.python-wheels-macos index 0c0b316c8..7d64c618d 100644 --- a/deploy/docker/Dockerfile.python-wheels-macos +++ b/deploy/docker/Dockerfile.python-wheels-macos @@ -19,6 +19,8 @@ ENV LD_LIBRARY_PATH="/osxcross/lib" COPY --from=osxcross /osxcross /osxcross +RUN SDKROOT="$(echo /osxcross/SDK/MacOSX*.sdk)" && ln -sfn "${SDKROOT}" /osxcross/SDK/MacOSX.sdk + RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ ca-certificates \ @@ -45,6 +47,8 @@ ENV CXX_aarch64_apple_darwin=oa64-clang++ ENV AR_aarch64_apple_darwin=aarch64-apple-darwin25.1-ar ENV CARGO_TARGET_AARCH64_APPLE_DARWIN_LINKER=oa64-clang ENV CARGO_TARGET_AARCH64_APPLE_DARWIN_AR=aarch64-apple-darwin25.1-ar +ENV SDKROOT=/osxcross/SDK/MacOSX.sdk +ENV BINDGEN_EXTRA_CLANG_ARGS_aarch64_apple_darwin=--target=arm64-apple-macosx\ -isysroot\ ${SDKROOT} # Copy dependency manifests first for better caching. COPY Cargo.toml Cargo.lock ./ From 92aa156069262de7c0bf74090a454c754b019648 Mon Sep 17 00:00:00 2001 From: Drew Newberry Date: Fri, 10 Apr 2026 11:43:04 -0700 Subject: [PATCH 08/16] fix(docker): allow build scripts to dlopen libclang in Alpine musl In Alpine, Rust build scripts are compiled for the musl host target which defaults to static linking. Static musl binaries cannot dlopen, causing bindgen to fail when loading libclang.so for z3 FFI generation. Set CARGO_HOST_RUSTFLAGS="-C target-feature=-crt-static" so build scripts are dynamically linked (can dlopen) while the target CLI binary stays static. --- deploy/docker/Dockerfile.cli-musl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/deploy/docker/Dockerfile.cli-musl b/deploy/docker/Dockerfile.cli-musl index 5999ac964..1af6d438c 100644 --- a/deploy/docker/Dockerfile.cli-musl +++ b/deploy/docker/Dockerfile.cli-musl @@ -17,6 +17,11 @@ ARG CARGO_TARGET_CACHE_SCOPE=default ENV PATH="/usr/local/cargo/bin:${PATH}" ENV LIBCLANG_PATH="/usr/lib" +# Build scripts (build.rs) are compiled for the host, which in Alpine defaults +# to static musl linking. Static musl binaries cannot dlopen, so bindgen fails +# to load libclang.so. Disabling crt-static for host builds makes build scripts +# dynamically linked while keeping the target CLI binary fully static. +ENV CARGO_HOST_RUSTFLAGS="-C target-feature=-crt-static" WORKDIR /build From 73721d6ac490b3365304a55f9628a3543b6700d6 Mon Sep 17 00:00:00 2001 From: Drew Newberry Date: Fri, 10 Apr 2026 12:13:44 -0700 Subject: [PATCH 09/16] fix(ci): use zig as musl C/C++ compiler for Linux CLI builds Replace the Alpine Docker-in-Docker approach (Dockerfile.cli-musl) with direct-on-host builds using zig cc/c++ to target musl. This eliminates: - Docker-in-Docker overhead and cache mount complexity - The libclang dlopen failure in Alpine (static musl binaries cannot dlopen) - ~15 min z3 C++ compilation without sccache Zig provides a first-class musl-targeting C/C++ toolchain that avoids glibc contamination (no _FORTIFY_SOURCE symbols) while running natively on the glibc CI host where bindgen/libclang and sccache work normally. --- .github/workflows/release-dev.yml | 68 ++++++++++++++----- .github/workflows/release-tag.yml | 68 ++++++++++++++----- deploy/docker/Dockerfile.cli-musl | 109 ------------------------------ mise.toml | 1 + 4 files changed, 101 insertions(+), 145 deletions(-) delete mode 100644 deploy/docker/Dockerfile.cli-musl diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index 4c7407808..5e010781c 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -149,6 +149,11 @@ jobs: # --------------------------------------------------------------------------- # Build CLI binaries (Linux musl — static, native on each arch) + # + # Builds run directly on the CI host (glibc Ubuntu). Zig provides a + # musl-targeting C/C++ compiler so that bundled-z3 produces musl-compatible + # objects without glibc contamination. This avoids Docker-in-Docker and + # lets sccache work normally. # --------------------------------------------------------------------------- build-cli-linux: name: Build CLI (Linux ${{ matrix.arch }}) @@ -157,13 +162,13 @@ jobs: matrix: include: - arch: amd64 - docker_platform: linux/amd64 runner: build-amd64 target: x86_64-unknown-linux-musl + zig_target: x86_64-linux-musl - arch: arm64 - docker_platform: linux/arm64 runner: build-arm64 target: aarch64-unknown-linux-musl + zig_target: aarch64-linux-musl runs-on: ${{ matrix.runner }} timeout-minutes: 60 container: @@ -172,8 +177,6 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --privileged - volumes: - - /var/run/docker.sock:/var/run/docker.sock env: MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SCCACHE_MEMCACHED_ENDPOINT: ${{ vars.SCCACHE_MEMCACHED_ENDPOINT }} @@ -189,29 +192,58 @@ jobs: - name: Fetch tags run: git fetch --tags --force - - name: Set up Docker Buildx - uses: ./.github/actions/setup-buildx + - name: Install tools + run: mise install + + - name: Cache Rust target and registry + uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2 + with: + shared-key: cli-musl-${{ matrix.arch }} + cache-directories: .cache/sccache + cache-targets: "true" - - name: Build ${{ matrix.target }} via Docker + - name: Add Rust musl target + run: mise x -- rustup target add ${{ matrix.target }} + + - name: Set up zig-musl toolchain run: | set -euo pipefail - docker buildx build \ - --platform "${{ matrix.docker_platform }}" \ - --file deploy/docker/Dockerfile.cli-musl \ - --build-arg TARGET_TRIPLE="${{ matrix.target }}" \ - --build-arg OPENSHELL_CARGO_VERSION="${{ needs.compute-versions.outputs.cargo_version }}" \ - --build-arg OPENSHELL_IMAGE_TAG=dev \ - --build-arg CARGO_TARGET_CACHE_SCOPE="${{ github.sha }}" \ - --target binary \ - --output type=local,dest=out/ \ - . + ZIG="$(mise which zig)" + mkdir -p /tmp/zig-musl + printf '#!/bin/sh\nexec "%s" cc --target=${{ matrix.zig_target }} "$@"\n' "$ZIG" > /tmp/zig-musl/cc + printf '#!/bin/sh\nexec "%s" c++ --target=${{ matrix.zig_target }} "$@"\n' "$ZIG" > /tmp/zig-musl/cxx + chmod +x /tmp/zig-musl/cc /tmp/zig-musl/cxx + + # Tell cargo / cc-rs / cmake to use zig for the musl target + TARGET_ENV=$(echo "${{ matrix.target }}" | tr '-' '_') + echo "CC_${TARGET_ENV}=/tmp/zig-musl/cc" >> "$GITHUB_ENV" + echo "CXX_${TARGET_ENV}=/tmp/zig-musl/cxx" >> "$GITHUB_ENV" + echo "CARGO_TARGET_${TARGET_ENV^^}_LINKER=/tmp/zig-musl/cc" >> "$GITHUB_ENV" + + - name: Scope workspace to CLI crates + run: | + set -euo pipefail + sed -i 's|members = \["crates/\*"\]|members = ["crates/openshell-cli", "crates/openshell-core", "crates/openshell-bootstrap", "crates/openshell-policy", "crates/openshell-prover", "crates/openshell-providers", "crates/openshell-tui"]|' Cargo.toml + + - name: Patch workspace version + if: needs.compute-versions.outputs.cargo_version != '' + run: | + set -euo pipefail + sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${{ needs.compute-versions.outputs.cargo_version }}"'"/}' Cargo.toml + + - name: Build ${{ matrix.target }} + run: mise x -- cargo build --release --target ${{ matrix.target }} -p openshell-cli --features bundled-z3 + + - name: sccache stats + if: always() + run: mise x -- sccache --show-stats - name: Package binary run: | set -euo pipefail mkdir -p artifacts tar -czf artifacts/openshell-${{ matrix.target }}.tar.gz \ - -C out openshell + -C target/${{ matrix.target }}/release openshell ls -lh artifacts/ - name: Upload artifact diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index af938e675..f00d6f819 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -170,6 +170,11 @@ jobs: # --------------------------------------------------------------------------- # Build CLI binaries (Linux musl — static, native on each arch) + # + # Builds run directly on the CI host (glibc Ubuntu). Zig provides a + # musl-targeting C/C++ compiler so that bundled-z3 produces musl-compatible + # objects without glibc contamination. This avoids Docker-in-Docker and + # lets sccache work normally. # --------------------------------------------------------------------------- build-cli-linux: name: Build CLI (Linux ${{ matrix.arch }}) @@ -178,13 +183,13 @@ jobs: matrix: include: - arch: amd64 - docker_platform: linux/amd64 runner: build-amd64 target: x86_64-unknown-linux-musl + zig_target: x86_64-linux-musl - arch: arm64 - docker_platform: linux/arm64 runner: build-arm64 target: aarch64-unknown-linux-musl + zig_target: aarch64-linux-musl runs-on: ${{ matrix.runner }} timeout-minutes: 60 container: @@ -193,8 +198,6 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --privileged - volumes: - - /var/run/docker.sock:/var/run/docker.sock env: MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SCCACHE_MEMCACHED_ENDPOINT: ${{ vars.SCCACHE_MEMCACHED_ENDPOINT }} @@ -211,29 +214,58 @@ jobs: - name: Fetch tags run: git fetch --tags --force - - name: Set up Docker Buildx - uses: ./.github/actions/setup-buildx + - name: Install tools + run: mise install + + - name: Cache Rust target and registry + uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2 + with: + shared-key: cli-musl-${{ matrix.arch }} + cache-directories: .cache/sccache + cache-targets: "true" - - name: Build ${{ matrix.target }} via Docker + - name: Add Rust musl target + run: mise x -- rustup target add ${{ matrix.target }} + + - name: Set up zig-musl toolchain run: | set -euo pipefail - docker buildx build \ - --platform "${{ matrix.docker_platform }}" \ - --file deploy/docker/Dockerfile.cli-musl \ - --build-arg TARGET_TRIPLE="${{ matrix.target }}" \ - --build-arg OPENSHELL_CARGO_VERSION="${{ needs.compute-versions.outputs.cargo_version }}" \ - --build-arg OPENSHELL_IMAGE_TAG="${{ needs.compute-versions.outputs.semver }}" \ - --build-arg CARGO_TARGET_CACHE_SCOPE="${{ github.sha }}" \ - --target binary \ - --output type=local,dest=out/ \ - . + ZIG="$(mise which zig)" + mkdir -p /tmp/zig-musl + printf '#!/bin/sh\nexec "%s" cc --target=${{ matrix.zig_target }} "$@"\n' "$ZIG" > /tmp/zig-musl/cc + printf '#!/bin/sh\nexec "%s" c++ --target=${{ matrix.zig_target }} "$@"\n' "$ZIG" > /tmp/zig-musl/cxx + chmod +x /tmp/zig-musl/cc /tmp/zig-musl/cxx + + # Tell cargo / cc-rs / cmake to use zig for the musl target + TARGET_ENV=$(echo "${{ matrix.target }}" | tr '-' '_') + echo "CC_${TARGET_ENV}=/tmp/zig-musl/cc" >> "$GITHUB_ENV" + echo "CXX_${TARGET_ENV}=/tmp/zig-musl/cxx" >> "$GITHUB_ENV" + echo "CARGO_TARGET_${TARGET_ENV^^}_LINKER=/tmp/zig-musl/cc" >> "$GITHUB_ENV" + + - name: Scope workspace to CLI crates + run: | + set -euo pipefail + sed -i 's|members = \["crates/\*"\]|members = ["crates/openshell-cli", "crates/openshell-core", "crates/openshell-bootstrap", "crates/openshell-policy", "crates/openshell-prover", "crates/openshell-providers", "crates/openshell-tui"]|' Cargo.toml + + - name: Patch workspace version + if: needs.compute-versions.outputs.cargo_version != '' + run: | + set -euo pipefail + sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${{ needs.compute-versions.outputs.cargo_version }}"'"/}' Cargo.toml + + - name: Build ${{ matrix.target }} + run: mise x -- cargo build --release --target ${{ matrix.target }} -p openshell-cli --features bundled-z3 + + - name: sccache stats + if: always() + run: mise x -- sccache --show-stats - name: Package binary run: | set -euo pipefail mkdir -p artifacts tar -czf artifacts/openshell-${{ matrix.target }}.tar.gz \ - -C out openshell + -C target/${{ matrix.target }}/release openshell ls -lh artifacts/ - name: Upload artifact diff --git a/deploy/docker/Dockerfile.cli-musl b/deploy/docker/Dockerfile.cli-musl deleted file mode 100644 index 1af6d438c..000000000 --- a/deploy/docker/Dockerfile.cli-musl +++ /dev/null @@ -1,109 +0,0 @@ -# syntax=docker/dockerfile:1.6 - -# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -# Build a fully static OpenShell CLI binary inside a native musl environment. -# -# This avoids the glibc contamination that occurs when bundled-z3 is compiled -# with the Debian/Ubuntu host C++ toolchain and then linked into a musl target. - -ARG RUST_IMAGE=rust:1.88-alpine3.22 - -FROM ${RUST_IMAGE} AS builder - -ARG TARGET_TRIPLE -ARG CARGO_TARGET_CACHE_SCOPE=default - -ENV PATH="/usr/local/cargo/bin:${PATH}" -ENV LIBCLANG_PATH="/usr/lib" -# Build scripts (build.rs) are compiled for the host, which in Alpine defaults -# to static musl linking. Static musl binaries cannot dlopen, so bindgen fails -# to load libclang.so. Disabling crt-static for host builds makes build scripts -# dynamically linked while keeping the target CLI binary fully static. -ENV CARGO_HOST_RUSTFLAGS="-C target-feature=-crt-static" - -WORKDIR /build - -RUN apk add --no-cache \ - build-base \ - clang20-dev \ - llvm20-dev \ - cmake \ - musl-dev \ - perl \ - pkgconf \ - python3 - -RUN /usr/local/cargo/bin/rustup target add "${TARGET_TRIPLE}" - -# --------------------------------------------------------------------------- -# Stage 1: dependency caching — copy only manifests, create dummy sources, -# build dependencies. This layer is cached unless Cargo.toml/lock changes. -# --------------------------------------------------------------------------- -COPY Cargo.toml Cargo.lock ./ -COPY crates/openshell-bootstrap/Cargo.toml crates/openshell-bootstrap/Cargo.toml -COPY crates/openshell-cli/Cargo.toml crates/openshell-cli/Cargo.toml -COPY crates/openshell-core/Cargo.toml crates/openshell-core/Cargo.toml -COPY crates/openshell-policy/Cargo.toml crates/openshell-policy/Cargo.toml -COPY crates/openshell-providers/Cargo.toml crates/openshell-providers/Cargo.toml -COPY crates/openshell-tui/Cargo.toml crates/openshell-tui/Cargo.toml -COPY crates/openshell-prover/Cargo.toml crates/openshell-prover/Cargo.toml -COPY crates/openshell-core/build.rs crates/openshell-core/build.rs -COPY proto/ proto/ - -# Scope workspace to CLI crates only — avoids compiling unnecessary members. -RUN sed -i 's|members = \["crates/\*"\]|members = ["crates/openshell-cli", "crates/openshell-core", "crates/openshell-bootstrap", "crates/openshell-policy", "crates/openshell-prover", "crates/openshell-providers", "crates/openshell-tui"]|' Cargo.toml - -RUN mkdir -p crates/openshell-cli/src \ - crates/openshell-core/src \ - crates/openshell-bootstrap/src \ - crates/openshell-policy/src \ - crates/openshell-providers/src \ - crates/openshell-prover/src \ - crates/openshell-tui/src && \ - echo "fn main() {}" > crates/openshell-cli/src/main.rs && \ - touch crates/openshell-core/src/lib.rs && \ - touch crates/openshell-bootstrap/src/lib.rs && \ - touch crates/openshell-policy/src/lib.rs && \ - touch crates/openshell-providers/src/lib.rs && \ - touch crates/openshell-prover/src/lib.rs && \ - touch crates/openshell-tui/src/lib.rs - -RUN --mount=type=cache,id=cargo-registry-cli-musl-${TARGET_TRIPLE},sharing=locked,target=/usr/local/cargo/registry \ - --mount=type=cache,id=cargo-git-cli-musl-${TARGET_TRIPLE},sharing=locked,target=/usr/local/cargo/git \ - --mount=type=cache,id=cargo-target-cli-musl-${TARGET_TRIPLE}-${CARGO_TARGET_CACHE_SCOPE},sharing=locked,target=/build/target \ - /usr/local/cargo/bin/cargo build --release --target "${TARGET_TRIPLE}" -p openshell-cli --features bundled-z3 2>/dev/null || true - -# --------------------------------------------------------------------------- -# Stage 2: real build -# --------------------------------------------------------------------------- -COPY crates/ crates/ - -# Touch source files to ensure they're rebuilt (not the cached dummy). -RUN touch crates/openshell-cli/src/main.rs \ - crates/openshell-cli/src/lib.rs \ - crates/openshell-bootstrap/src/lib.rs \ - crates/openshell-core/src/lib.rs \ - crates/openshell-policy/src/lib.rs \ - crates/openshell-providers/src/lib.rs \ - crates/openshell-tui/src/lib.rs \ - crates/openshell-core/build.rs \ - proto/*.proto - -# Declare version ARGs here (not earlier) so the git-hash-bearing values do not -# invalidate the expensive dependency-build layers above on every commit. -ARG OPENSHELL_CARGO_VERSION -ARG OPENSHELL_IMAGE_TAG -RUN --mount=type=cache,id=cargo-registry-cli-musl-${TARGET_TRIPLE},sharing=locked,target=/usr/local/cargo/registry \ - --mount=type=cache,id=cargo-git-cli-musl-${TARGET_TRIPLE},sharing=locked,target=/usr/local/cargo/git \ - --mount=type=cache,id=cargo-target-cli-musl-${TARGET_TRIPLE}-${CARGO_TARGET_CACHE_SCOPE},sharing=locked,target=/build/target \ - if [ -n "${OPENSHELL_CARGO_VERSION:-}" ]; then \ - sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${OPENSHELL_CARGO_VERSION}"'"/}' Cargo.toml; \ - fi && \ - OPENSHELL_IMAGE_TAG="${OPENSHELL_IMAGE_TAG:-dev}" \ - /usr/local/cargo/bin/cargo build --release --target "${TARGET_TRIPLE}" -p openshell-cli --features bundled-z3 && \ - cp "target/${TARGET_TRIPLE}/release/openshell" /openshell - -FROM scratch AS binary -COPY --from=builder /openshell /openshell diff --git a/mise.toml b/mise.toml index 12f67fdec..b045b563c 100644 --- a/mise.toml +++ b/mise.toml @@ -23,6 +23,7 @@ helm = "4.1.1" "ubi:mozilla/sccache" = { version = "0.14.0", matching = "sccache-v" } "ubi:anchore/syft" = { version = "1.42.3", matching = "syft_" } "ubi:EmbarkStudios/cargo-about" = "0.8.4" +zig = "0.14.1" [env] _.path = ["{{config_root}}/scripts/bin"] From 70ddc3d45f76e3038f09cb89cde0c74eaacbc6ee Mon Sep 17 00:00:00 2001 From: Drew Newberry Date: Fri, 10 Apr 2026 12:28:18 -0700 Subject: [PATCH 10/16] fix(ci): strip --target flags in zig wrappers for cc-rs compatibility cc-rs automatically injects --target= (e.g. aarch64-unknown-linux-musl) when invoking clang-like compilers. Zig cannot parse the 'unknown' vendor component in Rust target triples. The wrapper scripts now filter out any --target flags from the arguments and rely solely on the zig-native target specified by the wrapper itself. --- .github/workflows/release-dev.yml | 21 +++++++++++++++++---- .github/workflows/release-tag.yml | 21 +++++++++++++++++---- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index 5e010781c..85d9071ec 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -209,15 +209,28 @@ jobs: run: | set -euo pipefail ZIG="$(mise which zig)" + ZIG_TARGET="${{ matrix.zig_target }}" mkdir -p /tmp/zig-musl - printf '#!/bin/sh\nexec "%s" cc --target=${{ matrix.zig_target }} "$@"\n' "$ZIG" > /tmp/zig-musl/cc - printf '#!/bin/sh\nexec "%s" c++ --target=${{ matrix.zig_target }} "$@"\n' "$ZIG" > /tmp/zig-musl/cxx - chmod +x /tmp/zig-musl/cc /tmp/zig-musl/cxx + + # cc-rs injects --target= (e.g. aarch64-unknown-linux-musl) + # which zig cannot parse. The wrappers strip any --target flags and use + # the correct zig target instead. + for tool in cc c++; do + cat > "/tmp/zig-musl/${tool}" <> "$GITHUB_ENV" - echo "CXX_${TARGET_ENV}=/tmp/zig-musl/cxx" >> "$GITHUB_ENV" + echo "CXX_${TARGET_ENV}=/tmp/zig-musl/c++" >> "$GITHUB_ENV" echo "CARGO_TARGET_${TARGET_ENV^^}_LINKER=/tmp/zig-musl/cc" >> "$GITHUB_ENV" - name: Scope workspace to CLI crates diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index f00d6f819..982814e76 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -231,15 +231,28 @@ jobs: run: | set -euo pipefail ZIG="$(mise which zig)" + ZIG_TARGET="${{ matrix.zig_target }}" mkdir -p /tmp/zig-musl - printf '#!/bin/sh\nexec "%s" cc --target=${{ matrix.zig_target }} "$@"\n' "$ZIG" > /tmp/zig-musl/cc - printf '#!/bin/sh\nexec "%s" c++ --target=${{ matrix.zig_target }} "$@"\n' "$ZIG" > /tmp/zig-musl/cxx - chmod +x /tmp/zig-musl/cc /tmp/zig-musl/cxx + + # cc-rs injects --target= (e.g. aarch64-unknown-linux-musl) + # which zig cannot parse. The wrappers strip any --target flags and use + # the correct zig target instead. + for tool in cc c++; do + cat > "/tmp/zig-musl/${tool}" <> "$GITHUB_ENV" - echo "CXX_${TARGET_ENV}=/tmp/zig-musl/cxx" >> "$GITHUB_ENV" + echo "CXX_${TARGET_ENV}=/tmp/zig-musl/c++" >> "$GITHUB_ENV" echo "CARGO_TARGET_${TARGET_ENV^^}_LINKER=/tmp/zig-musl/cc" >> "$GITHUB_ENV" - name: Scope workspace to CLI crates From 21a0ef107d0872fcb45403887228e93c8d035c54 Mon Sep 17 00:00:00 2001 From: Drew Newberry Date: Fri, 10 Apr 2026 12:47:13 -0700 Subject: [PATCH 11/16] fix(ci): do not use zig as linker, only as C/C++ compiler Zig's linker provides its own musl CRT startup objects (_start, _start_c) which conflict with Rust's self-contained musl CRT objects. Only use zig for compiling C/C++ source (z3, ring); the system gcc works correctly as the linker since Rust supplies its own musl sysroot. --- .github/workflows/release-dev.yml | 6 ++++-- .github/workflows/release-tag.yml | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index 85d9071ec..92b85a0d7 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -227,11 +227,13 @@ jobs: chmod +x "/tmp/zig-musl/${tool}" done - # Tell cargo / cc-rs / cmake to use zig for the musl target + # Tell cargo / cc-rs / cmake to use zig for C/C++ compilation. + # Do NOT set the linker — Rust's default linker (system cc/gcc) + # works correctly because Rust ships its own musl CRT objects. + # Using zig as the linker causes duplicate _start symbols. TARGET_ENV=$(echo "${{ matrix.target }}" | tr '-' '_') echo "CC_${TARGET_ENV}=/tmp/zig-musl/cc" >> "$GITHUB_ENV" echo "CXX_${TARGET_ENV}=/tmp/zig-musl/c++" >> "$GITHUB_ENV" - echo "CARGO_TARGET_${TARGET_ENV^^}_LINKER=/tmp/zig-musl/cc" >> "$GITHUB_ENV" - name: Scope workspace to CLI crates run: | diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 982814e76..935853768 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -249,11 +249,13 @@ jobs: chmod +x "/tmp/zig-musl/${tool}" done - # Tell cargo / cc-rs / cmake to use zig for the musl target + # Tell cargo / cc-rs / cmake to use zig for C/C++ compilation. + # Do NOT set the linker — Rust's default linker (system cc/gcc) + # works correctly because Rust ships its own musl CRT objects. + # Using zig as the linker causes duplicate _start symbols. TARGET_ENV=$(echo "${{ matrix.target }}" | tr '-' '_') echo "CC_${TARGET_ENV}=/tmp/zig-musl/cc" >> "$GITHUB_ENV" echo "CXX_${TARGET_ENV}=/tmp/zig-musl/c++" >> "$GITHUB_ENV" - echo "CARGO_TARGET_${TARGET_ENV^^}_LINKER=/tmp/zig-musl/cc" >> "$GITHUB_ENV" - name: Scope workspace to CLI crates run: | From 2b739df85252e1d64602a8603b04fc1695393323 Mon Sep 17 00:00:00 2001 From: Drew Newberry Date: Fri, 10 Apr 2026 13:05:34 -0700 Subject: [PATCH 12/16] fix(ci): replace zig with g++ FORTIFY_SOURCE wrapper for musl builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Zig's C++ compiler uses libc++ while the system linker expects libstdc++, causing unresolved std::__1::* symbols from z3. Replace zig with a simple g++ wrapper that disables _FORTIFY_SOURCE — the only glibc-specific flag that produces symbols absent from musl (__printf_chk, __memcpy_chk, etc.). System gcc handles linking correctly since Rust provides its own musl CRT objects and libc. --- .github/workflows/release-dev.yml | 43 +++++++++---------------------- .github/workflows/release-tag.yml | 43 +++++++++---------------------- mise.toml | 1 - 3 files changed, 24 insertions(+), 63 deletions(-) diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index 92b85a0d7..85e0f3fec 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -150,10 +150,9 @@ jobs: # --------------------------------------------------------------------------- # Build CLI binaries (Linux musl — static, native on each arch) # - # Builds run directly on the CI host (glibc Ubuntu). Zig provides a - # musl-targeting C/C++ compiler so that bundled-z3 produces musl-compatible - # objects without glibc contamination. This avoids Docker-in-Docker and - # lets sccache work normally. + # Builds run directly on the CI host (glibc Ubuntu). The system g++ is + # used for C++ compilation (z3) with _FORTIFY_SOURCE disabled to avoid + # glibc-specific hardened symbols that do not exist in musl. # --------------------------------------------------------------------------- build-cli-linux: name: Build CLI (Linux ${{ matrix.arch }}) @@ -164,11 +163,9 @@ jobs: - arch: amd64 runner: build-amd64 target: x86_64-unknown-linux-musl - zig_target: x86_64-linux-musl - arch: arm64 runner: build-arm64 target: aarch64-unknown-linux-musl - zig_target: aarch64-linux-musl runs-on: ${{ matrix.runner }} timeout-minutes: 60 container: @@ -205,35 +202,19 @@ jobs: - name: Add Rust musl target run: mise x -- rustup target add ${{ matrix.target }} - - name: Set up zig-musl toolchain + - name: Set up musl C++ wrapper run: | set -euo pipefail - ZIG="$(mise which zig)" - ZIG_TARGET="${{ matrix.zig_target }}" - mkdir -p /tmp/zig-musl - - # cc-rs injects --target= (e.g. aarch64-unknown-linux-musl) - # which zig cannot parse. The wrappers strip any --target flags and use - # the correct zig target instead. - for tool in cc c++; do - cat > "/tmp/zig-musl/${tool}" < /usr/local/bin/musl-g++ + chmod +x /usr/local/bin/musl-g++ - # Tell cargo / cc-rs / cmake to use zig for C/C++ compilation. - # Do NOT set the linker — Rust's default linker (system cc/gcc) - # works correctly because Rust ships its own musl CRT objects. - # Using zig as the linker causes duplicate _start symbols. TARGET_ENV=$(echo "${{ matrix.target }}" | tr '-' '_') - echo "CC_${TARGET_ENV}=/tmp/zig-musl/cc" >> "$GITHUB_ENV" - echo "CXX_${TARGET_ENV}=/tmp/zig-musl/c++" >> "$GITHUB_ENV" + echo "CXX_${TARGET_ENV}=/usr/local/bin/musl-g++" >> "$GITHUB_ENV" - name: Scope workspace to CLI crates run: | diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 935853768..f6cffd89f 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -171,10 +171,9 @@ jobs: # --------------------------------------------------------------------------- # Build CLI binaries (Linux musl — static, native on each arch) # - # Builds run directly on the CI host (glibc Ubuntu). Zig provides a - # musl-targeting C/C++ compiler so that bundled-z3 produces musl-compatible - # objects without glibc contamination. This avoids Docker-in-Docker and - # lets sccache work normally. + # Builds run directly on the CI host (glibc Ubuntu). The system g++ is + # used for C++ compilation (z3) with _FORTIFY_SOURCE disabled to avoid + # glibc-specific hardened symbols that do not exist in musl. # --------------------------------------------------------------------------- build-cli-linux: name: Build CLI (Linux ${{ matrix.arch }}) @@ -185,11 +184,9 @@ jobs: - arch: amd64 runner: build-amd64 target: x86_64-unknown-linux-musl - zig_target: x86_64-linux-musl - arch: arm64 runner: build-arm64 target: aarch64-unknown-linux-musl - zig_target: aarch64-linux-musl runs-on: ${{ matrix.runner }} timeout-minutes: 60 container: @@ -227,35 +224,19 @@ jobs: - name: Add Rust musl target run: mise x -- rustup target add ${{ matrix.target }} - - name: Set up zig-musl toolchain + - name: Set up musl C++ wrapper run: | set -euo pipefail - ZIG="$(mise which zig)" - ZIG_TARGET="${{ matrix.zig_target }}" - mkdir -p /tmp/zig-musl - - # cc-rs injects --target= (e.g. aarch64-unknown-linux-musl) - # which zig cannot parse. The wrappers strip any --target flags and use - # the correct zig target instead. - for tool in cc c++; do - cat > "/tmp/zig-musl/${tool}" < /usr/local/bin/musl-g++ + chmod +x /usr/local/bin/musl-g++ - # Tell cargo / cc-rs / cmake to use zig for C/C++ compilation. - # Do NOT set the linker — Rust's default linker (system cc/gcc) - # works correctly because Rust ships its own musl CRT objects. - # Using zig as the linker causes duplicate _start symbols. TARGET_ENV=$(echo "${{ matrix.target }}" | tr '-' '_') - echo "CC_${TARGET_ENV}=/tmp/zig-musl/cc" >> "$GITHUB_ENV" - echo "CXX_${TARGET_ENV}=/tmp/zig-musl/c++" >> "$GITHUB_ENV" + echo "CXX_${TARGET_ENV}=/usr/local/bin/musl-g++" >> "$GITHUB_ENV" - name: Scope workspace to CLI crates run: | diff --git a/mise.toml b/mise.toml index b045b563c..12f67fdec 100644 --- a/mise.toml +++ b/mise.toml @@ -23,7 +23,6 @@ helm = "4.1.1" "ubi:mozilla/sccache" = { version = "0.14.0", matching = "sccache-v" } "ubi:anchore/syft" = { version = "1.42.3", matching = "syft_" } "ubi:EmbarkStudios/cargo-about" = "0.8.4" -zig = "0.14.1" [env] _.path = ["{{config_root}}/scripts/bin"] From cb32a375d500d10382f4464a4d75fe48d9668090 Mon Sep 17 00:00:00 2001 From: Drew Newberry Date: Fri, 10 Apr 2026 13:15:41 -0700 Subject: [PATCH 13/16] fix(ci): set CC for musl target so cc-rs finds the C compiler cc-rs probes for aarch64-linux-musl-gcc by default, which does not exist on the Ubuntu CI host. Set CC_ explicitly to a wrapper that also disables _FORTIFY_SOURCE for consistency with the CXX wrapper. --- .github/workflows/release-dev.yml | 8 ++++++++ .github/workflows/release-tag.yml | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index 85e0f3fec..af703347d 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -213,7 +213,15 @@ jobs: > /usr/local/bin/musl-g++ chmod +x /usr/local/bin/musl-g++ + # Point both CC and CXX at wrappers that disable _FORTIFY_SOURCE. + # CC must be set explicitly or cc-rs probes for aarch64-linux-musl-gcc + # which does not exist on the Ubuntu CI host. + printf '#!/bin/sh\nexec cc -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 "$@"\n' \ + > /usr/local/bin/musl-cc + chmod +x /usr/local/bin/musl-cc + TARGET_ENV=$(echo "${{ matrix.target }}" | tr '-' '_') + echo "CC_${TARGET_ENV}=/usr/local/bin/musl-cc" >> "$GITHUB_ENV" echo "CXX_${TARGET_ENV}=/usr/local/bin/musl-g++" >> "$GITHUB_ENV" - name: Scope workspace to CLI crates diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index f6cffd89f..4f27517a9 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -235,7 +235,15 @@ jobs: > /usr/local/bin/musl-g++ chmod +x /usr/local/bin/musl-g++ + # Point both CC and CXX at wrappers that disable _FORTIFY_SOURCE. + # CC must be set explicitly or cc-rs probes for aarch64-linux-musl-gcc + # which does not exist on the Ubuntu CI host. + printf '#!/bin/sh\nexec cc -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 "$@"\n' \ + > /usr/local/bin/musl-cc + chmod +x /usr/local/bin/musl-cc + TARGET_ENV=$(echo "${{ matrix.target }}" | tr '-' '_') + echo "CC_${TARGET_ENV}=/usr/local/bin/musl-cc" >> "$GITHUB_ENV" echo "CXX_${TARGET_ENV}=/usr/local/bin/musl-g++" >> "$GITHUB_ENV" - name: Scope workspace to CLI crates From bdeaab6294eff74af49cee662fa7ae6d93d01cd7 Mon Sep 17 00:00:00 2001 From: Drew Newberry Date: Fri, 10 Apr 2026 13:37:07 -0700 Subject: [PATCH 14/16] fix(ci): use zig toolchain end-to-end for musl z3 builds Configure Linux musl release jobs to compile and link with zig wrappers, normalize cc-rs target flags, disable Rust self-contained musl linking, and link z3 against libc++ via CXXSTDLIB=c++. This avoids glibc symbol leaks from host g++ while keeping the build off Docker. --- .github/workflows/release-dev.yml | 50 ++++++++++++++++++------------- .github/workflows/release-tag.yml | 50 ++++++++++++++++++------------- mise.toml | 1 + 3 files changed, 61 insertions(+), 40 deletions(-) diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index af703347d..bc92ab648 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -150,9 +150,8 @@ jobs: # --------------------------------------------------------------------------- # Build CLI binaries (Linux musl — static, native on each arch) # - # Builds run directly on the CI host (glibc Ubuntu). The system g++ is - # used for C++ compilation (z3) with _FORTIFY_SOURCE disabled to avoid - # glibc-specific hardened symbols that do not exist in musl. + # Builds run directly on the CI host (glibc Ubuntu). Zig provides musl + # C/C++ toolchains for bundled-z3 and ring, and is also used as the linker. # --------------------------------------------------------------------------- build-cli-linux: name: Build CLI (Linux ${{ matrix.arch }}) @@ -163,9 +162,11 @@ jobs: - arch: amd64 runner: build-amd64 target: x86_64-unknown-linux-musl + zig_target: x86_64-linux-musl - arch: arm64 runner: build-arm64 target: aarch64-unknown-linux-musl + zig_target: aarch64-linux-musl runs-on: ${{ matrix.runner }} timeout-minutes: 60 container: @@ -202,27 +203,36 @@ jobs: - name: Add Rust musl target run: mise x -- rustup target add ${{ matrix.target }} - - name: Set up musl C++ wrapper + - name: Set up zig musl wrappers run: | set -euo pipefail - # System g++ with _FORTIFY_SOURCE disabled. FORTIFY_SOURCE makes - # g++ emit glibc-specific hardened calls (__printf_chk, __memcpy_chk) - # that do not exist in musl, causing linker failures. Disabling it - # produces standard POSIX calls that resolve against musl. - printf '#!/bin/sh\nexec g++ -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 "$@"\n' \ - > /usr/local/bin/musl-g++ - chmod +x /usr/local/bin/musl-g++ - - # Point both CC and CXX at wrappers that disable _FORTIFY_SOURCE. - # CC must be set explicitly or cc-rs probes for aarch64-linux-musl-gcc - # which does not exist on the Ubuntu CI host. - printf '#!/bin/sh\nexec cc -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 "$@"\n' \ - > /usr/local/bin/musl-cc - chmod +x /usr/local/bin/musl-cc + ZIG="$(mise which zig)" + ZIG_TARGET="${{ matrix.zig_target }}" + mkdir -p /tmp/zig-musl + + # cc-rs injects --target= (for example + # aarch64-unknown-linux-musl), which zig does not parse. Strip any + # caller-provided --target and use the wrapper's zig-native target. + for tool in cc c++; do + printf '#!/bin/bash\nargs=()\nfor arg in "$@"; do\n case "$arg" in\n --target=*) ;;\n *) args+=("$arg") ;;\n esac\ndone\nexec "%s" %s --target=%s "${args[@]}"\n' \ + "$ZIG" "$tool" "$ZIG_TARGET" > "/tmp/zig-musl/${tool}" + chmod +x "/tmp/zig-musl/${tool}" + done TARGET_ENV=$(echo "${{ matrix.target }}" | tr '-' '_') - echo "CC_${TARGET_ENV}=/usr/local/bin/musl-cc" >> "$GITHUB_ENV" - echo "CXX_${TARGET_ENV}=/usr/local/bin/musl-g++" >> "$GITHUB_ENV" + TARGET_ENV_UPPER=${TARGET_ENV^^} + + # Use zig for C/C++ compilation and final linking. + echo "CC_${TARGET_ENV}=/tmp/zig-musl/cc" >> "$GITHUB_ENV" + echo "CXX_${TARGET_ENV}=/tmp/zig-musl/c++" >> "$GITHUB_ENV" + echo "CARGO_TARGET_${TARGET_ENV_UPPER}_LINKER=/tmp/zig-musl/cc" >> "$GITHUB_ENV" + + # Let zig own CRT/startfiles to avoid duplicate _start symbols. + echo "CARGO_TARGET_${TARGET_ENV_UPPER}_RUSTFLAGS=-Clink-self-contained=no" >> "$GITHUB_ENV" + + # z3 built with zig c++ uses libc++ symbols (std::__1::*). + # Override z3-sys default (stdc++) so Rust links the matching runtime. + echo "CXXSTDLIB=c++" >> "$GITHUB_ENV" - name: Scope workspace to CLI crates run: | diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 4f27517a9..564a88d67 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -171,9 +171,8 @@ jobs: # --------------------------------------------------------------------------- # Build CLI binaries (Linux musl — static, native on each arch) # - # Builds run directly on the CI host (glibc Ubuntu). The system g++ is - # used for C++ compilation (z3) with _FORTIFY_SOURCE disabled to avoid - # glibc-specific hardened symbols that do not exist in musl. + # Builds run directly on the CI host (glibc Ubuntu). Zig provides musl + # C/C++ toolchains for bundled-z3 and ring, and is also used as the linker. # --------------------------------------------------------------------------- build-cli-linux: name: Build CLI (Linux ${{ matrix.arch }}) @@ -184,9 +183,11 @@ jobs: - arch: amd64 runner: build-amd64 target: x86_64-unknown-linux-musl + zig_target: x86_64-linux-musl - arch: arm64 runner: build-arm64 target: aarch64-unknown-linux-musl + zig_target: aarch64-linux-musl runs-on: ${{ matrix.runner }} timeout-minutes: 60 container: @@ -224,27 +225,36 @@ jobs: - name: Add Rust musl target run: mise x -- rustup target add ${{ matrix.target }} - - name: Set up musl C++ wrapper + - name: Set up zig musl wrappers run: | set -euo pipefail - # System g++ with _FORTIFY_SOURCE disabled. FORTIFY_SOURCE makes - # g++ emit glibc-specific hardened calls (__printf_chk, __memcpy_chk) - # that do not exist in musl, causing linker failures. Disabling it - # produces standard POSIX calls that resolve against musl. - printf '#!/bin/sh\nexec g++ -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 "$@"\n' \ - > /usr/local/bin/musl-g++ - chmod +x /usr/local/bin/musl-g++ - - # Point both CC and CXX at wrappers that disable _FORTIFY_SOURCE. - # CC must be set explicitly or cc-rs probes for aarch64-linux-musl-gcc - # which does not exist on the Ubuntu CI host. - printf '#!/bin/sh\nexec cc -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 "$@"\n' \ - > /usr/local/bin/musl-cc - chmod +x /usr/local/bin/musl-cc + ZIG="$(mise which zig)" + ZIG_TARGET="${{ matrix.zig_target }}" + mkdir -p /tmp/zig-musl + + # cc-rs injects --target= (for example + # aarch64-unknown-linux-musl), which zig does not parse. Strip any + # caller-provided --target and use the wrapper's zig-native target. + for tool in cc c++; do + printf '#!/bin/bash\nargs=()\nfor arg in "$@"; do\n case "$arg" in\n --target=*) ;;\n *) args+=("$arg") ;;\n esac\ndone\nexec "%s" %s --target=%s "${args[@]}"\n' \ + "$ZIG" "$tool" "$ZIG_TARGET" > "/tmp/zig-musl/${tool}" + chmod +x "/tmp/zig-musl/${tool}" + done TARGET_ENV=$(echo "${{ matrix.target }}" | tr '-' '_') - echo "CC_${TARGET_ENV}=/usr/local/bin/musl-cc" >> "$GITHUB_ENV" - echo "CXX_${TARGET_ENV}=/usr/local/bin/musl-g++" >> "$GITHUB_ENV" + TARGET_ENV_UPPER=${TARGET_ENV^^} + + # Use zig for C/C++ compilation and final linking. + echo "CC_${TARGET_ENV}=/tmp/zig-musl/cc" >> "$GITHUB_ENV" + echo "CXX_${TARGET_ENV}=/tmp/zig-musl/c++" >> "$GITHUB_ENV" + echo "CARGO_TARGET_${TARGET_ENV_UPPER}_LINKER=/tmp/zig-musl/cc" >> "$GITHUB_ENV" + + # Let zig own CRT/startfiles to avoid duplicate _start symbols. + echo "CARGO_TARGET_${TARGET_ENV_UPPER}_RUSTFLAGS=-Clink-self-contained=no" >> "$GITHUB_ENV" + + # z3 built with zig c++ uses libc++ symbols (std::__1::*). + # Override z3-sys default (stdc++) so Rust links the matching runtime. + echo "CXXSTDLIB=c++" >> "$GITHUB_ENV" - name: Scope workspace to CLI crates run: | diff --git a/mise.toml b/mise.toml index 12f67fdec..b045b563c 100644 --- a/mise.toml +++ b/mise.toml @@ -23,6 +23,7 @@ helm = "4.1.1" "ubi:mozilla/sccache" = { version = "0.14.0", matching = "sccache-v" } "ubi:anchore/syft" = { version = "1.42.3", matching = "syft_" } "ubi:EmbarkStudios/cargo-about" = "0.8.4" +zig = "0.14.1" [env] _.path = ["{{config_root}}/scripts/bin"] From 077cddb55d0e577eae1acf9fa1c277c88efa0b4b Mon Sep 17 00:00:00 2001 From: Drew Newberry Date: Fri, 10 Apr 2026 14:20:39 -0700 Subject: [PATCH 15/16] fix(docker): install C++ cross-compilers for wheel z3 builds Python wheel cross-builds now compile bundled z3, which invokes CMake with CXX_. The cross toolchain setup installed only gcc, so aarch64-linux- gnu-g++/x86_64-linux-gnu-g++ were missing and z3-sys failed at configure time. Install matching g++ cross compilers alongside gcc. --- deploy/docker/cross-build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/docker/cross-build.sh b/deploy/docker/cross-build.sh index 0c2678b8e..bb4e4eb14 100755 --- a/deploy/docker/cross-build.sh +++ b/deploy/docker/cross-build.sh @@ -50,11 +50,11 @@ install_cross_toolchain() { arm64) dpkg --add-architecture arm64 apt-get update && apt-get install -y --no-install-recommends \ - gcc-aarch64-linux-gnu libc6-dev-arm64-cross ;; + gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libc6-dev-arm64-cross ;; amd64) dpkg --add-architecture amd64 apt-get update && apt-get install -y --no-install-recommends \ - gcc-x86-64-linux-gnu libc6-dev-amd64-cross ;; + gcc-x86-64-linux-gnu g++-x86-64-linux-gnu libc6-dev-amd64-cross ;; esac rm -rf /var/lib/apt/lists/* } From d33f850c5a14e43cbea42ecb392ad3d53c5c4433 Mon Sep 17 00:00:00 2001 From: Drew Newberry Date: Fri, 10 Apr 2026 15:46:21 -0700 Subject: [PATCH 16/16] fix(docker): bump macOS deployment target for bundled z3 builds The osxcross SDK headers gate std::to_chars behind macOS 13.3+. Bundled z3 builds in macOS-targeted Docker images were compiling with -mmacosx-version-min=11.0, causing C++ availability errors in libc++. Set MACOSX_DEPLOYMENT_TARGET and target C/C++ flags to 13.3. --- deploy/docker/Dockerfile.cli-macos | 3 +++ deploy/docker/Dockerfile.python-wheels-macos | 3 +++ 2 files changed, 6 insertions(+) diff --git a/deploy/docker/Dockerfile.cli-macos b/deploy/docker/Dockerfile.cli-macos index 10982efd1..f9370691c 100644 --- a/deploy/docker/Dockerfile.cli-macos +++ b/deploy/docker/Dockerfile.cli-macos @@ -53,6 +53,9 @@ ENV AR_aarch64_apple_darwin=aarch64-apple-darwin25.1-ar ENV CARGO_TARGET_AARCH64_APPLE_DARWIN_LINKER=oa64-clang ENV CARGO_TARGET_AARCH64_APPLE_DARWIN_AR=aarch64-apple-darwin25.1-ar ENV SDKROOT=/osxcross/SDK/MacOSX.sdk +ENV MACOSX_DEPLOYMENT_TARGET=13.3 +ENV CFLAGS_aarch64_apple_darwin=--target=arm64-apple-macosx\ -mmacosx-version-min=13.3 +ENV CXXFLAGS_aarch64_apple_darwin=--target=arm64-apple-macosx\ -mmacosx-version-min=13.3 ENV BINDGEN_EXTRA_CLANG_ARGS_aarch64_apple_darwin=--target=arm64-apple-macosx\ -isysroot\ ${SDKROOT} # --------------------------------------------------------------------------- diff --git a/deploy/docker/Dockerfile.python-wheels-macos b/deploy/docker/Dockerfile.python-wheels-macos index 7d64c618d..79cc6d9b4 100644 --- a/deploy/docker/Dockerfile.python-wheels-macos +++ b/deploy/docker/Dockerfile.python-wheels-macos @@ -48,6 +48,9 @@ ENV AR_aarch64_apple_darwin=aarch64-apple-darwin25.1-ar ENV CARGO_TARGET_AARCH64_APPLE_DARWIN_LINKER=oa64-clang ENV CARGO_TARGET_AARCH64_APPLE_DARWIN_AR=aarch64-apple-darwin25.1-ar ENV SDKROOT=/osxcross/SDK/MacOSX.sdk +ENV MACOSX_DEPLOYMENT_TARGET=13.3 +ENV CFLAGS_aarch64_apple_darwin=--target=arm64-apple-macosx\ -mmacosx-version-min=13.3 +ENV CXXFLAGS_aarch64_apple_darwin=--target=arm64-apple-macosx\ -mmacosx-version-min=13.3 ENV BINDGEN_EXTRA_CLANG_ARGS_aarch64_apple_darwin=--target=arm64-apple-macosx\ -isysroot\ ${SDKROOT} # Copy dependency manifests first for better caching.