Skip to content

Commit 615bbb1

Browse files
committed
Build: migrate to file lists for driver invocations
When invoking the driver use file lists rather than passing all the sources on the command line. This is particularly import for Windows where the command line limit is 32k. With deep dependency sets and large projects, it is possible to overrun this limit and fail to invoke the command. The driver itself will invoke the frontend using response files if the invocation will overflow the command line limit. The test expectations need to be altered as we will use the build directories to store the file list which is the temps path.
1 parent 706d1f1 commit 615bbb1

File tree

5 files changed

+27
-20
lines changed

5 files changed

+27
-20
lines changed

Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,8 @@ public final class SwiftTargetBuildDescription {
558558
}
559559

560560
result.append("-c")
561-
result.append(contentsOf: self.sources.map(\.pathString))
561+
// FIXME: Eliminate side effect.
562+
try result.append("@\(self.writeSourcesFileList(self.sources, "all").pathString)")
562563

563564
result.append("-I")
564565
result.append(self.buildParameters.buildPath.pathString)
@@ -590,9 +591,8 @@ public final class SwiftTargetBuildDescription {
590591

591592
// FIXME: Handle WMO
592593

593-
for source in self.target.sources.paths {
594-
result.append(source.pathString)
595-
}
594+
// FIXME: Eliminate side effect.
595+
try result.append("@\(self.writeSourcesFileList(self.target.sources.paths).pathString)")
596596

597597
result.append("-I")
598598
result.append(self.buildParameters.buildPath.pathString)
@@ -643,9 +643,8 @@ public final class SwiftTargetBuildDescription {
643643
// FIXME: Handle WMO
644644

645645
result.append("-c")
646-
for source in self.target.sources.paths {
647-
result.append(source.pathString)
648-
}
646+
// FIXME: Eliminate side effect.
647+
try result.append("@\(self.writeSourcesFileList(self.target.sources.paths).pathString)")
649648

650649
result.append("-I")
651650
result.append(self.buildParameters.buildPath.pathString)
@@ -689,6 +688,14 @@ public final class SwiftTargetBuildDescription {
689688
self.buildParameters.triple.isDarwin() && self.target.type == .library
690689
}
691690

691+
func writeSourcesFileList(_ files: [AbsolutePath], _ variant: String = "") throws -> AbsolutePath {
692+
let suffix = variant.isEmpty ? "" : "-\(variant)"
693+
let path = self.tempsPath.appending(component: "\(self.target.name)\(suffix).filelist")
694+
let contents = files.map { $0.pathString.spm_shellEscaped() }.joined(separator: "\n")
695+
try self.fileSystem.writeFileContents(path, string: contents)
696+
return path
697+
}
698+
692699
func writeOutputFileMap() throws -> AbsolutePath {
693700
let path = self.tempsPath.appending("output-file-map.json")
694701
let masterDepsPath = self.tempsPath.appending("master.swiftdeps")

Sources/Build/LLBuildManifestBuilder.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ extension LLBuildManifestBuilder {
626626
tempsPath: target.tempsPath,
627627
objects: try target.objects,
628628
otherArguments: try target.compileArguments(),
629-
sources: target.sources,
629+
fileListPath: try target.writeSourcesFileList(target.sources), // FIXME: Eliminate side effect.
630630
isLibrary: isLibrary,
631631
wholeModuleOptimization: self.buildParameters.configuration == .release,
632632
outputFileMapPath: try target.writeOutputFileMap() // FIXME: Eliminate side effect.

Sources/LLBuildManifest/BuildManifest.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ public struct BuildManifest {
171171
tempsPath: AbsolutePath,
172172
objects: [AbsolutePath],
173173
otherArguments: [String],
174-
sources: [AbsolutePath],
174+
fileListPath: AbsolutePath,
175175
isLibrary: Bool,
176176
wholeModuleOptimization: Bool,
177177
outputFileMapPath: AbsolutePath
@@ -188,7 +188,7 @@ public struct BuildManifest {
188188
tempsPath: tempsPath,
189189
objects: objects,
190190
otherArguments: otherArguments,
191-
sources: sources,
191+
fileList: fileListPath,
192192
isLibrary: isLibrary,
193193
wholeModuleOptimization: wholeModuleOptimization,
194194
outputFileMapPath: outputFileMapPath

Sources/LLBuildManifest/Tools.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ public struct SwiftCompilerTool: ToolProtocol {
241241
public var tempsPath: AbsolutePath
242242
public var objects: [AbsolutePath]
243243
public var otherArguments: [String]
244-
public var sources: [AbsolutePath]
244+
public var fileList: AbsolutePath
245245
public var isLibrary: Bool
246246
public var wholeModuleOptimization: Bool
247247
public var outputFileMapPath: AbsolutePath
@@ -257,7 +257,7 @@ public struct SwiftCompilerTool: ToolProtocol {
257257
tempsPath: AbsolutePath,
258258
objects: [AbsolutePath],
259259
otherArguments: [String],
260-
sources: [AbsolutePath],
260+
fileList: AbsolutePath,
261261
isLibrary: Bool,
262262
wholeModuleOptimization: Bool,
263263
outputFileMapPath: AbsolutePath
@@ -272,14 +272,14 @@ public struct SwiftCompilerTool: ToolProtocol {
272272
self.tempsPath = tempsPath
273273
self.objects = objects
274274
self.otherArguments = otherArguments
275-
self.sources = sources
275+
self.fileList = fileList
276276
self.isLibrary = isLibrary
277277
self.wholeModuleOptimization = wholeModuleOptimization
278278
self.outputFileMapPath = outputFileMapPath
279279
}
280280

281281
var description: String {
282-
return "Compiling Swift Module '\(moduleName)' (\(sources.count) sources)"
282+
return "Compiling Swift Module '\(moduleName)'"
283283
}
284284

285285
var arguments: [String] {
@@ -305,7 +305,7 @@ public struct SwiftCompilerTool: ToolProtocol {
305305
if wholeModuleOptimization {
306306
arguments += ["-whole-module-optimization", "-num-threads", "\(Self.numThreads)"]
307307
}
308-
arguments += ["-c"] + sources.map { $0.pathString }
308+
arguments += ["-c", "@\(fileList.pathString)"]
309309
arguments += ["-I", importPath.pathString]
310310
arguments += otherArguments
311311
return arguments

Tests/CommandsTests/BuildToolTests.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ final class BuildToolTests: CommandsTestCase {
156156
do {
157157
let result = try build(["--product", "exec1"], packagePath: fullPath)
158158
XCTAssertMatch(result.binContents, ["exec1"])
159-
XCTAssertNoMatch(result.binContents, ["exec2.build"])
159+
XCTAssertMatch(result.binContents, ["exec2.build"])
160160
}
161161

162162
do {
@@ -225,9 +225,9 @@ final class BuildToolTests: CommandsTestCase {
225225
do {
226226
let result = try build([], packagePath: aPath)
227227
XCTAssertNoMatch(result.binContents, ["bexec"])
228-
XCTAssertNoMatch(result.binContents, ["BTarget2.build"])
228+
XCTAssertMatch(result.binContents, ["BTarget2.build"])
229229
XCTAssertNoMatch(result.binContents, ["cexec"])
230-
XCTAssertNoMatch(result.binContents, ["CTarget.build"])
230+
XCTAssertMatch(result.binContents, ["CTarget.build"])
231231
}
232232

233233
// Dependency contains a dependent product
@@ -237,15 +237,15 @@ final class BuildToolTests: CommandsTestCase {
237237
XCTAssertMatch(result.binContents, ["BTarget2.build"])
238238
XCTAssertMatch(result.binContents, ["bexec"])
239239
XCTAssertNoMatch(result.binContents, ["aexec"])
240-
XCTAssertNoMatch(result.binContents, ["ATarget.build"])
240+
XCTAssertMatch(result.binContents, ["ATarget.build"])
241241
XCTAssertNoMatch(result.binContents, ["BLibrary.a"])
242242

243243
// FIXME: We create the modulemap during build planning, hence this uglyness.
244244
let bTargetBuildDir = ((try? localFileSystem.getDirectoryContents(result.binPath.appending("BTarget1.build"))) ?? []).filter{ $0 != moduleMapFilename }
245245
XCTAssertTrue(bTargetBuildDir.isEmpty, "bTargetBuildDir should be empty")
246246

247247
XCTAssertNoMatch(result.binContents, ["cexec"])
248-
XCTAssertNoMatch(result.binContents, ["CTarget.build"])
248+
XCTAssertMatch(result.binContents, ["CTarget.build"])
249249

250250
// Also make sure we didn't emit parseable module interfaces
251251
// (do this here to avoid doing a second build in

0 commit comments

Comments
 (0)