An easy-to-host PDS on the ATProtocol, iPhone and MacOS. Maintain control of your keys and data, always.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(MM-143): resolve Nix devenv vs Xcode toolchain conflicts for iOS dev

Four interacting issues prevented `cargo tauri ios dev` from working in the
Nix devenv environment:

1. languages.rust used Nix's rust-default which ships no iOS target stdlibs.
Fix: replace with pkgs.rustup + project-local RUSTUP_HOME/CARGO_HOME so
rustup reads rust-toolchain.toml and installs aarch64-apple-ios-sim stdlib.

2. Nix Darwin setup hooks override DEVELOPER_DIR to a stub apple-sdk with no
runtime tools (xcrun simctl fails with "tool not found").
Fix: re-export DEVELOPER_DIR to real Xcode.app in enterShell, which runs
after all Nix hooks and wins.

3. Nix cc-wrapper injects -mmacos-version-min into iOS target CC invocations,
which clang rejects alongside -mios-simulator-version-min.
Fix: src-tauri/.cargo/config.toml sets CC_aarch64_apple_ios_sim to
Xcode's unwrapped clang for build scripts.

4. Nix cc-wrapper uses macOS sysroot for the iOS target final link, failing to
find UIKit and other iOS frameworks.
Fix: .cargo/config.toml sets [target.aarch64-apple-ios-sim].linker (and
aarch64-apple-darwin for proc-macro host builds) to Xcode's clang.

authored by

Malpercio and committed by
Tangled
c4c5d70e 17163c37

