Skip to content

fix(ios): build one simulator arch for --remote and key iOS simulator builds by arch - #1834

Merged
janicduplessis merged 4 commits into
mainfrom
fix/1803-remote-ios-single-arch
Sep 28, 2026
Merged

janicduplessis merged 4 commits into
mainfrom
fix/1803-remote-ios-single-arch

Conversation

@janicduplessis

@janicduplessis janicduplessis commented Sep 28, 2026 •

Copy link
Copy Markdown
Collaborator

Description

stim ios --remote proxy|eas builds with -destination 'generic/platform=iOS Simulator' because no remote UDID exists at build time (#1212 boots the remote device after the build). With a generic destination Xcode forces ONLY_ACTIVE_ARCH=NO and compiles every ARCHS value, so a remote build compiled arm64 and x86_64 for a simulator that runs one of them: about twice the xcodebuild time, .app size and DerivedData (numbers in #1803).

Separately, the iOS simulator cache key carried no architecture, so an arm64-only Debug build, an Intel Mac's x86_64-only build and a fat build all shared <fp>-debug-sim, locally and in the Expo build cache provider.

Solution

One slice for --remote. The generic destination stays; the build adds ARCHS=<arch> ONLY_ACTIVE_ARCH=YES, the only thing that narrows a generic build. <arch> is the agent-device /health hostArch (callstack/agent-device#3048, upstream.hostArch first when talking to a proxy), read once per run. A missing or unknown value, an error, or no answer in 3 s means arm64, so today, before any agent-device release reports the field, every remote gets arm64.

EAS never gets a /health read: its daemon URL only exists once eas sim creates the session, which since #1212 happens after the build. EAS hosts are Apple silicon (checked in #1803), so arm64 is correct there.

Arch in the iOS simulator key, mirroring Android's ABI component:

Build Key
local Debug simulator <fp>-debug-sim-arm64 (-x86-64 on an Intel Mac, from process.arch)
--remote (any configuration) <fp>-<config>-sim-<remote arch>
local Release/other simulator <fp>-release-sim, unchanged
device <fp>-debug-device, unchanged

Existing iOS Debug simulator cache entries miss once after this lands. A local non-Debug simulator build stays fat (#608), and I kept its key unsuffixed rather than adding -universal: no suffix already means "the ARCHS the project lists", as on Android, and Release entries stay valid. @stim-cli/expo-build-cache keys expo run:ios Debug simulator builds on the host arch the same way (--device generic stays unsuffixed, since it compiles every ARCHS; a simulator named with --device <name> keys as on-<name> with no arch, as before, because the name cannot tell a simulator from a phone), and remote build-cache providers now receive arch in runOptions, as Android passes abi.

stim ios --plan now refuses the ios.remote setting with STIM_BAD_ARG, as it already did for android.remote: the run keys the remote arch, which a plan cannot read without a session. No setting or flag is added.

Test plan

  • Not run: a full stim ios --remote proxy install. A local proxy would let agent-device pick a simulator on this shared machine that Stim does not own, and an EAS session is billed.
  • Real xcodebuild -showBuildSettings on apps/mobile (Xcode 27.0, arm64, target Stim, generic destination): Debug and Release both resolve ARCHS = arm64 x86_64; adding ARCHS=arm64 ONLY_ACTIVE_ARCH=YES gives arm64, and ARCHS=x86_64 ... gives x86_64.
  • Real build with the exact new remote arguments (generic destination, ARCHS=arm64 ONLY_ACTIVE_ARCH=YES, fresh DerivedData, no compilation cache): BUILD SUCCEEDED, lipo -archs gives arm64 for Stim.app/Stim and ExpoCamera.framework, .app 172 MB, DerivedData 4.4 GB. The same build without the settings (what --remote did before): x86_64 arm64, 341 MB, 9.5 GB. Wall times were 339 s single-arch and 380 s fat, but the machine load differed a lot between the runs (load average about 80-225 vs 40-80), so the times don't compare; the A/B in ios --remote compiles arm64 and x86_64 for a one-arch simulator; iOS sim cache key has no arch #1803 measured 151 s vs 285 s.
  • readRemoteSimulatorArch against a real loopback agent-device proxy 0.21.12: /agent-device/health returns no hostArch, and the reader returns arm64; a closed port also returns arm64.
  • Unit tests cover the /health parser and reader (proxy upstream, absent, unknown arch, error, bad JSON, timeout), the xcodebuild argv with and without an arch, stim ios --remote proxy|eas reading /health once and building/keying that arch, the key table, and the CLI and expo-build-cache resolving the same iOS entries (cache-packages.test.ts).

Fixes #1803

… builds by arch

A --remote build uses the generic simulator destination, where Xcode compiles every ARCHS value. Pass ARCHS=<arch> ONLY_ACTIVE_ARCH=YES, reading the arch from the agent-device daemon /health hostArch and defaulting to arm64. The iOS simulator cache key now ends in the arch for single-arch builds, in the CLI and in @stim-cli/expo-build-cache.

Closes #1803
A remote run keys the remote simulator arch, which a plan cannot read without a session, matching the android.remote refusal.
Expo --device generic compiles every ARCHS value, so it keeps the unsuffixed key. Also scope the plan guide's CAS and no-device refusals to Android.
@janicduplessis
janicduplessis marked this pull request as ready for review September 28, 2026 21:50
@janicduplessis
janicduplessis merged commit 9c93b98 into main Sep 28, 2026
8 checks passed
@janicduplessis
janicduplessis deleted the fix/1803-remote-ios-single-arch branch September 28, 2026 21:50
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.

ios --remote compiles arm64 and x86_64 for a one-arch simulator; iOS sim cache key has no arch

1 participant