Release v0.2.0 #216
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build Apple | |
| on: | |
| pull_request: | |
| branches: [master] | |
| paths: | |
| - 'bindings/apple/**' | |
| - 'crates/xybrid-bolt/**' | |
| - 'crates/xybrid-ffi-facade/**' | |
| - 'crates/xybrid-core/**' | |
| - 'crates/xybrid-sdk/**' | |
| - 'xtask/**' | |
| - 'Cargo.lock' | |
| - 'Cargo.toml' | |
| - '.github/workflows/build-apple.yml' | |
| # Docs-only changes under the paths above (READMEs, examples) never | |
| # affect the native build — exclude markdown so they don't trigger it. | |
| - '!**.md' | |
| # Run on master merges too, so each merge saves a default-branch-scoped | |
| # cache (sccache + rust-cache). GitHub Actions caches are branch-scoped: | |
| # a PR run can only restore caches from its own branch or the default | |
| # branch. Without this trigger master never builds, so master has no | |
| # cache, so every new PR branch's first run is cold (~30 min). Warming | |
| # master here lets new branches start warm (~5 min). Keep these paths in | |
| # sync with the pull_request trigger above. | |
| push: | |
| branches: [master] | |
| paths: | |
| - 'bindings/apple/**' | |
| - 'crates/xybrid-bolt/**' | |
| - 'crates/xybrid-ffi-facade/**' | |
| - 'crates/xybrid-core/**' | |
| - 'crates/xybrid-sdk/**' | |
| - 'xtask/**' | |
| - 'Cargo.lock' | |
| - 'Cargo.toml' | |
| - '.github/workflows/build-apple.yml' | |
| - '!**.md' | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: read-all | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: 1 | |
| jobs: | |
| build-xcframework: | |
| name: Build XCFramework | |
| runs-on: macos-14 | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # stable | |
| with: | |
| toolchain: stable | |
| targets: >- | |
| aarch64-apple-ios, | |
| aarch64-apple-ios-sim, | |
| aarch64-apple-darwin | |
| - name: Setup sccache | |
| uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9 | |
| - name: Configure sccache environment | |
| shell: bash | |
| run: | | |
| echo "SCCACHE_GHA_ENABLED=true" >> $GITHUB_ENV | |
| echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV | |
| echo "CMAKE_C_COMPILER_LAUNCHER=sccache" >> $GITHUB_ENV | |
| echo "CMAKE_CXX_COMPILER_LAUNCHER=sccache" >> $GITHUB_ENV | |
| - name: Cache Rust dependencies | |
| uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| with: | |
| prefix-key: "v1-rust" | |
| shared-key: "apple-xcframework" | |
| cache-all-crates: "true" | |
| save-if: "true" | |
| # boltffi CLI provides the `boltffi pack apple` that | |
| # `cargo xtask build-xcframework` shells out to. Cache the installed | |
| # binary across runs. | |
| - name: Cache boltffi CLI | |
| id: cache-boltffi | |
| uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 | |
| with: | |
| path: ~/.cargo/bin/boltffi | |
| key: boltffi-cli-${{ runner.os }}-0.25.3 | |
| - name: Install boltffi CLI | |
| # `which || install` is idempotent whether or not the cache populated | |
| # the binary. Pinned to 0.25.3 to MATCH the runtime `boltffi` crate | |
| # (Cargo.lock): a CLI/runtime version skew mis-generates unit-ok | |
| # `Result<(), E>` exports (model warmup/unload) as a `void` foreign | |
| # function that drops the error and leaks the result buffer. `--locked` | |
| # installs against the CLI's own bundled Cargo.lock for reproducibility. | |
| run: which boltffi || cargo install boltffi_cli --version 0.25.3 --locked | |
| # Prebuilt-natives fast path (iOS device + arm64 simulator — the two | |
| # slices boltffi's xcframework builds). Best-effort: pull the prebuilt | |
| # llama.cpp slices and point build.rs at them so the xcframework build | |
| # skips the llama.cpp cmake compile per slice. On ANY miss/error this is a | |
| # silent no-op (continue-on-error) and the slice compiles from source — it | |
| # can never break the build. build.rs keys on | |
| # XYBRID_NATIVES_PREBUILT_DIR/<target>, so each slice in the single | |
| # `boltffi pack apple` invocation resolves its own (or falls through). | |
| - name: Setup oras | |
| uses: oras-project/setup-oras@38de303aac69abb66f3e6255b7198bff35f323e3 # v2.0.0 | |
| # `oras login`, not docker/login-action: macOS runners have no docker. | |
| # Best-effort + same-repo only (forks have no token → anonymous pull). | |
| - name: Log in to ghcr (best-effort, same-repo) | |
| if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository | |
| continue-on-error: true | |
| env: | |
| GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: echo "$GHCR_TOKEN" | oras login ghcr.io -u "${{ github.actor }}" --password-stdin | |
| - name: Pull prebuilt natives (iOS device + sim, best-effort) | |
| continue-on-error: true | |
| env: | |
| XYBRID_NATIVES_PKG: ghcr.io/xybrid-ai/llama-natives | |
| run: | | |
| # Use the Rust TARGET spelling aarch64-apple-ios-sim (with -sim); | |
| # build.rs keys the slice dir on it. | |
| DEST="$RUNNER_TEMP/natives" | |
| got_any=0 | |
| for triple in aarch64-apple-ios aarch64-apple-ios-sim; do | |
| if tools/scripts/natives-pull.sh "$triple" base "$DEST"; then | |
| echo "prebuilt natives staged for $triple (will skip cmake)" | |
| got_any=1 | |
| else | |
| echo "no prebuilt natives for $triple — compiles from source" | |
| fi | |
| done | |
| if [ "$got_any" = 1 ]; then | |
| echo "XYBRID_NATIVES_PREBUILT_DIR=$DEST" >> "$GITHUB_ENV" | |
| else | |
| echo "no prebuilt natives — compiles from source (unchanged)" | |
| fi | |
| - name: Build XCFramework | |
| run: cargo xtask build-xcframework --release | |
| - name: Verify XCFramework | |
| run: | | |
| XCFW_PATH="bindings/apple/XCFrameworks/XybridFFI.xcframework" | |
| if [ ! -d "$XCFW_PATH" ]; then | |
| echo "Error: XCFramework not found at $XCFW_PATH" | |
| exit 1 | |
| fi | |
| echo "XCFramework contents:" | |
| ls -la "$XCFW_PATH" | |
| echo "" | |
| echo "Verifying architectures..." | |
| # boltffi names the slice static lib libxybrid-bolt.a and lays | |
| # out one dir per slice (ios-arm64, ios-arm64-simulator; macOS is | |
| # excluded via boltffi.toml). Glob rather than hard-code so this | |
| # survives naming/slice changes. | |
| found=$(find "$XCFW_PATH" -name '*.a') | |
| if [ -z "$found" ]; then | |
| echo "Error: no static libraries found inside the XCFramework" | |
| exit 1 | |
| fi | |
| echo "$found" | while read -r lib; do file "$lib"; done | |
| - name: Compile Swift binding wrapper (iOS Simulator) | |
| # Compiles the hand-written Xybrid.swift + the bolt-generated | |
| # xybrid_bolt.swift into the SPM `Xybrid` library, so a wrapper break | |
| # (non-exhaustive errorDescription switch, a missing import, an | |
| # enum-shape mismatch vs the regenerated bindings) fails CI here instead | |
| # of only when a human builds the example app. Uses the xcframework | |
| # just built above: the committed state is useLocalNatives = false (so | |
| # SPM consumers resolve the published release asset), so this step flips | |
| # to local mode at CI runtime before resolving — otherwise it would try | |
| # to download the remote asset, which 404s on a release PR while the | |
| # v<version> release is still a draft. The flip is CI-only, never committed. | |
| # | |
| # Targets the iOS Simulator for two reasons: (1) the xcframework ships | |
| # only ios-arm64 + ios-arm64-simulator (boltffi.toml include_macos=false), | |
| # so a host/macOS build has no slice to link; (2) Xybrid.swift gates | |
| # `import UIKit` behind `#if os(iOS)`, so only an iOS build type-checks | |
| # the UIKit-conditional code — the code most likely to break. Compiles | |
| # the wrapper library ONLY (the example .xcodeproj has no shared scheme; | |
| # ContentView/LiveVision aren't built) and boots no simulator (generic | |
| # destination = compile + link, no run, no signing). | |
| run: | | |
| set -euo pipefail | |
| # CI-runtime flip to the locally-built xcframework. Do NOT commit this. | |
| ./bindings/apple/scripts/set-natives-mode.sh --set-local | |
| xcodebuild -resolvePackageDependencies | |
| xcodebuild build \ | |
| -scheme Xybrid \ | |
| -destination 'generic/platform=iOS Simulator' \ | |
| -skipPackagePluginValidation \ | |
| CODE_SIGNING_ALLOWED=NO | |
| - name: Check iOS vision build (compile-only, not shipped) | |
| # Compile-only gate for the OPT-IN native llama.cpp vision backend | |
| # (mtmd). This backend is in NO platform preset and is NOT shipped in | |
| # the XCFramework above — this step only proves the | |
| # `llm-llamacpp-vision` (mtmd) chain still cross-compiles for iOS, the | |
| # gate the UniFFI->bolt migration dropped (it pointed at the deleted | |
| # `xybrid-uniffi`; retargeted here at `xybrid-sdk`, which now carries | |
| # both `platform-ios` and `llm-llamacpp-vision`: xybrid-sdk -> | |
| # xybrid-core/llm-llamacpp-vision -> xybrid-llama-sys/vision; the -sys | |
| # crate lives at crates/llama-cpp-sys/, package `xybrid-llama-sys`). | |
| # | |
| # `check` (not `build`) is sufficient and matches the old gate: the | |
| # crates/llama-cpp-sys/build.rs runs on `check` and is what compiles | |
| # llama.cpp + the mtmd C++ via cmake and bindgens the mtmd FFI (gated | |
| # on CARGO_FEATURE_VISION). Like the shipped llm-llamacpp build above, | |
| # it sources llama.cpp through build.rs's pinned-commit OUT_DIR clone | |
| # (vendor/llama-cpp is an un-checked-out submodule), so no extra | |
| # checkout is needed. | |
| run: cargo check -p xybrid-sdk --features platform-ios,llm-llamacpp-vision --target aarch64-apple-ios | |
| - name: Upload XCFramework artifact | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: XybridFFI-xcframework | |
| path: bindings/apple/XCFrameworks/XybridFFI.xcframework | |
| if-no-files-found: error |