nix-native ios cross compile#3759
Conversation
|
Claude finished @insipx's task —— View job PR Review - Nix-native iOS Cross-CompilationReview Date: July 2, 2026 17:39 UTC This PR introduces a comprehensive Nix-based iOS build pipeline to resolve Xcode version conflicts. The implementation is well-structured, but there are three critical issues that need attention before merging: 🔴 Critical Issues1. Node.js Darwin Build Will Fail with New OpenSSL Linking (nix/lib/base.nix:79)File: remaining=$(otool -L "$NODE_LIB" | awk 'NR > 1 && $1 ~ /^\/nix\/store\// { print $1 }')
if [ -n "$remaining" ]; then
echo "error: $NODE_LIB still references /nix/store after postFixup:" >&2
exit 1
fiThe current Impact: Darwin Node.js builds will break in CI and local development. Fix Required: Either:
2. CocoaPods Publish Job Missing Xcode Setup (.github/workflows/release-ios.yml:222)File: This defeats the core goal of this PR (resolving Xcode version conflicts). If the runner's default Xcode differs from what the xcframework was built with, the validation can fail with version mismatches. Impact: Release job instability when runner Xcode doesn't match pinned version. Fix Required: Add the setup-ios-xcode step to the - uses: ./.github/actions/setup-ios-xcode
- name: Publish to CocoaPods3. Xcode Version Mismatch Between Action and Source CodeFiles:
On a cold cache with a runner that has Xcode 26.3.1 installed, the action will resolve that bundle, but Impact: Cold-cache CI builds fail when runner has a different 26.3.x patch build. Fix Required: Either tighten the version check to match exactly what the pinned store path expects, OR compute the store path dynamically instead of hard-coding it. ✅ Positive Observations
📝 Minor Observations (Non-Blocking)
Recommendation: Address the three critical issues above, particularly #1 and #2, before merging to prevent immediate CI/release failures. |
90ab637 to
d23960c
Compare
There was a problem hiding this comment.
🟠 High
Line 83 in 90ab637
The new import ./nix/ios-packages.nix at line 58 replaces the manually-defined iOS packages, but the old flake outputs .#ios-xcframeworks, .#ios-xcframeworks-fast, .#ios-libs, and .#ios-libs-fast are removed without compatibility aliases. The iOS release workflow in .github/workflows/release-ios.yml still invokes nix build .#ios-xcframeworks, so it will fail with "does not provide attribute 'ios-xcframeworks'" after this change. Consider re-exporting these attributes from ./nix/ios-packages.nix or adding passthrough aliases in packages to maintain backward compatibility.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @flake.nix around line 83:
The new import `./nix/ios-packages.nix` at line 58 replaces the manually-defined iOS packages, but the old flake outputs `.#ios-xcframeworks`, `.#ios-xcframeworks-fast`, `.#ios-libs`, and `.#ios-libs-fast` are removed without compatibility aliases. The iOS release workflow in `.github/workflows/release-ios.yml` still invokes `nix build .#ios-xcframeworks`, so it will fail with "does not provide attribute 'ios-xcframeworks'" after this change. Consider re-exporting these attributes from `./nix/ios-packages.nix` or adding passthrough aliases in `packages` to maintain backward compatibility.
| @@ -1,2 +1,2 @@ | |||
| watch_file nix/shells/local.nix | |||
| use flake . | |||
| # watch_file nix/shells/local.nix | |||
There was a problem hiding this comment.
🟡 Medium .envrc:1
Changing use flake . to use flake .#rust removes nix/shells/local.nix from the dev shell, so tools like just are no longer available. The workflow .github/workflows/test-devcontainer.yml runs direnv exec . just --version, which will fail because just is missing from the rust shell. Consider re-adding watch_file nix/shells/local.nix and including just in the rust shell, or document why these tools are intentionally excluded.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @.envrc around line 1:
Changing `use flake .` to `use flake .#rust` removes `nix/shells/local.nix` from the dev shell, so tools like `just` are no longer available. The workflow `.github/workflows/test-devcontainer.yml` runs `direnv exec . just --version`, which will fail because `just` is missing from the `rust` shell. Consider re-adding `watch_file nix/shells/local.nix` and including `just` in the `rust` shell, or document why these tools are intentionally excluded.
| # Use nixpkgs' pre-built openssl instead of letting openssl-sys vendor and build from source | ||
| # (which calls xcrun for the SDK and fails in cross sandboxes). | ||
| OPENSSL_NO_VENDOR = "1"; | ||
| OPENSSL_DIR = "${openssl.dev}"; | ||
| OPENSSL_LIB_DIR = "${openssl.out}/lib"; | ||
| OPENSSL_INCLUDE_DIR = "${openssl.dev}/include"; |
There was a problem hiding this comment.
🟠 High lib/base.nix:75
The new OPENSSL_* environment variables in commonArgs are inherited by Android cross-compilation derivations. Android builds intentionally use buildInputs = [ ] to link against the NDK/sysroot instead of Nix libraries, but these OPENSSL_* variables force openssl-sys to use nixpkgs' host OpenSSL (${openssl}). This causes Android builds to either fail compilation or link against x86_64 libraries instead of ARM/Android libraries. Consider making these OpenSSL overrides conditional on !stdenv.hostPlatform.isAndroid (or similar platform check), or moving them to the iOS-specific derivation where they are actually needed.
- # Use nixpkgs' pre-built openssl instead of letting openssl-sys vendor and build from source
- # (which calls xcrun for the SDK and fails in cross sandboxes).
- OPENSSL_NO_VENDOR = "1";
- OPENSSL_DIR = "${openssl.dev}";
- OPENSSL_LIB_DIR = "${openssl.out}/lib";
- OPENSSL_INCLUDE_DIR = "${openssl.dev}/include";
+ # Use nixpkgs' pre-built openssl instead of letting openssl-sys vendor and build from source
+ # (which calls xcrun for the SDK and fails in cross sandboxes).
+ # Only apply for iOS; Android uses NDK OpenSSL via vendored build.
+ OPENSSL_NO_VENDOR = if stdenv.hostPlatform.isDarwin then "1" else null;
+ OPENSSL_DIR = if stdenv.hostPlatform.isDarwin then "${openssl.dev}" else null;
+ OPENSSL_LIB_DIR = if stdenv.hostPlatform.isDarwin then "${openssl.out}/lib" else null;
+ OPENSSL_INCLUDE_DIR = if stdenv.hostPlatform.isDarwin then "${openssl.dev}/include" else null;🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @nix/lib/base.nix around lines 75-80:
The new `OPENSSL_*` environment variables in `commonArgs` are inherited by Android cross-compilation derivations. Android builds intentionally use `buildInputs = [ ]` to link against the NDK/sysroot instead of Nix libraries, but these `OPENSSL_*` variables force `openssl-sys` to use nixpkgs' host OpenSSL (`${openssl}`). This causes Android builds to either fail compilation or link against x86_64 libraries instead of ARM/Android libraries. Consider making these OpenSSL overrides conditional on `!stdenv.hostPlatform.isAndroid` (or similar platform check), or moving them to the iOS-specific derivation where they are actually needed.
| version = xmtp.mkVersion rust; | ||
| inherit (base) commonArgs bindingsFileset; | ||
|
|
||
| cargoArtifacts = xmtp.base.mkCargoArtifacts rust false null; |
There was a problem hiding this comment.
🟠 High package/ios-bindings.nix:13
The cargoArtifacts derivation at line 13 uses xmtp.base.mkCargoArtifacts rust false null, which builds dependencies without iosEnv.envSetup. Crates with Apple/Xcode-dependent build scripts fail during the dependency phase because the Apple SDK environment is never configured. This breaks cross-compilation for all iOS targets (device and simulator) since ios-packages.nix reuses this derivation for every iOS ABI. Consider passing iosEnv to mkCargoArtifacts so the dependency build runs with proper SDK setup, similar to the previous iOS builder.
- cargoArtifacts = xmtp.base.mkCargoArtifacts rust false null;🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @nix/package/ios-bindings.nix around line 13:
The `cargoArtifacts` derivation at line 13 uses `xmtp.base.mkCargoArtifacts rust false null`, which builds dependencies without `iosEnv.envSetup`. Crates with Apple/Xcode-dependent build scripts fail during the dependency phase because the Apple SDK environment is never configured. This breaks cross-compilation for all iOS targets (device and simulator) since `ios-packages.nix` reuses this derivation for every iOS ABI. Consider passing `iosEnv` to `mkCargoArtifacts` so the dependency build runs with proper SDK setup, similar to the previous iOS builder.
There was a problem hiding this comment.
Contradicted empirically: the deps-only phase builds clean on the prebuilt toolchain — the cross cc wrapper carries the SDK itself (-isysroot via iosSdkPkgs), so iosEnv is not needed during dependency builds. arm64-apple-ios and simulator artifacts were produced from exactly this configuration.
| fastAbis = [ | ||
| fastAbi | ||
| "iphone64-simulator" | ||
| ]; |
There was a problem hiding this comment.
🟢 Low nix/ios-packages.nix:74
When fastAbi resolves to "x86_64-darwin" on Intel Macs, fastAbis still only contains ["x86_64-darwin", "iphone64-simulator"], where iphone64-simulator is hard-coded to aarch64-apple-ios-simulator. This produces xcframeworks with an arm64 simulator slice and no x86_64-apple-ios-simulator binary, making them unusable for local simulator builds on Intel hosts despite explicitly selecting x86_64-darwin as a supported host. Consider adding an iphone64-simulator-intel target for x86_64-apple-ios-simulator and including it in fastAbis when the host is Intel.
- fastAbis = [
- fastAbi
- "iphone64-simulator"
- ];🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @nix/ios-packages.nix around lines 74-77:
When `fastAbi` resolves to `"x86_64-darwin"` on Intel Macs, `fastAbis` still only contains `["x86_64-darwin", "iphone64-simulator"]`, where `iphone64-simulator` is hard-coded to `aarch64-apple-ios-simulator`. This produces xcframeworks with an arm64 simulator slice and no `x86_64-apple-ios-simulator` binary, making them unusable for local simulator builds on Intel hosts despite explicitly selecting `x86_64-darwin` as a supported host. Consider adding an `iphone64-simulator-intel` target for `x86_64-apple-ios-simulator` and including it in `fastAbis` when the host is Intel.
There was a problem hiding this comment.
Acknowledged limitation: x86_64 simulator slices are intentionally unsupported (team is arm64-only). Can revisit if an Intel use-case appears.
| inherit version; | ||
| pname = "xmtpv3-swift"; | ||
| language = "swift"; | ||
| dylibPath = "${dylib}/libxmtpv3.a"; |
There was a problem hiding this comment.
🟠 High package/ios-bindings.nix:36
swift-bindings passes ${dylib}/libxmtpv3.a as dylibPath to uniffiGenerate, which forwards it to ffi-uniffi-bindgen generate --library. UniFFI library-mode generation requires a loadable shared library, not a static archive, and fails with Failed to extract data from archive member when given .a files. This causes the iOS bindings derivation to fail during Swift binding generation instead of producing the expected xcframework inputs.
- dylibPath = "${dylib}/libxmtpv3.a";
+ dylibPath = "${dylib}/libxmtpv3.dylib";🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @nix/package/ios-bindings.nix around line 36:
`swift-bindings` passes `${dylib}/libxmtpv3.a` as `dylibPath` to `uniffiGenerate`, which forwards it to `ffi-uniffi-bindgen generate --library`. UniFFI library-mode generation requires a loadable shared library, not a static archive, and fails with `Failed to extract data from archive member` when given `.a` files. This causes the iOS bindings derivation to fail during Swift binding generation instead of producing the expected xcframework inputs.
There was a problem hiding this comment.
Works in practice: uniffi-bindgen library mode reads static archives and the swift bindings in this PR were generated from libxmtpv3.a in green builds (device + simulator).
| - uses: maxim-lobanov/setup-xcode@v1 | ||
| with: | ||
| xcode-version: "26.3" |
There was a problem hiding this comment.
🟡 Medium workflows/lint-ios.yml:16
xcode-version: "26.3" is a semver range for maxim-lobanov/setup-xcode, not an exact version. The action resolves any installed version matching the range (e.g., 26.3.1), but xmtplabs/xmtp-cache-apple expects the exact content-addressed bundle at the pinned /nix/store path. When the resolved Xcode differs, the cache action only warns about the hash mismatch, then later tries to export the pinned store path which is absent — causing the lint job to fail on cold caches or after eviction. Consider pinning to an exact Xcode version string or adding validation that the selected Xcode matches the expected store path hash.
- uses: maxim-lobanov/setup-xcode@v1
with:
- xcode-version: "26.3"
+ xcode-version: "26.3.0"Also found in 1 other location(s)
sdks/ios/dev/.ensure-xcode:61
xcodes install "${XCODE_VERSION}"does not request the same Xcode variant that Nix expects. The pinned nixpkgs packagedarwin.xcode_26_3is the26.3_Universalbundle (pkgs/os-specific/darwin/xcode/default.nix), butxcodesnow has architecture-specific installs and can choose a non-universal download forinstall 26.3. When that happens, line 81 rejects the imported app because$got != $expected, so the new "auto-install Xcode" path fails on machines that download the Apple-silicon-only variant instead of the universal one.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @.github/workflows/lint-ios.yml around lines 16-18:
`xcode-version: "26.3"` is a semver range for `maxim-lobanov/setup-xcode`, not an exact version. The action resolves any installed version matching the range (e.g., `26.3.1`), but `xmtplabs/xmtp-cache-apple` expects the exact content-addressed bundle at the pinned `/nix/store` path. When the resolved Xcode differs, the cache action only warns about the hash mismatch, then later tries to export the pinned store path which is absent — causing the lint job to fail on cold caches or after eviction. Consider pinning to an exact Xcode version string or adding validation that the selected Xcode matches the expected store path hash.
Also found in 1 other location(s):
- sdks/ios/dev/.ensure-xcode:61 -- `xcodes install "${XCODE_VERSION}"` does not request the same Xcode variant that Nix expects. The pinned nixpkgs package `darwin.xcode_26_3` is the `26.3_Universal` bundle (`pkgs/os-specific/darwin/xcode/default.nix`), but `xcodes` now has architecture-specific installs and can choose a non-universal download for `install 26.3`. When that happens, line 81 rejects the imported app because `$got != $expected`, so the new "auto-install Xcode" path fails on machines that download the Apple-silicon-only variant instead of the universal one.
There was a problem hiding this comment.
Acknowledged, but the failure mode is loud-not-wrong: builds consume only the pinned /nix/store path. If setup-xcode resolves a different 26.3.x, the bootstrap import lands at a different store path, the pinned path stays absent, and the nix build fails with requireFile's instructions — a mismatched bundle can never silently poison a build. Warm runs restore from cache and never touch the local bundle. Tightening the bootstrap to verify before import is an xmtp-cache-apple change, tracked separately.
2ffdf70 to
f777113
Compare
edcd3c4 to
e43c26e
Compare
538dbd0 to
44a9c6d
Compare
| (hostPkgs.fetchpatch2 { | ||
| url = "https://github.com/NixOS/nixpkgs/compare/2f51ad37d9416828be4be7f48e7617b01cdf0641...insipx:nixpkgs:4f8f394b62476598617a085acda285902d5998ce.patch"; |
There was a problem hiding this comment.
🟠 High lib/default.nix:113
The fetchpatch2 call at line 113 uses a GitHub .patch URL without ?full_index=1. GitHub's patch files abbreviate index hashes by default, which fetchpatch2 cannot normalize, causing hash verification failures and breaking mkCrossPkgs on clean builds.
- (hostPkgs.fetchpatch2 {
- url = "https://github.com/NixOS/nixpkgs/compare/2f51ad37d9416828be4be7f48e7617b01cdf0641...insipx:nixpkgs:4f8f394b62476598617a085acda285902d5998ce.patch";
+ (hostPkgs.fetchpatch2 {
+ url = "https://github.com/NixOS/nixpkgs/compare/2f51ad37d9416828be4be7f48e7617b01cdf0641...insipx:nixpkgs:4f8f394b62476598617a085acda285902d5998ce.patch?full_index=1";🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @nix/lib/default.nix around lines 113-114:
The `fetchpatch2` call at line 113 uses a GitHub `.patch` URL without `?full_index=1`. GitHub's patch files abbreviate `index` hashes by default, which `fetchpatch2` cannot normalize, causing hash verification failures and breaking `mkCrossPkgs` on clean builds.
43307d7 to
a3861fd
Compare
| - uses: ./.github/actions/setup-ios-xcode | ||
| - uses: taiki-e/install-action@just |
There was a problem hiding this comment.
🟡 Medium workflows/lint-ios.yml:16
The new setup-ios-xcode step pins the workflow to a specific Xcode NAR, but just ios lint only runs swiftlint and swiftformat which don't require Xcode. When the Xcode cache is cold, the runner fails at bootstrap despite the lint tools being available, turning a previously reliable job into an intermittently failing gate. Consider removing this step since it's unnecessary for the tools being invoked.
- - uses: ./.github/actions/setup-ios-xcode
- uses: taiki-e/install-action@just🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @.github/workflows/lint-ios.yml around lines 16-17:
The new `setup-ios-xcode` step pins the workflow to a specific Xcode NAR, but `just ios lint` only runs `swiftlint` and `swiftformat` which don't require Xcode. When the Xcode cache is cold, the runner fails at bootstrap despite the lint tools being available, turning a previously reliable job into an intermittently failing gate. Consider removing this step since it's unnecessary for the tools being invoked.
8c1ff22 to
a083d4d
Compare
| nativeBuildInputs = xmtp.base.commonArgs.nativeBuildInputs ++ [ | ||
| cargo-llvm-cov | ||
| ]; | ||
| # Test executables link the nix openssl/sqlcipher dynamically | ||
| # (OPENSSL_NO_VENDOR) and cargo doesn't rpath — resolve at run time. | ||
| LD_LIBRARY_PATH = lib.makeLibraryPath xmtp.base.commonArgs.buildInputs; |
There was a problem hiding this comment.
🟡 Medium package/nextest.nix:31
LD_LIBRARY_PATH only works on ELF/Linux; macOS dyld uses DYLD_LIBRARY_PATH for runtime library resolution. Since this package is also instantiated for aarch64-darwin in nix/ci-checks.nix, test binaries on macOS will fail to start with missing library errors for openssl/sqlcipher.
Consider setting DYLD_LIBRARY_PATH for Darwin targets, either alongside or conditional to LD_LIBRARY_PATH.
# Test executables link the nix openssl/sqlcipher dynamically
# (OPENSSL_NO_VENDOR) and cargo doesn't rpath — resolve at run time.
LD_LIBRARY_PATH = lib.makeLibraryPath xmtp.base.commonArgs.buildInputs;
+ DYLD_LIBRARY_PATH = lib.optionalString stdenv.isDarwin (lib.makeLibraryPath xmtp.base.commonArgs.buildInputs);
};🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @nix/package/nextest.nix around lines 31-36:
`LD_LIBRARY_PATH` only works on ELF/Linux; macOS `dyld` uses `DYLD_LIBRARY_PATH` for runtime library resolution. Since this package is also instantiated for `aarch64-darwin` in `nix/ci-checks.nix`, test binaries on macOS will fail to start with missing library errors for `openssl`/`sqlcipher`.
Consider setting `DYLD_LIBRARY_PATH` for Darwin targets, either alongside or conditional to `LD_LIBRARY_PATH`.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3759 +/- ##
==========================================
+ Coverage 84.55% 84.64% +0.08%
==========================================
Files 410 410
Lines 60905 60905
==========================================
+ Hits 51497 51550 +53
+ Misses 9408 9355 -53 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
|
||
| # Use nixpkgs' pre-built openssl instead of letting openssl-sys vendor and build from source | ||
| # (which calls xcrun for the SDK and fails in cross sandboxes). | ||
| OPENSSL_NO_VENDOR = "1"; |
There was a problem hiding this comment.
🟠 High lib/base.nix:79
Setting OPENSSL_NO_VENDOR=1 forces openssl-sys to link against Nix store libraries, but the iOS packaging code only copies libxmtpv3 into the xcframework without bundling the dependent openssl/sqlcipher/zstd dylibs. The resulting xcframework references absolute Nix store paths that don't exist on consumer machines, causing linking/loading failures for iOS developers outside Nix. Consider vendoring OpenSSL for iOS targets, or ensuring the xcframework packaging rewrites/bundles the runtime dependencies.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @nix/lib/base.nix around line 79:
Setting `OPENSSL_NO_VENDOR=1` forces `openssl-sys` to link against Nix store libraries, but the iOS packaging code only copies `libxmtpv3` into the xcframework without bundling the dependent `openssl`/`sqlcipher`/`zstd` dylibs. The resulting xcframework references absolute Nix store paths that don't exist on consumer machines, causing linking/loading failures for iOS developers outside Nix. Consider vendoring OpenSSL for iOS targets, or ensuring the xcframework packaging rewrites/bundles the runtime dependencies.
| xcode-path: ${{ steps.xcode-path.outputs.path }} | ||
| # requireFile fixed-output path: moves only if the pinned sha256 for | ||
| # xcode_26_3 changes, never with nixpkgs/flake.lock bumps. | ||
| xcode-nix-path: /nix/store/x9hdz5mfp44i9b05sswp271jdv68r8vx-Xcode.app |
There was a problem hiding this comment.
🟡 Medium setup-ios-xcode/action.yml:36
The Resolve Xcode bundle path step accepts any 26.3.* patch build (line 24: case "$v" in 26.3|26.3.*)), but xcode-nix-path and the final DEVELOPER_DIR export hard-code a single store path (/nix/store/x9hdz5mfp44i9b05sswp271jdv68r8vx-Xcode.app) precomputed for one exact bundle. On a cold cache, a runner with a different patch build (e.g. 26.3.1) resolves a local Xcode whose hash produces a different store path, so xmtplabs/xmtp-cache-apple cannot import it into the expected /nix/store path and later steps that reference the hard-coded DEVELOPER_DIR fail. Consider tightening the version glob to match only the exact patch build the pinned xcode-nix-path was computed from.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @.github/actions/setup-ios-xcode/action.yml around line 36:
The `Resolve Xcode bundle path` step accepts any `26.3.*` patch build (line 24: `case "$v" in 26.3|26.3.*)`), but `xcode-nix-path` and the final `DEVELOPER_DIR` export hard-code a single store path (`/nix/store/x9hdz5mfp44i9b05sswp271jdv68r8vx-Xcode.app`) precomputed for one exact bundle. On a cold cache, a runner with a different patch build (e.g. `26.3.1`) resolves a local Xcode whose hash produces a different store path, so `xmtplabs/xmtp-cache-apple` cannot import it into the expected `/nix/store` path and later steps that reference the hard-coded `DEVELOPER_DIR` fail. Consider tightening the version glob to match only the exact patch build the pinned `xcode-nix-path` was computed from.
There was a problem hiding this comment.
🟡 Medium
libxmtp/.github/workflows/release-ios.yml
Line 130 in 72c4377
The publish job runs pod trunk push XMTP.podspec, which invokes xcodebuild for validation, but this job never calls .github/actions/setup-ios-xcode. It uses the runner's default Xcode, so if that differs from the pinned toolchain the pod validation/build can fail on the exact Xcode-version mismatch this PR is trying to eliminate. Add the same setup-ios-xcode step to the publish job (before the CocoaPods push) so both jobs use the same Xcode.
Also found in 1 other location(s)
sdks/ios/dev/.ensure-xcode:23
XCODE_VERSIONis taken from the ambient environment (XCODE_VERSION="${XCODE_VERSION:-26.3}"), but the actual iOS build graph is still pinned toxcodeVer = "26.3"innix/ios-packages.nix. If a developer or CI job already exportsXCODE_VERSION(a common variable name in Apple build tooling), this script will materialize and/or cache the wrongdarwin.xcode_*store path and return success, after which the subsequentnix buildstill fails because the real pinned Xcode was never imported.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @.github/workflows/release-ios.yml around line 130:
The `publish` job runs `pod trunk push XMTP.podspec`, which invokes `xcodebuild` for validation, but this job never calls `.github/actions/setup-ios-xcode`. It uses the runner's default Xcode, so if that differs from the pinned toolchain the pod validation/build can fail on the exact Xcode-version mismatch this PR is trying to eliminate. Add the same `setup-ios-xcode` step to the `publish` job (before the CocoaPods push) so both jobs use the same Xcode.
Also found in 1 other location(s):
- sdks/ios/dev/.ensure-xcode:23 -- `XCODE_VERSION` is taken from the ambient environment (`XCODE_VERSION="${XCODE_VERSION:-26.3}"`), but the actual iOS build graph is still pinned to `xcodeVer = "26.3"` in `nix/ios-packages.nix`. If a developer or CI job already exports `XCODE_VERSION` (a common variable name in Apple build tooling), this script will materialize and/or cache the wrong `darwin.xcode_*` store path and return success, after which the subsequent `nix build` still fails because the real pinned Xcode was never imported.
|
|
||
| # Use nixpkgs' pre-built openssl instead of letting openssl-sys vendor and build from source | ||
| # (which calls xcrun for the SDK and fails in cross sandboxes). | ||
| OPENSSL_NO_VENDOR = "1"; |
There was a problem hiding this comment.
🟠 High lib/base.nix:79
On Darwin, the Node addon build in nix/package/node.nix rewrites libiconv load commands in postFixup and then aborts if any other /nix/store path remains in otool -L output. Now that commonArgs forces dynamic linking against Nix openssl and sqlcipher via OPENSSL_NO_VENDOR/OPENSSL_*, the .node addon also records /nix/store/.../libssl, libcrypto, and libsqlcipher references. Those are never rewritten, so the existing remaining=$(otool -L ... | awk 'NR > 1 && $1 ~ /^\/nix\/store\//') check will fail the Darwin node build. Add install name rewrites for those libraries (or adjust the remaining-path check) so the Node addon does not carry unrewritten /nix/store references.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @nix/lib/base.nix around line 79:
On Darwin, the Node addon build in `nix/package/node.nix` rewrites `libiconv` load commands in `postFixup` and then aborts if any other `/nix/store` path remains in `otool -L` output. Now that `commonArgs` forces dynamic linking against Nix `openssl` and `sqlcipher` via `OPENSSL_NO_VENDOR`/`OPENSSL_*`, the `.node` addon also records `/nix/store/.../libssl`, `libcrypto`, and `libsqlcipher` references. Those are never rewritten, so the existing `remaining=$(otool -L ... | awk 'NR > 1 && $1 ~ /^\/nix\/store\//')` check will fail the Darwin node build. Add install name rewrites for those libraries (or adjust the remaining-path check) so the Node addon does not carry unrewritten `/nix/store` references.
<!-- Macroscope's pull request summary starts here --> <!-- Macroscope will only edit the content between these invisible markers, and the markers themselves will not be visible in the GitHub rendered markdown. --> <!-- If you delete either of the start / end markers from your PR's description, Macroscope will append its summary at the bottom of the description. --> > [!NOTE] > ### Update Rust toolchain to 1.96.1 and fix nix wasm and cargo zigbuild builds > - Bumps Rust channel in [flake.nix](https://github.com/xmtp/libxmtp/pull/3810/files#diff-206b9ce276ab5971a2489d75eb1b12999d4bf3843b7988cbe8d687cfde61dea0) from 1.95.0 to 1.96.1 and updates [flake.lock](https://github.com/xmtp/libxmtp/pull/3810/files#diff-216b2b7bfde9416c79d133bacb031e95702a20bdedb548c0b055c837aa4f6a9c) accordingly. > - Fixes [nix/package/node.nix](https://github.com/xmtp/libxmtp/pull/3810/files#diff-fa9b6ba547ea5ae35048580f634e5edb6375afb0138fd6fb6e77fef6ee8c357b) to pass an explicit `--target` flag to `cargo zigbuild` for glibc-suffixed targets. > - Reworks [nix/package/wasm.nix](https://github.com/xmtp/libxmtp/pull/3810/files#diff-2d98b57de1a5d3f600ce6146d8d6cf009fcdb1f194727820ef2639148b5ccd7e) to let `wasm-pack` install artifacts into `$out/dist` directly, removing cargo binary post-install and JSON log capture. > - Updates `@napi-rs/cli` from 3.5.1 to 3.7.2 and Playwright from 1.58 to 1.60 across JS packages. > - Updates `.envrc` to load the `#rust` flake output and adds `just` to the Rust dev shell. > > <!-- Macroscope's review summary starts here --> > > <sup><a href="https://app.macroscope.com">Macroscope</a> summarized 551ccfe.</sup> > <!-- Macroscope's review summary ends here --> > <!-- macroscope-ui-refresh --> <!-- Macroscope's pull request summary ends here --> updating the .envrc to use the #rust shell since the android bindings build w/o android sdk in nix shell & nix ios shell is broken until #3759 . further should make loading dev shell faster Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Cross pkgsets for arm64-apple-ios + simulator via mkCrossPkgs, iOS bindings derivations, and Darwin sandbox fixes for transitive deps.
Wrap the builder-host Xcode (~94 drvs vs ~2500 source-built); dedupe target config into iosCommon; ios-verify smoke-checks xcframeworks.
xcode-tools bundle + ios-xcframework module (static, dynamic, release, dev outputs); no __noChroot.
Cross pkgsets apply the upstream iOS branch onto nixos-unstable via fetchpatch2 (re-pin hash after branch pushes; URL in nix/lib/default.nix). SDK output content-addressed on the from-scratch path.
just ios build imports /Applications/Xcode_<ver>.app when missing (one-time, Darwin only); CI verifies xmtp-cache-apple already did it.
sqlcipher kept for musl dep-builds; DEVELOPER_DIR hook for xcodebuild; Android drops OPENSSL_* pins; reproducible version file; Linux hides unbuildable iOS outputs; plist min-version fixes; workflows derive xcode-path and materialize Xcode via xmtp-cache-apple.
Same stack applied to the same nixos-unstable input; existing cross drvs are unchanged.
An xcframework is one directory per slice plus an Info.plist manifest; write it directly with cctools + rcodesign. xcodebuild -create-xcframework dlopens host Xcode first-launch frameworks (CoreDevice -> MobileDevice), which cannot be bound into the build sandbox. Drops the xcode-tools bundle and the __impureHostDeps escape hatch.
Runner Xcode bundles are pruned images and never hash to the pinned requireFile path; bindings substitute from xmtp.cachix and swift steps fall back to the version-verified runner bundle.
Static OpenSSL for shipped Apple binaries (nix-store dylib refs crash on device); floors stay 14/11, asserted against Package.swift/podspec at eval; validation checks LC_BUILD_VERSION and store-path leaks; symlink-safe release packaging; shared slice/openssl helpers.
| @@ -58,14 +58,16 @@ let | |||
| # We detect this by checking if the result starts with /nix/ and skip it. | |||
| resolveXcode = '' | |||
There was a problem hiding this comment.
🟡 Medium lib/ios-env.nix:59
When DEVELOPER_DIR is a non-/nix path like /Library/Developer/CommandLineTools (the Command Line Tools package, not a full Xcode), resolveXcode accepts it without verifying it contains a real Xcode toolchain. The exported CC/CXX paths (.../Toolchains/XcodeDefault.xctoolchain/usr/bin/clang) and iOS SDK paths (Platforms/iPhoneOS.platform/...) do not exist in that tree, so envSetup/envSetupAll produce broken compiler and SDK variables and iOS compilation fails — even when xcode-select -p points at a usable full Xcode. Consider rejecting DEVELOPER_DIR values that lack Toolchains/XcodeDefault.xctoolchain and falling through to the xcode-select lookup instead.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @nix/lib/ios-env.nix around line 59:
When `DEVELOPER_DIR` is a non-`/nix` path like `/Library/Developer/CommandLineTools` (the Command Line Tools package, not a full Xcode), `resolveXcode` accepts it without verifying it contains a real Xcode toolchain. The exported `CC`/`CXX` paths (`.../Toolchains/XcodeDefault.xctoolchain/usr/bin/clang`) and iOS SDK paths (`Platforms/iPhoneOS.platform/...`) do not exist in that tree, so `envSetup`/`envSetupAll` produce broken compiler and SDK variables and iOS compilation fails — even when `xcode-select -p` points at a usable full Xcode. Consider rejecting `DEVELOPER_DIR` values that lack `Toolchains/XcodeDefault.xctoolchain` and falling through to the `xcode-select` lookup instead.
this resolves some issues compiling on macOS that crop up occasionally b/c of conflicting XCodes.
this applies my patch which fixes iOS cross-compilation upstream. it adds a script which imports XCode into the nix store, if the right xcode version does not exist it downloads the correct version with
xcodes. this pins the xcode version for the iOS library builds.Note
Add Nix-native iOS cross-compilation pipeline for xcframework and Swift bindings
ios-libs,ios-xcframework-static,ios-xcframework-dynamic,ios-release, andios-devFast.mkCrossPkgsby patching nixpkgs at build time (via fetchpatch2 of the upstream iOS PR) to enable iOS cross toolchains.libxmtpv3static/dynamic libraries and generate Swift FFI headers via uniffi.mkStatic,mkDynamic,mkRelease, andmkDevconstructors that lipo slices, assemble signed.frameworkbundles, and invokexcodebuild -create-xcframework.commonArgsin nix/lib/base.nix: switches fromsqlitetosqlcipher, enforcesstrictDeps, and uses system OpenSSL instead of vendored builds.nix/lib/base.nixchanges affect all Rust derivations — switching tosqlcipherand system OpenSSL may break existing builds that relied on vendored dependencies.📊 Macroscope summarized 570924d. 7 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted
🗂️ Filtered Issues
No issues evaluated.