Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
### Changed
- Targets in the generated project now follow the declaration order from the source spec (Xcode sidebar, `xcodebuild -list` output). Previously they were always sorted alphabetically. Applies to both YAML and JSON specs. Declaration order is now also preserved for targets whose `platform`/`name` come from a target template and for targets whose key is a `${VARIABLE}`. #1619 @mirkokg

### Fixed
- Apply per-platform deployment targets to targets using `supportedDestinations` #1641 @arhxam

### Internal
- Update to XcodeProj 9.14.0 #1629 @philprime

Expand Down
19 changes: 17 additions & 2 deletions Sources/ProjectSpec/Target.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public struct Target: ProjectTarget {
public var scheme: TargetScheme?
public var legacy: LegacyTarget?
public var deploymentTarget: Version?
public var deploymentTargets: DeploymentTarget?
public var attributes: [String: Any]
public var productName: String
public var onlyCopyFilesOnInstall: Bool
Expand Down Expand Up @@ -82,6 +83,7 @@ public struct Target: ProjectTarget {
supportedDestinations: [SupportedDestination]? = nil,
productName: String? = nil,
deploymentTarget: Version? = nil,
deploymentTargets: DeploymentTarget? = nil,
settings: Settings = .empty,
configFiles: [String: String] = [:],
sources: [TargetSource] = [],
Expand All @@ -107,6 +109,7 @@ public struct Target: ProjectTarget {
self.platform = platform
self.supportedDestinations = supportedDestinations
self.deploymentTarget = deploymentTarget
self.deploymentTargets = deploymentTargets
self.productName = productName ?? name
self.settings = settings
self.configFiles = configFiles
Expand Down Expand Up @@ -227,6 +230,7 @@ extension Target: Equatable {
lhs.type == rhs.type &&
lhs.platform == rhs.platform &&
lhs.deploymentTarget == rhs.deploymentTarget &&
lhs.deploymentTargets == rhs.deploymentTargets &&
lhs.transitivelyLinkDependencies == rhs.transitivelyLinkDependencies &&
lhs.requiresObjCLinking == rhs.requiresObjCLinking &&
lhs.directlyEmbedCarthageDependencies == rhs.directlyEmbedCarthageDependencies &&
Expand Down Expand Up @@ -314,12 +318,18 @@ extension Target: NamedJSONDictionaryConvertible {
throw SpecParsingError.unknownTargetPlatform(platformString)
}

if let string: String = jsonDictionary.json(atKeyPath: "deploymentTarget") {
if let dictionary = jsonDictionary["deploymentTarget"] as? JSONDictionary {
deploymentTarget = nil
deploymentTargets = try DeploymentTarget(jsonDictionary: dictionary)
} else if let string: String = jsonDictionary.json(atKeyPath: "deploymentTarget") {
deploymentTarget = try Version.parse(string)
deploymentTargets = nil
} else if let double: Double = jsonDictionary.json(atKeyPath: "deploymentTarget") {
deploymentTarget = try Version.parse(String(double))
deploymentTargets = nil
} else {
deploymentTarget = nil
deploymentTargets = nil
}

settings = try BuildSettingsParser(jsonDictionary: jsonDictionary).parse()
Expand Down Expand Up @@ -395,7 +405,6 @@ extension Target: JSONEncodable {
"buildToolPlugins": buildToolPlugins.map { $0.toJSONValue() },
"postbuildScripts": postBuildScripts.map { $0.toJSONValue() },
"buildRules": buildRules.map { $0.toJSONValue() },
"deploymentTarget": deploymentTarget?.deploymentTarget,
"info": info?.toJSONValue(),
"entitlements": entitlements?.toJSONValue(),
"transitivelyLinkDependencies": transitivelyLinkDependencies,
Expand All @@ -405,6 +414,12 @@ extension Target: JSONEncodable {
"legacy": legacy?.toJSONValue(),
]

if let deploymentTargets {
dict["deploymentTarget"] = deploymentTargets.toJSONValue()
} else {
dict["deploymentTarget"] = deploymentTarget?.deploymentTarget
}

if productName != name {
dict["productName"] = productName
}
Expand Down
15 changes: 7 additions & 8 deletions Sources/XcodeGenKit/SettingsBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,15 @@ extension Project {
}

// apply custom platform version
if let version = target.deploymentTarget {
if !specSupportedDestinations.isEmpty {
for supportedDestination in specSupportedDestinations {
if let platform = Platform(rawValue: supportedDestination.rawValue) {
buildSettings[platform.deploymentTargetSetting] = .string(version.deploymentTarget)
}
if !specSupportedDestinations.isEmpty {
for supportedDestination in specSupportedDestinations {
if let platform = Platform(rawValue: supportedDestination.rawValue),
let version = target.deploymentTargets?.version(for: platform) ?? target.deploymentTarget {
buildSettings[platform.deploymentTargetSetting] = .string(version.deploymentTarget)
}
} else {
buildSettings[target.platform.deploymentTargetSetting] = .string(version.deploymentTarget)
}
} else if let version = target.deploymentTargets?.version(for: target.platform) ?? target.deploymentTarget {
buildSettings[target.platform.deploymentTargetSetting] = .string(version.deploymentTarget)
}

// Prevent setting presets from overrwriting settings in target xcconfig files
Expand Down
20 changes: 20 additions & 0 deletions Tests/ProjectSpecTests/SpecLoadingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,26 @@ class SpecLoadingTests: XCTestCase {
try expect(project.targets) == [target]
try expect(project.targets.first?.supportedDestinations) == [.macCatalyst, .iOS]
}

$0.it("encodes per-platform deployment targets") {
let deploymentTargets = DeploymentTarget(
iOS: Version(major: 18, minor: 0, patch: 0),
macOS: Version(major: 15, minor: 0, patch: 0)
)
let target = Target(
name: "Framework",
type: .framework,
platform: .auto,
supportedDestinations: [.iOS, .macOS],
deploymentTargets: deploymentTargets
)

let targetJSON = target.toJSONValue() as! [String: Any?]
let deploymentTargetJSON = targetJSON["deploymentTarget"] as! [String: String?]

try expect(deploymentTargetJSON["iOS"]!) == "18.0.0"
try expect(deploymentTargetJSON["macOS"]!) == "15.0.0"
}

$0.it("invalid target platform because platform is an array and supported destinations is in use") {
let expectedError = SpecParsingError.invalidTargetPlatformAsArray
Expand Down
20 changes: 20 additions & 0 deletions Tests/XcodeGenKitTests/ProjectGeneratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,26 @@ class ProjectGeneratorTests: XCTestCase {
try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"]?.stringValue) == "AppIcon"
try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"]?.stringValue) == "iPhone Developer"
}

$0.it("supportedDestinations applies per-platform deployment targets") {
let target = try Target(name: "Target", jsonDictionary: [
"type": "application",
"supportedDestinations": ["iOS", "macOS"],
"deploymentTarget": [
"iOS": "18.0",
"macOS": "15.0",
"tvOS": "17.0",
],
])
let project = Project(name: "", targets: [target])

let pbxProject = try project.generatePbxProj()
let targetConfig = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first)

try expect(targetConfig.buildSettings["IPHONEOS_DEPLOYMENT_TARGET"]?.stringValue) == "18.0"
try expect(targetConfig.buildSettings["MACOSX_DEPLOYMENT_TARGET"]?.stringValue) == "15.0"
try expect(targetConfig.buildSettings["TVOS_DEPLOYMENT_TARGET"]).beNil()
}

$0.it("supportedDestinations merges settings - iOS, visionOS") {
let target = Target(name: "Target", type: .application, platform: .auto, supportedDestinations: [.visionOS, .iOS])
Expand Down