diff --git a/Sources/ProjectSpec/Target.swift b/Sources/ProjectSpec/Target.swift index 99a7bde8..bf49c10a 100644 --- a/Sources/ProjectSpec/Target.swift +++ b/Sources/ProjectSpec/Target.swift @@ -111,7 +111,7 @@ extension Target { targets.append(json) } } - + return try targets.map { try Target(jsonDictionary: $0) } } } @@ -196,9 +196,11 @@ extension Target: JSONObjectConvertible { public struct Dependency: Equatable { - public let type: DependencyType - public let reference: String - public let embed: Bool? + public var type: DependencyType + public var reference: String + public var embed: Bool? + public var codeSign: Bool = true + public var removeHeaders: Bool = true public init(type: DependencyType, reference: String, embed: Bool? = nil) { self.type = type @@ -214,15 +216,27 @@ public struct Dependency: Equatable { public static func ==(lhs: Dependency, rhs: Dependency) -> Bool { return lhs.reference == rhs.reference && - lhs.type == rhs.type && - lhs.embed == rhs.embed + lhs.type == rhs.type && + lhs.codeSign == rhs.codeSign && + lhs.removeHeaders == rhs.removeHeaders && + lhs.embed == rhs.embed + } + + public var buildSettings: [String: Any] { + var attributes: [String] = [] + if codeSign { + attributes.append("CodeSignOnCopy") + } + if removeHeaders { + attributes.append("RemoveHeadersOnCopy") + } + return ["ATTRIBUTES": attributes] } } extension Dependency: JSONObjectConvertible { public init(jsonDictionary: JSONDictionary) throws { - embed = jsonDictionary.json(atKeyPath: "embed") if let target: String = jsonDictionary.json(atKeyPath: "target") { type = .target reference = target @@ -235,5 +249,14 @@ extension Dependency: JSONObjectConvertible { } else { throw ProjectSpecError.invalidDependency(jsonDictionary) } + + embed = jsonDictionary.json(atKeyPath: "embed") + + if let bool: Bool = jsonDictionary.json(atKeyPath: "codeSign") { + codeSign = bool + } + if let bool: Bool = jsonDictionary.json(atKeyPath: "removeHeaders") { + removeHeaders = bool + } } } diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index b3feac28..203d3cf7 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -203,6 +203,8 @@ public class PBXProjGenerator { var extensions: [String] = [] for dependancy in target.dependencies { + + let embed = dependancy.embed ?? (target.type.isApp ? true : false) switch dependancy.type { case .target: let dependencyTargetName = dependancy.reference @@ -220,36 +222,42 @@ public class PBXProjGenerator { // link targetFrameworkBuildFiles.append(dependencyBuildFile) - if target.type.isApp { + if embed { + let embedSettings = dependancy.buildSettings + let embedFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, dependencyFileReference + target.name), fileRef: dependencyFileReference, settings: embedSettings) + addObject(embedFile) + if dependencyTarget.type.isExtension { - // embed app extensions - let embedSettings: [String: Any] = ["ATTRIBUTES": ["RemoveHeadersOnCopy"]] - let embedFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, dependencyFileReference + target.name), fileRef: dependencyFileReference, settings: embedSettings) - addObject(embedFile) + // embed app extension extensions.append(embedFile.reference) } else { - // embed frameworks - let embedSettings: [String: Any] = ["ATTRIBUTES": ["CodeSignOnCopy", "RemoveHeadersOnCopy"]] - let embedFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, dependencyFileReference + target.name), fileRef: dependencyFileReference, settings: embedSettings) - addObject(embedFile) copyFiles.append(embedFile.reference) } } case .framework: + let fileReference = getFileReference(path: Path(dependancy.reference), inPath: basePath) + let buildFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, fileReference + target.name), fileRef: fileReference) addObject(buildFile) + targetFrameworkBuildFiles.append(buildFile.reference) if !frameworkFiles.contains(fileReference) { frameworkFiles.append(fileReference) } + + if embed { + let embedFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, fileReference + target.name), fileRef: fileReference, settings: dependancy.buildSettings) + addObject(embedFile) + copyFiles.append(buildFile.reference) + } case .carthage: if carthageFrameworksByPlatform[target.platform.rawValue] == nil { carthageFrameworksByPlatform[target.platform.rawValue] = [] } var platformPath = Path(getCarthageBuildPath(platform: target.platform)) - var frameworkPath = platformPath + carthage + var frameworkPath = platformPath + dependancy.reference if frameworkPath.extension == nil { frameworkPath = Path(frameworkPath.string + ".framework") } @@ -381,10 +389,10 @@ public class PBXProjGenerator { func getCarthageFrameworks(target: Target) -> [String] { var frameworks: [String] = [] for dependency in target.dependencies { - switch dependency { - case let .carthage(framework): frameworks.append(framework) - case let .target(targetName): - if let target = spec.targets.first(where: { $0.name == targetName }) { + switch dependency.type { + case .carthage: frameworks.append(dependency.reference) + case .target: + if let target = spec.getTarget(dependency.reference) { frameworks += getCarthageFrameworks(target: target) } default: break @@ -455,7 +463,7 @@ public class PBXProjGenerator { allFilePaths.append(path) } } - + let groupPath: String = depth == 0 ? path.byRemovingBase(path: basePath).string : path.lastComponent let group: PBXGroup if let cachedGroup = groupsByPath[path] { diff --git a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift index eae370f8..0ae3357c 100644 --- a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift @@ -19,7 +19,7 @@ func projectGeneratorTests() { let application = Target(name: "MyApp", type: .application, platform: .iOS, settings: Settings(buildSettings: ["SETTING_1": "VALUE"]), - dependencies: [.target("MyFramework")]) + dependencies: [Dependency(type: .target, reference: "MyFramework")]) let framework = Target(name: "MyFramework", type: .framework, platform: .iOS, settings: Settings(buildSettings: ["SETTING_2": "VALUE"])) diff --git a/Tests/XcodeGenKitTests/SpecLoadingTests.swift b/Tests/XcodeGenKitTests/SpecLoadingTests.swift index eb225ec4..f82c39ee 100644 --- a/Tests/XcodeGenKitTests/SpecLoadingTests.swift +++ b/Tests/XcodeGenKitTests/SpecLoadingTests.swift @@ -53,15 +53,15 @@ func specLoadingTests() { $0.it("parses target dependencies") { var targetDictionary = validTarget targetDictionary["dependencies"] = [ - ["target": "name"], + ["target": "name", "embed": false], ["carthage": "name"], ["framework": "path"], ] let target = try Target(jsonDictionary: targetDictionary) try expect(target.dependencies.count) == 3 - try expect(target.dependencies[0]) == .target("name") - try expect(target.dependencies[1]) == .carthage("name") - try expect(target.dependencies[2]) == .framework("path") + try expect(target.dependencies[0]) == Dependency(type: .target, reference: "name", embed: false) + try expect(target.dependencies[1]) == Dependency(type: .carthage, reference: "name") + try expect(target.dependencies[2]) == Dependency(type: .framework, reference: "path") } $0.it("parsed cross platform targets") { diff --git a/docs/ProjectSpec.md b/docs/ProjectSpec.md index b03caee6..dc0dbdec 100644 --- a/docs/ProjectSpec.md +++ b/docs/ProjectSpec.md @@ -171,15 +171,23 @@ targets: ``` ### Dependency -A dependency can be one of a few types: +A dependency can be one of a 3 types: - `target: name` - links to another target - `framework: path` - links to a framework - `carthage: name` - helper for linking to a carthage framework -**Carthage notes** +**Embed options**: -Carthage frameworks expected to be in `CARTHAGE_BUILD_PATH/PLATFORM/FRAMEWORK.framework` where: +These only applied to `target` and `framework` dependencies. + +- ⚪️ **embed**: `Bool` - Whether to embed the dependency. Defaults to true for application target and false for non application targets. +- ⚪️ **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 + +**Carthage Dependency** + +Carthage frameworks are expected to be in `CARTHAGE_BUILD_PATH/PLATFORM/FRAMEWORK.framework` where: - `CARTHAGE_BUILD_PATH` = `options.carthageBuildPath` or `Carthage/Build` by default - `PLATFORM` = the target's platform