Skip to content

Commit 912b130

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 912b130

File tree

5 files changed

+32
-20
lines changed

5 files changed

+32
-20
lines changed

Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift

Lines changed: 13 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.writeFileList(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.writeFileList(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.writeFileList(self.target.sources.paths).pathString)")
649648

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

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

Sources/Build/LLBuildManifestBuilder.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,8 @@ extension LLBuildManifestBuilder {
626626
tempsPath: target.tempsPath,
627627
objects: try target.objects,
628628
otherArguments: try target.compileArguments(),
629-
sources: target.sources,
629+
sourceCount: target.sources.count,
630+
fileListPath: try target.writeFileList(target.sources),
630631
isLibrary: isLibrary,
631632
wholeModuleOptimization: self.buildParameters.configuration == .release,
632633
outputFileMapPath: try target.writeOutputFileMap() // FIXME: Eliminate side effect.

Sources/LLBuildManifest/BuildManifest.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ public struct BuildManifest {
171171
tempsPath: AbsolutePath,
172172
objects: [AbsolutePath],
173173
otherArguments: [String],
174-
sources: [AbsolutePath],
174+
sourceCount: Int,
175+
fileListPath: AbsolutePath,
175176
isLibrary: Bool,
176177
wholeModuleOptimization: Bool,
177178
outputFileMapPath: AbsolutePath
@@ -188,7 +189,8 @@ public struct BuildManifest {
188189
tempsPath: tempsPath,
189190
objects: objects,
190191
otherArguments: otherArguments,
191-
sources: sources,
192+
sourceCount: sourceCount,
193+
fileList: fileListPath,
192194
isLibrary: isLibrary,
193195
wholeModuleOptimization: wholeModuleOptimization,
194196
outputFileMapPath: outputFileMapPath

Sources/LLBuildManifest/Tools.swift

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,8 @@ 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 sourceCount: Int
245+
public var fileList: AbsolutePath
245246
public var isLibrary: Bool
246247
public var wholeModuleOptimization: Bool
247248
public var outputFileMapPath: AbsolutePath
@@ -257,7 +258,8 @@ public struct SwiftCompilerTool: ToolProtocol {
257258
tempsPath: AbsolutePath,
258259
objects: [AbsolutePath],
259260
otherArguments: [String],
260-
sources: [AbsolutePath],
261+
sourceCount: Int,
262+
fileList: AbsolutePath,
261263
isLibrary: Bool,
262264
wholeModuleOptimization: Bool,
263265
outputFileMapPath: AbsolutePath
@@ -272,14 +274,15 @@ public struct SwiftCompilerTool: ToolProtocol {
272274
self.tempsPath = tempsPath
273275
self.objects = objects
274276
self.otherArguments = otherArguments
275-
self.sources = sources
277+
self.sourceCount = sourceCount
278+
self.fileList = fileList
276279
self.isLibrary = isLibrary
277280
self.wholeModuleOptimization = wholeModuleOptimization
278281
self.outputFileMapPath = outputFileMapPath
279282
}
280283

281284
var description: String {
282-
return "Compiling Swift Module '\(moduleName)' (\(sources.count) sources)"
285+
return "Compiling Swift Module '\(moduleName)' (\(sourceCount) sources)"
283286
}
284287

285288
var arguments: [String] {
@@ -305,7 +308,7 @@ public struct SwiftCompilerTool: ToolProtocol {
305308
if wholeModuleOptimization {
306309
arguments += ["-whole-module-optimization", "-num-threads", "\(Self.numThreads)"]
307310
}
308-
arguments += ["-c"] + sources.map { $0.pathString }
311+
arguments += ["-c", "@\(fileList.pathString)"]
309312
arguments += ["-I", importPath.pathString]
310313
arguments += otherArguments
311314
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)