+91 -9
+21 -1
apps/identity-wallet/CLAUDE.md
··· 64 64 After cloning the repo, perform these steps once per developer machine: 65 65 66 66 ```bash 67 - # 1. Enter the Nix dev shell (provides cargo-tauri, node 22, pnpm) 67 + # 1. Enter the Nix dev shell (provides cargo-tauri, node 22, pnpm, rustup) 68 + # On first entry, enterShell installs the Rust toolchain + iOS targets via rustup. 69 + # This reads rust-toolchain.toml and may download ~2-4 GB — takes a few minutes. 68 70 nix develop --impure --accept-flake-config 69 71 70 72 # 2. Install frontend dependencies ··· 76 78 ``` 77 79 78 80 Note: `src-tauri/gen/` contains a machine-specific Xcode project. It is gitignored and must be re-generated on each developer machine. Do not commit it. 81 + 82 + ### Xcode build phase PATH (one-time manual step after `cargo tauri ios init`) 83 + 84 + Xcode's Run Script build phases do not inherit the Nix dev shell PATH. After regenerating `src-tauri/gen/`, the generated `project.pbxproj` script must be patched to expose both the devenv tools and the rustup-managed cargo: 85 + 86 + Open `src-tauri/gen/apple/identity-wallet.xcodeproj/project.pbxproj` and find the `shellScript` line in the PBXShellScriptBuildPhase section. Prepend: 87 + 88 + ``` 89 + export PATH="<project-root>/.devenv/state/cargo/bin:<project-root>/.devenv/profile/bin:$PATH" 90 + ``` 91 + 92 + where `<project-root>` is the absolute path to the repo root (e.g. `/Users/you/workspace/malpercio-dev/ezpds`). 93 + 94 + This step is required once per `cargo tauri ios init` run. 95 + 96 + ### Why rustup instead of Nix-managed Rust 97 + 98 + `languages.rust` in devenv uses Nix's `rust-default` package, which only ships stdlibs for standard host targets. iOS Simulator requires `aarch64-apple-ios-sim` stdlib. Nix doesn't package iOS cross-compilation stdlibs; `rustup` downloads them from the Rust release infrastructure. The dev shell is configured with project-local `RUSTUP_HOME` and `CARGO_HOME` (inside `.devenv/state/`) so the toolchain is isolated per project. 79 99 80 100 ## Development Workflow 81 101
+43
apps/identity-wallet/src-tauri/.cargo/config.toml
··· 1 + # iOS cross-compilation toolchain overrides. 2 + # 3 + # Nix's devenv shell puts its cc-wrapper (clang) in PATH via .devenv/profile/bin. 4 + # The cc-wrapper injects -mmacos-version-min=14.0 for the host platform, which 5 + # clang rejects when -mios-simulator-version-min is also present: 6 + # 7 + # clang: error: invalid argument '-mmacos-version-min=14.0' 8 + # not allowed with '-mios-simulator-version-min=14.0' 9 + # 10 + # Setting CC_* to Xcode's unwrapped clang (from XcodeDefault.xctoolchain) bypasses 11 + # the Nix wrapper for iOS targets while leaving macOS host builds unaffected. 12 + # Xcode is always installed at /Applications/Xcode.app on macOS. 13 + 14 + [env] 15 + CC_aarch64_apple_ios_sim = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" 16 + CC_aarch64_apple_ios = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" 17 + AR_aarch64_apple_ios_sim = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar" 18 + AR_aarch64_apple_ios = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar" 19 + 20 + # Linker overrides — for all targets, bypass the Nix cc-wrapper linker. 21 + # 22 + # The Nix cc-wrapper always injects its compiled-in macOS sysroot, which causes 23 + # two classes of failure: 24 + # 25 + # HOST (aarch64-apple-darwin) proc-macros / build scripts: 26 + # ld: library not found for -liconv 27 + # (Nix apple-sdk stub omits some /usr/lib stubs) 28 + # 29 + # iOS TARGET (aarch64-apple-ios-sim) final link: 30 + # ld: framework not found UIKit 31 + # clang: warning: using sysroot for 'MacOSX' but targeting 'iPhone' 32 + # (macOS sysroot injected even when rustc passes -target arm64-apple-ios*-simulator) 33 + # 34 + # Xcode's clang handles both host and iOS sysroots correctly. 35 + 36 + [target.aarch64-apple-darwin] 37 + linker = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" 38 + 39 + [target.aarch64-apple-ios-sim] 40 + linker = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" 41 + 42 + [target.aarch64-apple-ios] 43 + linker = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang"
+2 -2
apps/identity-wallet/src-tauri/Cargo.toml
··· 14 14 15 15 [dependencies] 16 16 # Tauri-specific — declared locally (not in workspace.dependencies per design plan) 17 - tauri = "2" 17 + tauri = { version = "2", features = [] } 18 18 # serde/serde_json are in workspace.dependencies (root Cargo.toml lines 30-32) 19 19 serde = { workspace = true } 20 20 serde_json = { workspace = true } 21 21 22 22 [build-dependencies] 23 23 # Tauri-specific — declared locally 24 - tauri-build = "2" 24 + tauri-build = { version = "2", features = [] } 25 25 26 26 # Tauri-recommended release optimizations for mobile binary size. 27 27 # IMPORTANT: Cargo ignores [profile.*] in workspace member crates — these settings
+25 -6
devenv.nix
··· 1 1 { pkgs, config, ... }: 2 2 { 3 - languages.rust = { 4 - enable = true; 5 - toolchainFile = ./rust-toolchain.toml; 6 - }; 7 - 8 3 packages = [ 9 4 pkgs.just 10 5 pkgs.cargo-audit ··· 13 8 pkgs.cargo-tauri 14 9 pkgs.nodejs_22 15 10 pkgs.pnpm 11 + pkgs.rustup 16 12 ]; 17 13 18 14 env.LIBSQLITE3_SYS_USE_PKG_CONFIG = "1"; 19 15 16 + # Rustup/Cargo state lives inside the project tree for a hermetic, per-project 17 + # toolchain installation. enterShell (below) prepends CARGO_HOME/bin to PATH. 18 + # languages.rust is intentionally absent: Nix's rust-default package does not 19 + # ship iOS target stdlibs; rustup reads rust-toolchain.toml and installs them. 20 + env.RUSTUP_HOME = "${config.devenv.root}/.devenv/state/rustup"; 21 + env.CARGO_HOME = "${config.devenv.root}/.devenv/state/cargo"; 22 + 20 23 # Relay dev configuration — override any of these in devenv.local.nix. 21 24 env.EZPDS_CONFIG = "${config.devenv.root}/relay.dev.toml"; 22 25 env.EZPDS_DATA_DIR = "${config.devenv.root}/.devenv/state/relay"; ··· 27 30 # DO NOT USE IN PRODUCTION. 28 31 env.EZPDS_SIGNING_KEY_MASTER_KEY = "2a55ebbdb7c0a4864a3944a443765b13602c6fbbeda38c2d6afc57b96663810e"; 29 32 33 + enterShell = '' 34 + # Nix's Darwin setup hooks (xcbuild, apple-sdk) override DEVELOPER_DIR to a 35 + # Nix SDK stub that has no runtime tools. Re-export here so this shell and all 36 + # processes it spawns (cargo tauri ios dev, xcodebuild, xcrun, simctl) use the 37 + # real Xcode installation. enterShell runs after all Nix hooks, so it wins. 38 + export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer" 39 + export PATH="$CARGO_HOME/bin:$PATH" 40 + if ! "$CARGO_HOME/bin/cargo" --version > /dev/null 2>&1; then 41 + echo "Installing Rust toolchain (first time — reads rust-toolchain.toml)…" 42 + rustup toolchain install 43 + fi 44 + ''; 45 + 30 46 processes.relay = { 31 - exec = "cargo run --package relay"; 47 + exec = '' 48 + export PATH="$CARGO_HOME/bin:$PATH" 49 + exec cargo run --package relay 50 + ''; 32 51 }; 33 52 }