Skip to content

nix-native ios cross compile#3759

Draft
insipx wants to merge 7 commits into
mainfrom
insipx/ios-build
Draft

nix-native ios cross compile#3759
insipx wants to merge 7 commits into
mainfrom
insipx/ios-build

Conversation

@insipx

@insipx insipx commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

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

  • Introduces a new nix/ios-packages.nix flake-parts module that defines iOS cross targets and exposes packages: ios-libs, ios-xcframework-static, ios-xcframework-dynamic, ios-release, and ios-devFast.
  • Adds nix/lib/default.nix support for mkCrossPkgs by patching nixpkgs at build time (via fetchpatch2 of the upstream iOS PR) to enable iOS cross toolchains.
  • Adds nix/package/ios-bindings.nix to build per-ABI libxmtpv3 static/dynamic libraries and generate Swift FFI headers via uniffi.
  • Adds nix/package/ios-xcframework/ with mkStatic, mkDynamic, mkRelease, and mkDev constructors that lipo slices, assemble signed .framework bundles, and invoke xcodebuild -create-xcframework.
  • Adds dev/ios-verify to validate Mach-O artifacts for iOS shippability (platform, arch, load commands, nix store refs, symbol blocklist).
  • Adds sdks/ios/dev/.ensure-xcode to auto-import the required Xcode version into the Nix store on developer machines.
  • Changes commonArgs in nix/lib/base.nix: switches from sqlite to sqlcipher, enforces strictDeps, and uses system OpenSSL instead of vendored builds.
  • Risk: nix/lib/base.nix changes affect all Rust derivations — switching to sqlcipher and system OpenSSL may break existing builds that relied on vendored dependencies.
📊 Macroscope summarized 90ab637. 20 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

Cross pkgsets for arm64-apple-ios + simulator via mkCrossPkgs, iOS
bindings derivations, and Darwin sandbox fixes for transitive deps.
@claude

claude Bot commented Jun 10, 2026

Copy link
Copy Markdown

Claude finished @insipx's task —— View job


PR Review - iOS Cross-Compilation

Reviewed on June 11, 2026 at 19:40 UTC

This PR introduces significant improvements to iOS cross-compilation with hermetic Xcode handling. The refactoring is well-structured, and most critical issues have been addressed through the review process. Below are the remaining observations:

Key Findings

1. Android Build Reproducibility Inconsistency ⚠️ Medium Priority

nix/package/android.nix:67 still uses wall-clock date ($(date -u +%Y-%m-%d)) for version file generation, while iOS was correctly fixed to use ${xmtp.gitCommitDate} for reproducibility. This inconsistency breaks deterministic builds for Android artifacts.

# Current (non-reproducible):
echo "Date: $(date -u +%Y-%m-%d)" >> $out/libxmtp-version.txt

# Should be:
echo "Date: ${xmtp.gitCommitDate}" >> $out/libxmtp-version.txt

2. Test Coverage Gap 📋 Informational

The new xcframework build infrastructure (nix/package/ios-xcframework/) includes validation checks for framework structure but lacks:

  • Integration tests for the Xcode import mechanism
  • Tests verifying xcframework validity across different Xcode versions
  • Automated verification that simulator/device slices work correctly

The existing iOS Swift test suite at sdks/ios/Tests/XMTPTests/ will exercise the generated bindings, but consider adding:

  • A CI check that builds and loads the xcframework on a real simulator
  • Verification that the "fast" builds work for local development

3. Security/Safety ObservationsAddressed or Low Risk

  • __impureHostDeps usage is appropriately scoped to only /Library/Developer/PrivateFrameworks
  • ✅ OPENSSL environment variables correctly gated per platform
  • ✅ Xcode pinning prevents version conflicts
  • ⚠️ The patch URL at nix/lib/default.nix:114 still references a personal fork branch rather than upstream nixpkgs, but the author has documented this as intentional until upstream merge

4. Code QualityGood

  • Well-structured module separation (helpers, mk-static, mk-dynamic, mk-release, mk-dev)
  • Clear comments explaining cross-compilation complexity
  • Proper use of Nix idioms and error handling
  • Good validation in xcframework builders

Minor Observations

  • .envrc change from .#local to .#rust shell may impact developers who rely on just being available, but this appears intentional
  • The 43 files changed is significant but well-organized into logical modules
  • Documentation in comments is thorough

Summary

