Hive Hive
Sign in

Xcode 27: external dependency compiled for iOS 13.0 despite its iOS 15.0 minimum deployment target

GitHub issue · Open

Metadata
Source
tuist/tuist #11916
Updated
Jul 21, 2026
Domains
Generated projects
Details

What happened?

When generating and building our iOS project with Tuist 4.202.5 and Xcode 27 beta 3, Tuist produces a target configuration that compiles for iOS 13.0.

However, a transitive framework dependency, JOSESwift, has a minimum deployment target of iOS 15.0. This causes the Xcode build to fail because the consuming target is compiled for an older deployment target.

The dependency chain is:

Trainline App → ThreeDSecureProviders → checkout-3ds-sdk-ios → JOSESwift

This appears to be related to Xcode 27’s requirement that the minimum iOS deployment target is iOS 15.0, which is not being reflected in the generated project or dependency configuration.

How do we reproduce it?

Use this sample: DemoProject.zip

  1. run .reproduce.sh

Error log

compiling for iOS 13.0, but module 'JOSESwift' has a minimum deployment target of iOS 15.0:
/Users/<user>/Library/Developer/Xcode/DerivedData/Trainline-.../Build/Products/Debug-iphonesimulator/JOSESwift.framework/Modules/JOSESwift.swiftmodule/arm64-apple-ios-simulator.swiftmodule

macOS version

26.5.2

Tuist version

4.202.5

Xcode version

27 beta 3

Flights

Investigate, reproduce, or fix this item in an isolated repository. Each Flight preserves its outcome and agent session.

New Flights are paused Configure model inference, GitHub, and a sandbox provider to start another Flight. Existing results remain available below.
No Flights yet

Start a Flight and preserve its objective, outcome, and session here.

Comments
PT
PetterBraka-Trainline Jul 21, 2026

I’ve created a demo project for this. Please let me know if there is a workaround fix for this issue

DemoProject.zip

D
diegodossantos95 Jul 27, 2026

We hit the same class of failure moving to Xcode 27. Here’s the manifest-level workaround that worked for us and survives regeneration.

The important part: PackageSettings.baseSettings alone is not enough. That only sets the project-level value on the generated dependency projects — SwiftPM re-asserts each package’s own minimum at the target build configuration, which overrides it. You have to floor the affected targets explicitly as well:

// Tuist/Package.swift
#if TUIST
import ProjectDescription
// Xcode 27 rejects any IPHONEOS_DEPLOYMENT_TARGET below 15.0. Generated SPM dependency
// targets that declare (or default to) iOS 12/13 fail the build. `baseSettings` sets the
// project-level floor; SPM re-asserts each package's own minimum at the target level, so
// every affected target has to be floored there too.
private let targetsBelowiOS15: [String] = [
"SomeDependencyTarget",
"AnotherDependencyTarget",
// ...
]
let packageSettings = PackageSettings(
baseSettings: .settings(base: ["IPHONEOS_DEPLOYMENT_TARGET": "15.0"]),
targetSettings: Dictionary(
uniqueKeysWithValues: targetsBelowiOS15.map { name in
(name, ["IPHONEOS_DEPLOYMENT_TARGET": "15.0"] as SettingsDictionary)
}
)
)
#endif

To collect the target names, run tuist install && tuist generate, then grep the generated dependency projects:

grep -rho 'IPHONEOS_DEPLOYMENT_TARGET = [0-9.]*' \
Tuist/.build/tuist-derived/*/*.xcodeproj/project.pbxproj | sort -u

Anything below 15 needs to go in the list. This got our project building green under Xcode 27, and because it lives in the manifest it holds across tuist generate — unlike a post-generation pbxproj patch, which also defeats binary caching.

The downside is that targetSettings is keyed by exact target name with no globbing, so the list is hand-maintained: adding a dependency that declares a sub-15 minimum breaks the build again. At least it fails loudly with a clear message.

PT
PetterBraka-Trainline Jul 28, 2026

Hi @diegodossantos95, unfortunately, that workaround doesn’t work for my project or the demo project. I suspect the issue is around using a static framework 🤔 When I collect the list of targets, it already says each target uses 15.0, so adding the targetSettings doesn’t update it.

find Tuist/.build/tuist-derived -name project.pbxproj -path '*.xcodeproj/*' -print0 \
| xargs -0 grep -H 'IPHONEOS_DEPLOYMENT_TARGET = [0-9.]*' \
| sed -E 's|.*/([^/]+)\.xcodeproj/project\.pbxproj:[[:space:]]*IPHONEOS_DEPLOYMENT_TARGET = ([0-9.]+);|\1: \2|' \
| sort -u
Adyen: 15.0
AdyenNetworking: 15.0
JOSESwift: 15.0
swiftui-introspect: 15.0
P
pepicrft Jul 28, 2026

I’m taking a look at this one :)

2
23122K Jul 28, 2026

It seems like iOS version (where MinimumDeploymentTarget < 15.0) specified in Package.swift is no longer respected when building with Xcode 27 (iPhoneSimulator27 SDK) as it produces -target arm64-apple-ios15.0-simulator

P
pepicrft Jul 29, 2026

I was able to reproduce this with Xcode 27.0 (build 27A5228h) and Tuist 4.200.5 using the demo project.

Root cause

The Checkout3DS.xcframework has MinimumOSVersion: 13.0 in its Info.plist, and its .swiftinterface embeds -target arm64-apple-ios13.0-simulator in the swift-module-flags. The swiftinterface imports JOSESwift (line 10 of the interface file).

When Xcode 27 compiles the swiftinterface via SwiftExplicitDependencyCompileModuleFromInterface, it uses the binary framework’s own deployment target (iOS 13.0) rather than the consuming target’s deployment target. JOSESwift is correctly compiled by Tuist with an iOS 15.0 deployment target (the oldestVersions(for:) function in PackageInfoMapper returns iOS 15.0 for Swift 6.4). Since 13.0 < 15.0, the compilation fails.

The Checkout3DS binary was built with -enable-library-evolution, so its original deployment target should not limit consumers to iOS 13.0. The framework is deployment-target agnostic at the binary level.

What changed

Xcode 27 enforces deployment target compatibility during explicit module compilation of binary framework swiftinterfaces more strictly than previous Xcode versions, which did not flag this mismatch.

Reproduction output

[x] Checkout3DS.framework/Modules/Checkout3DS.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface:11:8:
compiling for iOS 13.0, but module 'JOSESwift' has a minimum deployment target of iOS 15.0

Failing build command: SwiftExplicitDependencyCompileModuleFromInterface arm64

Suggestion

The ideal fix is on Apple’s side: SwiftExplicitDependencyCompileModuleFromInterface should use the consuming target’s deployment target, not the binary framework’s original build target. Since the framework uses library evolution, the embedded -target arm64-apple-ios13.0-simulator is informational and should not constrain downstream consumers.

As a Tuist-side workaround, we could bump the MinimumOSVersion in binary xcframework Info.plist files during tuist install or tuist generate to at least the minimum deployment target supported by the active Xcode version (iOS 15.0 for Xcode 27). This is a project-side workaround though, and the underlying Xcode behavior should be addressed.