Skip to content
Merged
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 2 additions & 1 deletion Docs/ProjectSpec.md
Original file line number Diff line number Diff line change
Expand Up @@ -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**:

Expand Down
24 changes: 16 additions & 8 deletions Sources/ProjectSpec/Dependency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
}
}
}
Expand All @@ -137,6 +144,7 @@ extension Dependency: JSONEncodable {
"embed": embed,
"codeSign": codeSign,
"link": link,
"platforms": platforms?.map(\.rawValue).sorted()
]

if removeHeaders != Dependency.removeHeadersDefault {
Expand Down
7 changes: 6 additions & 1 deletion Sources/ProjectSpec/Target.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 3 additions & 3 deletions Sources/XcodeGenKit/PBXProjGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
30 changes: 30 additions & 0 deletions Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -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 */; };
Expand Down Expand Up @@ -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 */;
Expand All @@ -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 */;
Expand Down Expand Up @@ -800,6 +816,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4C1504A05321046B3ED7A839 /* Framework2.framework in Frameworks */,
A1AEAAB53EAEDA1C307871FA /* Result.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -808,6 +825,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A7438C77A05D83E7016CF044 /* Framework2.framework in Frameworks */,
9DF5931DAD58C35B830A0A75 /* Result.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -1716,6 +1734,7 @@
buildRules = (
);
dependencies = (
D6C733BEB62EAA62CCC68556 /* PBXTargetDependency */,
CE96B0951433713033A03DCD /* PBXTargetDependency */,
);
name = Framework_tvOS;
Expand Down Expand Up @@ -1805,6 +1824,7 @@
buildRules = (
);
dependencies = (
0C99705018337CE91AA34CBA /* PBXTargetDependency */,
35DF16CA4A1F88140CF69620 /* PBXTargetDependency */,
);
name = Framework_watchOS;
Expand Down Expand Up @@ -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 */;
Expand Down Expand Up @@ -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 */;
Expand Down
10 changes: 6 additions & 4 deletions Tests/Fixtures/TestProject/project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -284,6 +284,8 @@ targets:
dependencies:
- carthage: Result
- target: StaticLibrary_ObjC_${platform}
- target: Framework2_${platform}
platforms: [tvOS, watchOS]

Framework2:
type: framework
Expand Down
17 changes: 10 additions & 7 deletions Tests/ProjectSpecTests/SpecLoadingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -376,26 +376,29 @@ 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"],
[
"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") {
Expand Down
6 changes: 3 additions & 3 deletions Tests/XcodeGenKitTests/PBXProjGeneratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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])

Expand Down