mirror of
https://github.com/yonaskolb/XcodeGen.git
synced 2026-03-18 20:02:25 +00:00
Add support for conditionally linking dependencies based on platform (#1087)
* Add initial support for conditional platform dependencies * Add tests for conditional platforms * Update docs and changelog * Respond to PR feedback * Change name of field from 'conditionalPlatforms' to 'platforms' Co-authored-by: Yonas Kolb <yonaskolb@users.noreply.github.com>
This commit is contained in:
@@ -6,6 +6,10 @@
|
||||
|
||||
- Added support for DocC Catalogs [#1091](https://github.com/yonaskolb/XcodeGen/pull/1091) @brevansio
|
||||
- Added support for "driver-extension" and "system-extension" product types [#1092](https://github.com/yonaskolb/XcodeGen/issues/1092) @vgorloff
|
||||
- Add support for conditionally linking dependencies for specific platforms [#1087](https://github.com/yonaskolb/XcodeGen/pull/1087) @daltonclaybrook
|
||||
|
||||
### Changed
|
||||
- **Breaking**: Rename the `platform` field on `Dependency` to `platformFilter` [#1087](https://github.com/yonaskolb/XcodeGen/pull/1087) @daltonclaybrook
|
||||
|
||||
## 2.23.1
|
||||
|
||||
|
||||
+2
-1
@@ -430,7 +430,8 @@ A dependency can be one of a 6 types:
|
||||
- [ ] **codeSign**: **Bool** - Whether the `codeSignOnCopy` setting is applied when embedding framework. Defaults to true
|
||||
- [ ] **removeHeaders**: **Bool** - Whether the `removeHeadersOnCopy` setting is applied when embedding the framework. Defaults to true
|
||||
- [ ] **weak**: **Bool** - Whether the `Weak` setting is applied when linking the framework. Defaults to false
|
||||
- [ ] **platform**: **String** - Add dependency to selected platforms. Available platforms are: **iOS**, **macOS** and **all**. Defaults is **all**
|
||||
- [ ] **platformFilter**: **String** - This field is specific to Mac Catalyst. It corresponds to the "Platforms" dropdown in the Frameworks & Libraries section of Target settings in Xcode. Available options are: **iOS**, **macOS** and **all**. Defaults is **all**
|
||||
- [ ] **platforms**: **[[Platform](#platform)]** - List of platforms this dependency should apply to. Defaults to all applicable platforms.
|
||||
|
||||
**Implicit Framework options**:
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ public struct Dependency: Equatable {
|
||||
public static let removeHeadersDefault = true
|
||||
public static let implicitDefault = false
|
||||
public static let weakLinkDefault = false
|
||||
public static let platformDefault: Platform = .all
|
||||
public static let platformFilterDefault: PlatformFilter = .all
|
||||
|
||||
public var type: DependencyType
|
||||
public var reference: String
|
||||
@@ -15,7 +15,8 @@ public struct Dependency: Equatable {
|
||||
public var link: Bool?
|
||||
public var implicit: Bool = implicitDefault
|
||||
public var weakLink: Bool = weakLinkDefault
|
||||
public var platform: Platform = platformDefault
|
||||
public var platformFilter: PlatformFilter = platformFilterDefault
|
||||
public var platforms: Set<Platform>?
|
||||
|
||||
public init(
|
||||
type: DependencyType,
|
||||
@@ -25,7 +26,8 @@ public struct Dependency: Equatable {
|
||||
link: Bool? = nil,
|
||||
implicit: Bool = implicitDefault,
|
||||
weakLink: Bool = weakLinkDefault,
|
||||
platform: Platform = platformDefault
|
||||
platformFilter: PlatformFilter = platformFilterDefault,
|
||||
platforms: Set<Platform>? = nil
|
||||
) {
|
||||
self.type = type
|
||||
self.reference = reference
|
||||
@@ -34,10 +36,11 @@ public struct Dependency: Equatable {
|
||||
self.link = link
|
||||
self.implicit = implicit
|
||||
self.weakLink = weakLink
|
||||
self.platform = platform
|
||||
self.platformFilter = platformFilter
|
||||
self.platforms = platforms
|
||||
}
|
||||
|
||||
public enum Platform: String, Equatable {
|
||||
public enum PlatformFilter: String, Equatable {
|
||||
case all
|
||||
case iOS
|
||||
case macOS
|
||||
@@ -123,10 +126,14 @@ extension Dependency: JSONObjectConvertible {
|
||||
weakLink = bool
|
||||
}
|
||||
|
||||
if let platformString: String = jsonDictionary.json(atKeyPath: "platform"), let platform = Platform(rawValue: platformString) {
|
||||
self.platform = platform
|
||||
if let platformFilterString: String = jsonDictionary.json(atKeyPath: "platformFilter"), let platformFilter = PlatformFilter(rawValue: platformFilterString) {
|
||||
self.platformFilter = platformFilter
|
||||
} else {
|
||||
self.platform = .all
|
||||
self.platformFilter = .all
|
||||
}
|
||||
|
||||
if let platforms: [ProjectSpec.Platform] = jsonDictionary.json(atKeyPath: "platforms") {
|
||||
self.platforms = Set(platforms)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,6 +144,7 @@ extension Dependency: JSONEncodable {
|
||||
"embed": embed,
|
||||
"codeSign": codeSign,
|
||||
"link": link,
|
||||
"platforms": platforms?.map(\.rawValue).sorted()
|
||||
]
|
||||
|
||||
if removeHeaders != Dependency.removeHeadersDefault {
|
||||
|
||||
@@ -301,7 +301,12 @@ extension Target: NamedJSONDictionaryConvertible {
|
||||
if jsonDictionary["dependencies"] == nil {
|
||||
dependencies = []
|
||||
} else {
|
||||
dependencies = try jsonDictionary.json(atKeyPath: "dependencies", invalidItemBehaviour: .fail)
|
||||
let dependencies: [Dependency] = try jsonDictionary.json(atKeyPath: "dependencies", invalidItemBehaviour: .fail)
|
||||
self.dependencies = dependencies.filter { [platform] dependency -> Bool in
|
||||
// If unspecified, all platforms are supported
|
||||
guard let platforms = dependency.platforms else { return true }
|
||||
return platforms.contains(platform)
|
||||
}
|
||||
}
|
||||
|
||||
if jsonDictionary["info"] != nil {
|
||||
|
||||
@@ -751,7 +751,7 @@ public class PBXProjGenerator {
|
||||
for dependency in targetDependencies {
|
||||
|
||||
let embed = dependency.embed ?? target.shouldEmbedDependencies
|
||||
let platform = makePlatform(for: dependency.platform)
|
||||
let platform = makePlatformFilter(for: dependency.platformFilter)
|
||||
|
||||
switch dependency.type {
|
||||
case .target:
|
||||
@@ -1320,8 +1320,8 @@ public class PBXProjGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
private func makePlatform(for platform: Dependency.Platform) -> String? {
|
||||
switch platform {
|
||||
private func makePlatformFilter(for filter: Dependency.PlatformFilter) -> String? {
|
||||
switch filter {
|
||||
case .all:
|
||||
return nil
|
||||
case .macOS:
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
47D1F439B8E6D287B3F3E8D1 /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A58A16491CDDF968B0D56DE /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
47FC57B04A3AD83359F433EA /* StaticLibrary_ObjC.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5A2B916A11DCC2565241359F /* StaticLibrary_ObjC.h */; };
|
||||
49A4B8937BB5520B36EA33F0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 814D72C2B921F60B759C2D4B /* Main.storyboard */; };
|
||||
4C1504A05321046B3ED7A839 /* Framework2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB055761199DF36DB0C629A6 /* Framework2.framework */; };
|
||||
4CB673A7C0C11E04F8544BDB /* Contacts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FDB2B6A77D39CD5602F2125F /* Contacts.framework */; };
|
||||
4DA7140FF84DBF39961F3409 /* NetworkSystemExtension.systemextension in Embed System Extensions */ = {isa = PBXBuildFile; fileRef = 2049B6DD2AFE85F9DC9F3EB3 /* NetworkSystemExtension.systemextension */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
4F6481557E2BEF8D749C37E3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 187E665975BB5611AF0F27E1 /* main.m */; };
|
||||
@@ -125,6 +126,7 @@
|
||||
A1588BF3BFFE1DF7409CBA10 /* Framework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8A9274BE42A03DC5DA1FAD04 /* Framework.framework */; };
|
||||
A1AEAAB53EAEDA1C307871FA /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB178D03E75929F3F5B10C56 /* Result.framework */; };
|
||||
A59B3F08914812573AFF6C2D /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FD4A16C7B8FEB7F97F3CBE3F /* libz.dylib */; };
|
||||
A7438C77A05D83E7016CF044 /* Framework2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A0DC40025AB59B688E758829 /* Framework2.framework */; };
|
||||
A7D1A9942302569A9515696A /* Result.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D296BB7355994040E197A1EE /* Result.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
A90C4C147AD175DB9F7B5114 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03CD22B8CD2E91BB97CC534E /* main.swift */; };
|
||||
A949422315536EACDF8DD78A /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B785B1161553A7DD6DA4255 /* NetworkExtension.framework */; };
|
||||
@@ -223,6 +225,13 @@
|
||||
remoteGlobalIDString = 0867B0DACEF28C11442DE8F7;
|
||||
remoteInfo = App_iOS;
|
||||
};
|
||||
45907115465077029040BF29 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 8B9A14DC280CCE013CC86440;
|
||||
remoteInfo = Framework2_tvOS;
|
||||
};
|
||||
469D922BE967C6D52ED84552 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */;
|
||||
@@ -244,6 +253,13 @@
|
||||
remoteGlobalIDString = 13E8C5AB873CEE21E18E552F;
|
||||
remoteInfo = StaticLibrary_ObjC_iOS;
|
||||
};
|
||||
59BFAC272F73B46E97B74426 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 6ED01BC471A8C3642258E178;
|
||||
remoteInfo = Framework2_watchOS;
|
||||
};
|
||||
610412261F48A0A36C32FC5C /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */;
|
||||
@@ -800,6 +816,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4C1504A05321046B3ED7A839 /* Framework2.framework in Frameworks */,
|
||||
A1AEAAB53EAEDA1C307871FA /* Result.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -808,6 +825,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A7438C77A05D83E7016CF044 /* Framework2.framework in Frameworks */,
|
||||
9DF5931DAD58C35B830A0A75 /* Result.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1716,6 +1734,7 @@
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
D6C733BEB62EAA62CCC68556 /* PBXTargetDependency */,
|
||||
CE96B0951433713033A03DCD /* PBXTargetDependency */,
|
||||
);
|
||||
name = Framework_tvOS;
|
||||
@@ -1805,6 +1824,7 @@
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
0C99705018337CE91AA34CBA /* PBXTargetDependency */,
|
||||
35DF16CA4A1F88140CF69620 /* PBXTargetDependency */,
|
||||
);
|
||||
name = Framework_watchOS;
|
||||
@@ -2783,6 +2803,11 @@
|
||||
target = 1C26A6A0BC446191F311D470 /* iMessageExtension */;
|
||||
targetProxy = C8FD369800D87311EC532712 /* PBXContainerItemProxy */;
|
||||
};
|
||||
0C99705018337CE91AA34CBA /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 6ED01BC471A8C3642258E178 /* Framework2_watchOS */;
|
||||
targetProxy = 59BFAC272F73B46E97B74426 /* PBXContainerItemProxy */;
|
||||
};
|
||||
0D33D01C71E8002A07F02122 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 208179651927D1138D19B5AD /* App_watchOS */;
|
||||
@@ -2909,6 +2934,11 @@
|
||||
target = 0867B0DACEF28C11442DE8F7 /* App_iOS */;
|
||||
targetProxy = 3A81C6D6875469889D53A2C5 /* PBXContainerItemProxy */;
|
||||
};
|
||||
D6C733BEB62EAA62CCC68556 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 8B9A14DC280CCE013CC86440 /* Framework2_tvOS */;
|
||||
targetProxy = 45907115465077029040BF29 /* PBXContainerItemProxy */;
|
||||
};
|
||||
E84285243DE0BB361A708079 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = AE3F93DB94E7208F2F1D9A78 /* Framework_iOS */;
|
||||
|
||||
@@ -119,16 +119,16 @@ targets:
|
||||
PRODUCT_BUNDLE_IDENTIFIER: com.project.app
|
||||
dependencies:
|
||||
- target: Framework_iOS
|
||||
platform: all
|
||||
platformFilter: all
|
||||
- target: StaticLibrary_ObjC_iOS
|
||||
- carthage: Result
|
||||
platform: macOS
|
||||
platformFilter: macOS
|
||||
- carthage: SwiftyJSON
|
||||
linkType: static
|
||||
platform: iOS
|
||||
platformFilter: iOS
|
||||
- target: Framework2_iOS
|
||||
weak: true
|
||||
platform: iOS
|
||||
platformFilter: iOS
|
||||
- target: App_watchOS
|
||||
- target: iMessageApp
|
||||
- sdk: Contacts.framework
|
||||
@@ -284,6 +284,8 @@ targets:
|
||||
dependencies:
|
||||
- carthage: Result
|
||||
- target: StaticLibrary_ObjC_${platform}
|
||||
- target: Framework2_${platform}
|
||||
platforms: [tvOS, watchOS]
|
||||
|
||||
Framework2:
|
||||
type: framework
|
||||
|
||||
@@ -376,9 +376,9 @@ class SpecLoadingTests: XCTestCase {
|
||||
$0.it("parses target dependencies") {
|
||||
var targetDictionary = validTarget
|
||||
targetDictionary["dependencies"] = [
|
||||
["target": "name", "embed": false, "platform": "all"],
|
||||
["target": "project/name", "embed": false, "platform": "macOS"],
|
||||
["carthage": "name", "findFrameworks": true, "platform": "iOS"],
|
||||
["target": "name", "embed": false, "platformFilter": "all"],
|
||||
["target": "project/name", "embed": false, "platformFilter": "macOS"],
|
||||
["carthage": "name", "findFrameworks": true, "platformFilter": "iOS"],
|
||||
["carthage": "name", "findFrameworks": true, "linkType": "static"],
|
||||
["framework": "path", "weak": true],
|
||||
["sdk": "Contacts.framework"],
|
||||
@@ -386,16 +386,19 @@ class SpecLoadingTests: XCTestCase {
|
||||
"sdk": "Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework",
|
||||
"root": "DEVELOPER_DIR",
|
||||
],
|
||||
["target": "conditionalMatch", "platforms": ["iOS"]],
|
||||
["target": "conditionalMiss", "platforms": ["watchOS"]],
|
||||
]
|
||||
let target = try Target(name: "test", jsonDictionary: targetDictionary)
|
||||
try expect(target.dependencies.count) == 7
|
||||
try expect(target.dependencies[0]) == Dependency(type: .target, reference: "name", embed: false, platform: .all)
|
||||
try expect(target.dependencies[1]) == Dependency(type: .target, reference: "project/name", embed: false, platform: .macOS)
|
||||
try expect(target.dependencies[2]) == Dependency(type: .carthage(findFrameworks: true, linkType: .dynamic), reference: "name", platform: .iOS)
|
||||
try expect(target.dependencies.count) == 8
|
||||
try expect(target.dependencies[0]) == Dependency(type: .target, reference: "name", embed: false, platformFilter: .all)
|
||||
try expect(target.dependencies[1]) == Dependency(type: .target, reference: "project/name", embed: false, platformFilter: .macOS)
|
||||
try expect(target.dependencies[2]) == Dependency(type: .carthage(findFrameworks: true, linkType: .dynamic), reference: "name", platformFilter: .iOS)
|
||||
try expect(target.dependencies[3]) == Dependency(type: .carthage(findFrameworks: true, linkType: .static), reference: "name")
|
||||
try expect(target.dependencies[4]) == Dependency(type: .framework, reference: "path", weakLink: true)
|
||||
try expect(target.dependencies[5]) == Dependency(type: .sdk(root: nil), reference: "Contacts.framework")
|
||||
try expect(target.dependencies[6]) == Dependency(type: .sdk(root: "DEVELOPER_DIR"), reference: "Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework")
|
||||
try expect(target.dependencies[7]) == Dependency(type: .target, reference: "conditionalMatch", platforms: [.iOS])
|
||||
}
|
||||
|
||||
$0.it("parses info plist") {
|
||||
|
||||
@@ -354,9 +354,9 @@ class PBXProjGeneratorTests: XCTestCase {
|
||||
let target1 = Target(name: "TestAll", type: .application, platform: .iOS, sources: ["Sources"])
|
||||
let target2 = Target(name: "TestiOS", type: .application, platform: .iOS, sources: ["Sources"])
|
||||
let target3 = Target(name: "TestmacOS", type: .application, platform: .iOS, sources: ["Sources"])
|
||||
let dependency1 = Dependency(type: .target, reference: "TestAll", platform: .all)
|
||||
let dependency2 = Dependency(type: .target, reference: "TestiOS", platform: .iOS)
|
||||
let dependency3 = Dependency(type: .target, reference: "TestmacOS", platform: .macOS)
|
||||
let dependency1 = Dependency(type: .target, reference: "TestAll", platformFilter: .all)
|
||||
let dependency2 = Dependency(type: .target, reference: "TestiOS", platformFilter: .iOS)
|
||||
let dependency3 = Dependency(type: .target, reference: "TestmacOS", platformFilter: .macOS)
|
||||
let target = Target(name: "Test", type: .application, platform: .iOS, sources: ["Sources"], dependencies: [dependency1, dependency2, dependency3])
|
||||
let project = Project(basePath: directoryPath, name: "Test", targets: [target, target1, target2, target3])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user