This is a solid refactoring that achieves the stated goal of hermetic iOS builds with pinned Xcode. The main actionable item is fixing the Android reproducibility inconsistency to match the iOS fix. Test coverage could be enhanced but the existing Swift test suite should catch functional regressions.


Wrap the builder-host Xcode (~94 drvs vs ~2500 source-built); dedupe
target config into iosCommon; ios-verify smoke-checks xcframeworks.
@insipx insipx force-pushed the insipx/ios-build branch 2 times, most recently from 90ab637 to d23960c Compare June 10, 2026 21:28
Comment thread nix/lib/base.nix
Comment thread nix/package/mls_validation_service.nix
Comment thread nix/lib/packages/xcode-tools.nix
Comment thread flake.nix

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High

packages = {

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.

Comment thread .envrc
@@ -1,2 +1,2 @@
watch_file nix/shells/local.nix
use flake .
# watch_file nix/shells/local.nix

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Comment thread sdks/ios/dev/.ensure-xcode
Comment thread nix/ios-packages.nix Outdated
xcode-tools bundle + ios-xcframework module (static, dynamic,
release, dev outputs); no __noChroot.
@insipx insipx force-pushed the insipx/ios-build branch from d23960c to d468d2c Compare June 10, 2026 21:34
Comment thread nix/lib/patches.nix
Comment thread nix/lib/default.nix Outdated
Comment thread nix/lib/base.nix
Comment on lines +75 to +80
# 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";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 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.

Comment thread sdks/ios/dev/.ensure-xcode
Comment thread nix/package/ios-bindings.nix
Comment thread nix/ios-packages.nix
version = xmtp.mkVersion rust;
inherit (base) commonArgs bindingsFileset;

cargoArtifacts = xmtp.base.mkCargoArtifacts rust false null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread nix/ios-packages.nix
Comment on lines +74 to +77
fastAbis = [
fastAbi
"iphone64-simulator"
];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged limitation: x86_64 simulator slices are intentionally unsupported (team is arm64-only). Can revisit if an Intel use-case appears.

Comment thread nix/package/ios-xcframework/helpers.nix
Comment thread sdks/ios/dev/.ensure-xcode
inherit version;
pname = "xmtpv3-swift";
language = "swift";
dylibPath = "${dylib}/libxmtpv3.a";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Comment thread sdks/ios/dev/bindings Outdated
Comment thread nix/lib/patches.nix
Comment thread sdks/ios/dev/.ensure-xcode
Comment thread sdks/ios/dev/bindings

# Darwin only: Linux workstations build via remote Darwin builders, which
# hold their own Xcode import.
if [[ "$(uname -s)" == "Darwin" ]]; then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium dev/bindings:6

The Darwin preflight unconditionally executes .ensure-xcode on the local machine, which fails or prompts for local Xcode installation even when the actual build will use a remote Darwin builder that already has Xcode imported. This breaks valid macOS + remote builder workflows where local Xcode is not required.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @sdks/ios/dev/bindings around line 6:

The Darwin preflight unconditionally executes `.ensure-xcode` on the local machine, which fails or prompts for local Xcode installation even when the actual build will use a remote Darwin builder that already has Xcode imported. This breaks valid macOS + remote builder workflows where local Xcode is not required.

Comment thread nix/package/ios-xcframework/default.nix
Comment on lines +34 to +36
mkdir -p $out/nix-support
echo 'export DEVELOPER_DIR="${darwin.xcode}/Contents/Developer"' \
> $out/nix-support/setup-hook

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium packages/xcode-tools.nix:34

The setup-hook only exports DEVELOPER_DIR, leaving SDKROOT unchanged from the Nix apple SDK. This causes child tools that use xcrun to resolve SDK paths from the wrong source while xcodebuild uses the pinned Xcode, breaking hermeticity and potentially causing intermittent build failures or wrong SDK selection. Per the repo's own nix/lib/ios-env.nix, both variables must be overridden together.

    mkdir -p $out/nix-support
-    echo 'export DEVELOPER_DIR="${darwin.xcode}/Contents/Developer"' \
-      > $out/nix-support/setup-hook
+    cat > $out/nix-support/setup-hook <<'EOF'
+export DEVELOPER_DIR="${darwin.xcode}/Contents/Developer"
+export SDKROOT="${darwin.xcode}/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"
+EOF
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @nix/lib/packages/xcode-tools.nix around lines 34-36:

The `setup-hook` only exports `DEVELOPER_DIR`, leaving `SDKROOT` unchanged from the Nix apple SDK. This causes child tools that use `xcrun` to resolve SDK paths from the wrong source while `xcodebuild` uses the pinned Xcode, breaking hermeticity and potentially causing intermittent build failures or wrong SDK selection. Per the repo's own `nix/lib/ios-env.nix`, both variables must be overridden together.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The xcframework derivations only run lipo/codesign/xcodebuild packaging — no compilation, no xcrun SDK resolution. SDKROOT consumers are absent, so the hook intentionally scopes to DEVELOPER_DIR only.

Comment thread nix/ios-packages.nix
Comment thread .github/workflows/test-ios.yml Outdated
@insipx insipx force-pushed the insipx/ios-build branch from b74529b to 9ec5479 Compare June 10, 2026 22:05
Comment thread .github/workflows/lint-ios.yml Outdated
Comment on lines +16 to +18
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: "26.3"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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 &#34;${XCODE_VERSION}&#34; 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.

🚀 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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread nix/package/ios-xcframework/helpers.nix
@insipx insipx force-pushed the insipx/ios-build branch from 9ec5479 to 801c918 Compare June 10, 2026 22:27
insipx added 3 commits June 10, 2026 22:03
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.
@insipx insipx force-pushed the insipx/ios-build branch 2 times, most recently from 2ffdf70 to f777113 Compare June 11, 2026 02:10
Comment thread nix/lib/uniffiGenerate.nix
Comment thread sdks/ios/dev/.ensure-xcode Outdated
Comment thread nix/package/ios-xcframework/mk-dynamic.nix Outdated
Comment thread nix/lib/base.nix Outdated
Comment thread sdks/ios/dev/.ensure-xcode Outdated
Comment thread nix/package/ios-xcframework/mk-dynamic.nix
Comment thread nix/lib/packages/xcode-tools.nix
@insipx insipx force-pushed the insipx/ios-build branch from f777113 to bf8ac4d Compare June 11, 2026 02:21
Comment thread .github/actions/setup-ios-xcode/action.yml
Comment thread .github/workflows/release-ios.yml
@insipx insipx force-pushed the insipx/ios-build branch from bf8ac4d to 83b1163 Compare June 11, 2026 02:57
Comment thread .github/actions/setup-ios-xcode/action.yml Outdated
Comment thread nix/ios-packages.nix
@insipx insipx force-pushed the insipx/ios-build branch from 83b1163 to adae38e Compare June 11, 2026 03:09
Comment thread .github/actions/setup-ios-xcode/action.yml Outdated
@insipx insipx force-pushed the insipx/ios-build branch from adae38e to 7be2c67 Compare June 11, 2026 03:30
Comment thread .github/actions/setup-ios-xcode/action.yml
@insipx insipx force-pushed the insipx/ios-build branch 2 times, most recently from edcd3c4 to e43c26e Compare June 11, 2026 06:38
Comment thread nix/ios-packages.nix Outdated
@insipx insipx force-pushed the insipx/ios-build branch 5 times, most recently from d3a6240 to fcfbf7d Compare June 11, 2026 15:54
Comment thread nix/lib/default.nix
Comment on lines +113 to +114
(hostPkgs.fetchpatch2 {
url = "https://github.com/NixOS/nixpkgs/compare/2f51ad37d9416828be4be7f48e7617b01cdf0641...insipx:nixpkgs:4f8f394b62476598617a085acda285902d5998ce.patch";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 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.

@insipx insipx force-pushed the insipx/ios-build branch 2 times, most recently from 43307d7 to a3861fd Compare June 11, 2026 16:10
Comment on lines +16 to 17
- uses: ./.github/actions/setup-ios-xcode
- uses: taiki-e/install-action@just

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

@insipx insipx force-pushed the insipx/ios-build branch 4 times, most recently from 8c1ff22 to a083d4d Compare June 11, 2026 18:44
Comment thread nix/package/nextest.nix Outdated
Comment on lines +31 to +36
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;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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`.

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.
@insipx insipx force-pushed the insipx/ios-build branch from a083d4d to 5eabd41 Compare June 11, 2026 19:39
@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 84.44%. Comparing base (8ad390a) to head (5eabd41).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3759      +/-   ##
==========================================
- Coverage   84.45%   84.44%   -0.02%     
==========================================
  Files         408      408              
  Lines       59772    59807      +35     
==========================================
+ Hits        50483    50502      +19     
- Misses       9289     9305      +16     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread nix/lib/base.nix

# 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";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant