From 6cfebe615bdd8ce8a735c90d1b1863d82a8fdc82 Mon Sep 17 00:00:00 2001 From: Govind Yadav Date: Wed, 16 Sep 2026 16:12:27 +0530 Subject: [PATCH 1/3] Add input files to build rules --- Docs/ProjectSpec.md | 3 +++ Sources/ProjectSpec/BuildRule.swift | 5 +++++ Sources/XcodeGenKit/PBXProjGenerator.swift | 1 + Tests/ProjectSpecTests/ProjectSpecTests.swift | 1 + Tests/ProjectSpecTests/SpecLoadingTests.swift | 3 ++- Tests/XcodeGenKitTests/ProjectGeneratorTests.swift | 3 +++ 6 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Docs/ProjectSpec.md b/Docs/ProjectSpec.md index 9fc2f9182..a4926566b 100644 --- a/Docs/ProjectSpec.md +++ b/Docs/ProjectSpec.md @@ -861,6 +861,7 @@ targets: - [ ] **script**: **String** - The script that will be run on each file. This or `compilerSpec` must be defined. - [ ] **compilerSpec**: **String**: A reference to a built in apple tool to run on each file. This is for advanced use and the the values for this must be checked. This or `script` must be defined. - [ ] **name**: **String** - The name of a build rule. Defaults to `Build Rule` +- [ ] **inputFiles**: **[String]** - The list of input files - [ ] **outputFiles**: **[String]** - The list of output files - [ ] **outputFilesCompilerFlags**: **[String]** - The list of compiler flags to apply to the output files - [ ] **runOncePerArchitecture**: **Bool** - a boolean that indicates if this rule should run once per architecture. This defaults to true @@ -876,6 +877,8 @@ targets: - filePattern: "*.txt" name: My Build Rule compilerSpec: com.apple.xcode.tools.swift.compiler + inputFiles: + - $(SRCROOT)/Input.txt outputFiles: - $(SRCROOT)/Generated.swift runOncePerArchitecture: false diff --git a/Sources/ProjectSpec/BuildRule.swift b/Sources/ProjectSpec/BuildRule.swift index f5fefc013..616150e3e 100644 --- a/Sources/ProjectSpec/BuildRule.swift +++ b/Sources/ProjectSpec/BuildRule.swift @@ -47,6 +47,7 @@ public struct BuildRule: Equatable { public var fileType: FileType public var action: Action + public var inputFiles: [String]? public var outputFiles: [String] public var outputFilesCompilerFlags: [String] public var name: String? @@ -56,6 +57,7 @@ public struct BuildRule: Equatable { fileType: FileType, action: Action, name: String? = nil, + inputFiles: [String]? = nil, outputFiles: [String] = [], outputFilesCompilerFlags: [String] = [], runOncePerArchitecture: Bool = runOncePerArchitectureDefault @@ -63,6 +65,7 @@ public struct BuildRule: Equatable { self.fileType = fileType self.action = action self.name = name + self.inputFiles = inputFiles self.outputFiles = outputFiles self.outputFilesCompilerFlags = outputFilesCompilerFlags self.runOncePerArchitecture = runOncePerArchitecture @@ -85,6 +88,7 @@ extension BuildRule: JSONObjectConvertible { action = .script(try jsonDictionary.json(atKeyPath: "script")) } + inputFiles = jsonDictionary.json(atKeyPath: "inputFiles") outputFiles = jsonDictionary.json(atKeyPath: "outputFiles") ?? [] outputFilesCompilerFlags = jsonDictionary.json(atKeyPath: "outputFilesCompilerFlags") ?? [] name = jsonDictionary.json(atKeyPath: "name") @@ -95,6 +99,7 @@ extension BuildRule: JSONObjectConvertible { extension BuildRule: JSONEncodable { public func toJSONValue() -> Any { var dict: [String: Any?] = [ + "inputFiles": inputFiles, "outputFiles": outputFiles, "outputFilesCompilerFlags": outputFilesCompilerFlags, "name": name, diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index 604ff473b..c22cefac9 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -1317,6 +1317,7 @@ public class PBXProjGenerator { filePatterns: buildRule.fileType.pattern, name: buildRule.name ?? "Build Rule", outputFiles: buildRule.outputFiles, + inputFiles: buildRule.inputFiles, outputFilesCompilerFlags: buildRule.outputFilesCompilerFlags, script: buildRule.action.script, runOncePerArchitecture: buildRule.runOncePerArchitecture diff --git a/Tests/ProjectSpecTests/ProjectSpecTests.swift b/Tests/ProjectSpecTests/ProjectSpecTests.swift index c308df96d..181fc8397 100644 --- a/Tests/ProjectSpecTests/ProjectSpecTests.swift +++ b/Tests/ProjectSpecTests/ProjectSpecTests.swift @@ -675,6 +675,7 @@ class ProjectSpecTests: XCTestCase { buildRules: [BuildRule(fileType: .pattern("*.xcassets"), action: .script("pre_process_swift.py"), name: "My Build Rule", + inputFiles: ["$(SRCROOT)/Assets.xcassets"], outputFiles: ["$(SRCROOT)/Generated.swift"], outputFilesCompilerFlags: ["foo"], runOncePerArchitecture: false), diff --git a/Tests/ProjectSpecTests/SpecLoadingTests.swift b/Tests/ProjectSpecTests/SpecLoadingTests.swift index 2efee3baa..e0d52c8bb 100644 --- a/Tests/ProjectSpecTests/SpecLoadingTests.swift +++ b/Tests/ProjectSpecTests/SpecLoadingTests.swift @@ -1481,6 +1481,7 @@ class SpecLoadingTests: XCTestCase { "name": "My Rule", "script": "my script", "filePattern": "*.swift", + "inputFiles": ["$(SRCROOT)/Source File.swift", "$(DERIVED_FILE_DIR)/Generated.swift"], "outputFiles": ["file1", "file2"], "outputFilesCompilerFlags": ["-a", "-b"], ], @@ -1492,7 +1493,7 @@ class SpecLoadingTests: XCTestCase { target["buildRules"] = buildRules let expectedBuildRules = [ - BuildRule(fileType: .pattern("*.swift"), action: .script("my script"), name: "My Rule", outputFiles: ["file1", "file2"], outputFilesCompilerFlags: ["-a", "-b"]), + BuildRule(fileType: .pattern("*.swift"), action: .script("my script"), name: "My Rule", inputFiles: ["$(SRCROOT)/Source File.swift", "$(DERIVED_FILE_DIR)/Generated.swift"], outputFiles: ["file1", "file2"], outputFilesCompilerFlags: ["-a", "-b"]), BuildRule(fileType: .type("sourcecode.swift"), action: .compilerSpec("apple.tool")), ] diff --git a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift index 600e4d61d..aeda9bf29 100644 --- a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift @@ -1515,6 +1515,7 @@ class ProjectGeneratorTests: XCTestCase { fileType: .type("sourcecode.swift"), action: .script("do thing"), name: "My Rule", + inputFiles: ["$(SRCROOT)/Source File.swift", "$(DERIVED_FILE_DIR)/Generated.swift"], outputFiles: ["file1.swift", "file2.swift"], outputFilesCompilerFlags: ["--zee", "--bee"] ), @@ -1532,6 +1533,7 @@ class ProjectGeneratorTests: XCTestCase { try expect(first.name) == "My Rule" try expect(first.isEditable) == true + try expect(first.inputFiles) == ["$(SRCROOT)/Source File.swift", "$(DERIVED_FILE_DIR)/Generated.swift"] try expect(first.outputFiles) == ["file1.swift", "file2.swift"] try expect(first.outputFilesCompilerFlags) == ["--zee", "--bee"] try expect(first.script) == "do thing" @@ -1544,6 +1546,7 @@ class ProjectGeneratorTests: XCTestCase { try expect(second.filePatterns) == "*.plist" try expect(second.compilerSpec) == "com.apple.build-tasks.copy-plist-file" try expect(second.script).beNil() + try expect(second.inputFiles).beNil() try expect(second.outputFiles) == [] try expect(second.outputFilesCompilerFlags) == [] } From 9985f07cf40034acb4f22575bc6fc1ebf883e6f4 Mon Sep 17 00:00:00 2001 From: Govind Yadav Date: Wed, 16 Sep 2026 16:14:09 +0530 Subject: [PATCH 2/3] Cover empty build rule inputs --- Tests/ProjectSpecTests/ProjectSpecTests.swift | 1 + Tests/ProjectSpecTests/SpecLoadingTests.swift | 6 ++++++ Tests/XcodeGenKitTests/ProjectGeneratorTests.swift | 12 ++++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Tests/ProjectSpecTests/ProjectSpecTests.swift b/Tests/ProjectSpecTests/ProjectSpecTests.swift index 181fc8397..8595625c4 100644 --- a/Tests/ProjectSpecTests/ProjectSpecTests.swift +++ b/Tests/ProjectSpecTests/ProjectSpecTests.swift @@ -682,6 +682,7 @@ class ProjectSpecTests: XCTestCase { BuildRule(fileType: .type("sourcecode.swift"), action: .compilerSpec("com.apple.xcode.tools.swift.compiler"), name: nil, + inputFiles: [], outputFiles: ["bar"], outputFilesCompilerFlags: ["foo"], runOncePerArchitecture: true)], diff --git a/Tests/ProjectSpecTests/SpecLoadingTests.swift b/Tests/ProjectSpecTests/SpecLoadingTests.swift index e0d52c8bb..fb86250af 100644 --- a/Tests/ProjectSpecTests/SpecLoadingTests.swift +++ b/Tests/ProjectSpecTests/SpecLoadingTests.swift @@ -1489,12 +1489,18 @@ class SpecLoadingTests: XCTestCase { "compilerSpec": "apple.tool", "fileType": "sourcecode.swift", ], + [ + "compilerSpec": "apple.other-tool", + "filePattern": "*.metal", + "inputFiles": [], + ], ] target["buildRules"] = buildRules let expectedBuildRules = [ BuildRule(fileType: .pattern("*.swift"), action: .script("my script"), name: "My Rule", inputFiles: ["$(SRCROOT)/Source File.swift", "$(DERIVED_FILE_DIR)/Generated.swift"], outputFiles: ["file1", "file2"], outputFilesCompilerFlags: ["-a", "-b"]), BuildRule(fileType: .type("sourcecode.swift"), action: .compilerSpec("apple.tool")), + BuildRule(fileType: .pattern("*.metal"), action: .compilerSpec("apple.other-tool"), inputFiles: []), ] let parsedTarget = try Target(name: "test", jsonDictionary: target) diff --git a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift index aeda9bf29..012bceef0 100644 --- a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift @@ -1523,13 +1523,19 @@ class ProjectGeneratorTests: XCTestCase { fileType: .pattern("*.plist"), action: .compilerSpec("com.apple.build-tasks.copy-plist-file") ), + BuildRule( + fileType: .pattern("*.metal"), + action: .compilerSpec("com.apple.compilers.metal"), + inputFiles: [] + ), ] let pbxProject = try scriptSpec.generatePbxProj() let buildRules = pbxProject.buildRules - try expect(buildRules.count) == 2 + try expect(buildRules.count) == 3 let first = buildRules.first { $0.name == "My Rule" }! - let second = buildRules.first { $0.name != "My Rule" }! + let second = buildRules.first { $0.filePatterns == "*.plist" }! + let third = buildRules.first { $0.filePatterns == "*.metal" }! try expect(first.name) == "My Rule" try expect(first.isEditable) == true @@ -1549,6 +1555,8 @@ class ProjectGeneratorTests: XCTestCase { try expect(second.inputFiles).beNil() try expect(second.outputFiles) == [] try expect(second.outputFilesCompilerFlags) == [] + + try expect(third.inputFiles) == [] } $0.it("generates dependency build file settings") { From 6e3d9121fef1fe4d876207652c9a9d712973e89e Mon Sep 17 00:00:00 2001 From: Govind Yadav Date: Wed, 16 Sep 2026 16:20:37 +0530 Subject: [PATCH 3/3] Add changelog entry for #1650 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45ff4ff89..3eeb3cf88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Next Version ### Added +- Added support for input files in build rules #1650 @GtechGovind - Added `buildArchitectures` to scheme build options and target schemes, to control Xcode's "Override Architectures" scheme setting #1642 @arhxam - Added FAQ documentation on how to add an Xcode capability, such as In-App Purchase #1644 @Hokila