[iOS][SPM] Derive the generated manifests' iOS platform floor from the app - #58379
Open
chrfalch wants to merge 5 commits into
Open
[iOS][SPM] Derive the generated manifests' iOS platform floor from the app#58379chrfalch wants to merge 5 commits into
chrfalch wants to merge 5 commits into
Conversation
chrfalch
marked this pull request as ready for review
September 9, 2026 07:46
cipolleschi
reviewed
Sep 9, 2026
cipolleschi
left a comment
Contributor
There was a problem hiding this comment.
A couple of questions about deployment-target propagation:
cipolleschi
reviewed
Sep 10, 2026
Contributor
|
Thanks for addressing the earlier feedback! Could you please also rebase this PR onto the latest |
Copilot stopped work on behalf of
rachel11026725 due to an error
September 10, 2026 10:35
chrfalch
force-pushed
the
chrfalch/spm-ios-deployment-target-floor
branch
from
September 10, 2026 10:37
54d0f61 to
19dc7a9
Compare
…e app
The Autolinked aggregate, the per-dependency synth packages and the
scaffolded community packages hardcoded `platforms: [.iOS(.v15)]`. SwiftPM
refuses to link a product whose minimum platform is above the depending
target's, so any self-managed package with a higher floor (every Expo
package: iOS 16.4) failed to resolve:
The package product 'Expo' requires minimum platform version 16.4 for the
iOS platform, but this target supports 15.0 (in target 'AutolinkedAggregate')
The floor is now the app's own IPHONEOS_DEPLOYMENT_TARGET, read from the
injected .xcodeproj (the marker's target, else the `--product-name` target,
else every application target; target configuration first, then the
project-level configuration of the same name; the lowest wins), clamped to
React Native's minimum (15.1) and emitted in string form (`.iOS("16.4")`).
setup-apple-spm.js resolves it once per run and passes it to the generator,
the sync script and the scaffolder via `--ios-deployment-target`.
SCAFFOLDER_VERSION is bumped so existing scaffolds regenerate.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Drop table rows and assertions that exercised the same branch twice or pinned internal layering, share the pbxproj fixture builders between the two suites that need a two-target project, and turn the helpers.rb parity test into a real read of min_ios_version_supported. Two matching code simplifications: the reader no longer normalizes (the comparison is numeric and the resolver sanitizes), and the marker uuid is used without an `isa` guard (a stale uuid still degrades to the default). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A configuration without a literal deployment target now falls back to the xcconfig its baseConfigurationReference points at, per Xcode's precedence (target literal, target xcconfig, project literal, project xcconfig). `<group>` references are anchored through the PBXGroup chain, `#include` lines are followed in place so a later assignment in the includer wins, and only the unconditional key with a plain version counts. A floor set through a build-setting variable is still not resolved and falls back to React Native's minimum. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…update `spm add` and `spm update` now rewrite the `platforms: [.iOS(...)]` element of every scaffolded manifest carrying the scaffolder marker to the app's deployment target, covering the `.iOS(.v15)` form older scaffolds carry. Nothing else in the file is touched and no scaffold is created; the full re-render stays with `spm scaffold`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The floor refresh visited only the direct autolinking.json entries, while the scaffolder covers the expanded set including transitive SwiftPM dependencies, so a previously scaffolded transitive dep kept its old floor after `spm update`. Both now share one dependency-collection helper. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
chrfalch
force-pushed
the
chrfalch/spm-ios-deployment-target-floor
branch
from
September 10, 2026 11:39
19dc7a9 to
167dc22
Compare
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary:
The SwiftPM manifests React Native generates — the
Autolinkedaggregate, the per-dependency synth packages, and the scaffolded community packages — hardcodedplatforms: [.iOS(.v15)]. SwiftPM refuses to link a product whose minimum platform is above the depending target's, so any self-managed package with a higher floor could not be autolinked. Every Expo package declares iOS 16.4, so a stock Expo app on 0.87.1 fails at build time with:The app itself is correct (
IPHONEOS_DEPLOYMENT_TARGET = 16.4); the only disagreement was the generated manifests.The floor is now the app's own
IPHONEOS_DEPLOYMENT_TARGET, read from the injected.xcodeproj:targetUuid, else the application target named by--product-name, else every application target.min_ios_version_supported) and emitted in string form (.iOS("16.4")), because the.vNNenum form cannot express a minor version.setup-apple-spm.jsresolves the value once peradd/update/sync/scaffoldrun, logs it (iOS deployment target: 16.4 (from MyApp.xcodeproj)), and passes it to the generator, the sync script, and the scaffolder via a new--ios-deployment-targetflag. The flag value is sanitized at the generator boundary as well.SCAFFOLDER_VERSIONis bumped to 20 so existing scaffolds regenerate with the new floor.A floor set in an
.xcconfigthe configuration is based on is honored, including#includechains (target literal → target xcconfig → project literal → project xcconfig). A floor supplied through a build-setting variable ($(MY_FLOOR)) is not resolved and falls back to the minimum; the log line says so.spm addandspm updatealso refresh theplatforms:element of existing scaffolded manifests (those carrying the scaffolder marker, including the pre-v20.iOS(.v15)form, over the same expanded dependency set the scaffolder uses, transitive SwiftPM dependencies included) without creating new scaffolds or touching anything else in them.Known limitation, documented in
scripts/spm/__docs__/spm-scripts.md: the project file is not one of the auto-sync build phase's staleness inputs, so a deployment target changed afterspm addtakes effect on the nextspm update.The default floor moves from 15.0 to 15.1 for apps without a readable project setting; React Native already requires 15.1 for the app target, so this is not observable.
Changelog:
[IOS] [FIXED] - SwiftPM: generated manifests derive their iOS platform floor from the app's
IPHONEOS_DEPLOYMENT_TARGETinstead of hardcoding iOS 15, so dependencies with a higher minimum (e.g. Expo, 16.4) can be autolinkedTest Plan:
Unit tests were written first and seen failing, then made green:
New/updated coverage:
ios-deployment-target-test.js(pbxproj reading: target-level, project-level fallback, xcconfig chain with#includeand<group>anchoring, minimum across configurations, marker/--product-name/all-targets selection, invalid values, clamping, unreadable project),scaffold-package-swift-test.js(emitted floor, refresh of existing scaffolded manifests),generate-spm-autolinking-test.js(aggregate and synth templates,--ios-deployment-targetthroughmain()),scaffold-package-swift-test.js,sync-spm-autolinking-test.js(flag forwarding),setup-apple-spm-test.js(resolution and log line).ESLint (
--max-warnings 0), Prettier, and Flow are clean on the touched files.Not run here: an end-to-end Xcode build of an Expo app on this branch. The failing scenario and the fix were verified by the Expo team against 0.87.1 with the same manifest change patched in locally (build proceeds past SwiftPM resolution into compiling
Expo).🤖 Generated with Claude Code