diff --git a/Docs/ProjectSpec.md b/Docs/ProjectSpec.md index ebb3a3f2..8196db5c 100644 --- a/Docs/ProjectSpec.md +++ b/Docs/ProjectSpec.md @@ -275,6 +275,9 @@ A source can be provided via a string (the path) or an object of the form: - `sharedSupport` - `plugins` - [ ] **subpath**: **String** - The path inside of the destination to copy the files. + - [ ] **phaseOrder**: **String** - When the Copy Files phase should execute in relation to other phases. This can be one of the following values: + - `preCompile`: Run before the Compile Sources phase + - `postCompile`: Run after the Compile Sources phase - `none` - Will not be added to any build phases - [ ] **type**: **String**: This can be one of the following values - `file`: a file reference with a parent group will be created (Default for files or directories with extensions) diff --git a/Sources/ProjectSpec/TargetSource.swift b/Sources/ProjectSpec/TargetSource.swift index 08bc65cd..74aed837 100644 --- a/Sources/ProjectSpec/TargetSource.swift +++ b/Sources/ProjectSpec/TargetSource.swift @@ -42,7 +42,8 @@ public struct TargetSource: Equatable { public struct CopyFilesSettings: Equatable, Hashable { public static let xpcServices = CopyFilesSettings( destination: .productsDirectory, - subpath: "$(CONTENTS_FOLDER_PATH)/XPCServices" + subpath: "$(CONTENTS_FOLDER_PATH)/XPCServices", + phaseOrder: .postCompile ) public enum Destination: String { @@ -72,13 +73,26 @@ public struct TargetSource: Equatable { } } } + + public enum PhaseOrder: String { + /// Run before the Compile Sources phase + case preCompile + /// Run after the Compile Sources and post-compile Run Script phases + case postCompile + } public var destination: Destination public var subpath: String + public var phaseOrder: PhaseOrder - public init(destination: Destination, subpath: String) { + public init( + destination: Destination, + subpath: String, + phaseOrder: PhaseOrder + ) { self.destination = destination self.subpath = subpath + self.phaseOrder = phaseOrder } } @@ -119,6 +133,7 @@ public struct TargetSource: Equatable { self.type = type self.optional = optional self.buildPhase = buildPhase + self.headerVisibility = headerVisibility } } @@ -189,5 +204,6 @@ extension TargetSource.BuildPhase.CopyFilesSettings: JSONObjectConvertible { public init(jsonDictionary: JSONDictionary) throws { destination = try jsonDictionary.json(atKeyPath: "destination") subpath = jsonDictionary.json(atKeyPath: "subpath") ?? "" + phaseOrder = jsonDictionary.json(atKeyPath: "phaseOrder") ?? .postCompile } } diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index 9dac781d..c7b0d40c 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -646,7 +646,13 @@ public class PBXProjGenerator { return sourceFilesByCopyFiles.mapValues { getBuildFilesForSourceFiles($0) } } + copyFilesBuildPhasesFiles.merge(getBuildFilesForCopyFilesPhases()) { $0 + $1 } + buildPhases += try target.prebuildScripts.map { try generateBuildScript(targetName: target.name, buildScript: $0) } + + buildPhases += copyFilesBuildPhasesFiles + .filter { $0.key.phaseOrder == .preCompile } + .map { generateCopyFiles(targetName: target.name, copyFiles: $0, buildPhaseFiles: $1) } let headersBuildPhaseFiles = getBuildFilesForPhase(.headers) if !headersBuildPhaseFiles.isEmpty && (target.type == .framework || target.type == .dynamicLibrary) { @@ -689,8 +695,9 @@ public class PBXProjGenerator { buildPhases.append(script.reference) } - copyFilesBuildPhasesFiles.merge(getBuildFilesForCopyFilesPhases()) { $0 + $1 } - buildPhases += copyFilesBuildPhasesFiles.map { generateCopyFiles(targetName: target.name, copyFiles: $0, buildPhaseFiles: $1) } + buildPhases += copyFilesBuildPhasesFiles + .filter { $0.key.phaseOrder == .postCompile } + .map { generateCopyFiles(targetName: target.name, copyFiles: $0, buildPhaseFiles: $1) } if !targetFrameworkBuildFiles.isEmpty { diff --git a/Sources/XcodeGenKit/SourceGenerator.swift b/Sources/XcodeGenKit/SourceGenerator.swift index a56614e3..12709f61 100644 --- a/Sources/XcodeGenKit/SourceGenerator.swift +++ b/Sources/XcodeGenKit/SourceGenerator.swift @@ -73,7 +73,8 @@ class SourceGenerator { if headerVisibility == .public { chosenBuildPhase = .copyFiles(TargetSource.BuildPhase.CopyFilesSettings( destination: .productsDirectory, - subpath: "include/$(PRODUCT_NAME)" + subpath: "include/$(PRODUCT_NAME)", + phaseOrder: .preCompile )) } else { chosenBuildPhase = nil @@ -194,7 +195,8 @@ class SourceGenerator { guard targetType == .staticLibrary else { return nil } return .copyFiles(TargetSource.BuildPhase.CopyFilesSettings( destination: .productsDirectory, - subpath: "include/$(PRODUCT_NAME)" + subpath: "include/$(PRODUCT_NAME)", + phaseOrder: .preCompile )) case "framework": return .frameworks case "xpc": return .copyFiles(.xpcServices) diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj b/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj index badfd0f1..7804b3e4 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj @@ -913,8 +913,8 @@ isa = PBXNativeTarget; buildConfigurationList = CL_399755008402 /* Build configuration list for PBXNativeTarget "StaticLibrary_ObjC" */; buildPhases = ( - SBP_39975500840 /* Sources */, CFBP_3265670993 /* CopyFiles */, + SBP_39975500840 /* Sources */, ); buildRules = ( );