Skip to content

Commit ce4ee20

Browse files
authored
Merge pull request #67 from owenv/compile-base-outputs
More accurate computation of compile job output paths
2 parents c6d3b39 + c4afe55 commit ce4ee20

File tree

4 files changed

+102
-12
lines changed

4 files changed

+102
-12
lines changed

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ extension Driver {
617617
return
618618
}
619619

620-
if jobs.contains(where: { $0.requiresInPlaceExecution }) {
620+
if jobs.contains(where: { $0.requiresInPlaceExecution }) || jobs.count == 1 {
621621
assert(jobs.count == 1, "Cannot execute in place for multi-job build plans")
622622
return try executeJobInPlace(jobs[0], resolver: resolver, forceResponseFiles: forceResponseFiles)
623623
}

Sources/SwiftDriver/Jobs/CompileJob.swift

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,57 @@ extension Driver {
2525
}
2626
}
2727

28-
/// Add the compiler inputs for a frontend compilation job, and return the corresponding primary set of outputs.
29-
func addCompileInputs(primaryInputs: [TypedVirtualPath], inputs: inout [TypedVirtualPath], commandLine: inout [Job.ArgTemplate]) -> [TypedVirtualPath] {
28+
fileprivate mutating func computePrimaryOutput(for input: TypedVirtualPath, outputType: FileType,
29+
isTopLevel: Bool) -> TypedVirtualPath {
30+
if let path = outputFileMap?.existingOutput(inputFile: input.file, outputType: outputType) {
31+
return TypedVirtualPath(file: path, type: outputType)
32+
}
33+
34+
if isTopLevel {
35+
if let baseOutput = parsedOptions.getLastArgument(.o)?.asSingle,
36+
let baseOutputPath = try? VirtualPath(path: baseOutput){
37+
return TypedVirtualPath(file: baseOutputPath, type: outputType)
38+
} else if compilerOutputType?.isTextual == true {
39+
return TypedVirtualPath(file: .standardOutput, type: outputType)
40+
}
41+
}
42+
43+
let baseName: String
44+
if (!compilerMode.usesPrimaryFileInputs && numThreads == 0) {
45+
baseName = moduleName
46+
} else {
47+
baseName = input.file.basenameWithoutExt
48+
}
49+
50+
if !isTopLevel {
51+
return TypedVirtualPath(file:VirtualPath.temporary(.init(baseName.appendingFileTypeExtension(outputType))),
52+
type: outputType)
53+
}
54+
55+
return TypedVirtualPath(file: .relative(.init(baseName.appendingFileTypeExtension(outputType))), type: outputType)
56+
}
57+
58+
/// Add the compiler inputs for a frontend compilation job, and return the
59+
/// corresponding primary set of outputs.
60+
mutating func addCompileInputs(primaryInputs: [TypedVirtualPath],
61+
inputs: inout [TypedVirtualPath],
62+
commandLine: inout [Job.ArgTemplate]) -> [TypedVirtualPath] {
63+
// Is this compile job top-level
64+
let isTopLevel: Bool
65+
66+
switch compilerOutputType {
67+
case .assembly, .sil, .raw_sil, .llvmIR, .ast:
68+
isTopLevel = true
69+
case .object:
70+
isTopLevel = (linkerOutputType == nil)
71+
case .swift, .sib, .image, .dSYM, .dependencies, .autolink,
72+
.swiftModule, .swiftDocumentation, .swiftInterface,
73+
.swiftSourceInfoFile, .raw_sib, .llvmBitcode, .diagnostics,
74+
.objcHeader, .swiftDeps, .remap, .importedModules, .tbd, .moduleTrace,
75+
.indexData, .optimizationRecord, .pcm, .pch, nil:
76+
isTopLevel = false
77+
}
78+
3079
// Collect the set of input files that are part of the Swift compilation.
3180
let swiftInputFiles: [TypedVirtualPath] = inputFiles.compactMap { inputFile in
3281
if inputFile.type.isPartOfSwiftCompilation {
@@ -58,21 +107,19 @@ extension Driver {
58107
// add an output for the input.
59108
if isPrimary || numThreads > 0,
60109
let compilerOutputType = compilerOutputType {
61-
let output = (outputFileMap ?? OutputFileMap()).getOutput(
62-
inputFile: input.file,
63-
outputType: compilerOutputType
64-
)
65-
primaryOutputs.append(TypedVirtualPath(file: output, type: compilerOutputType))
110+
primaryOutputs.append(computePrimaryOutput(for: input,
111+
outputType: compilerOutputType,
112+
isTopLevel: isTopLevel))
66113
}
67114
}
68115

69116
// When not using primary file inputs or multithreading, add a single output.
70117
if !usesPrimaryFileInputs && numThreads == 0,
71118
let outputType = compilerOutputType {
72-
let existingOutputPath = outputFileMap?.existingOutputForSingleInput(
73-
outputType: outputType)
74-
let output = existingOutputPath ?? VirtualPath.temporary(.init(moduleName.appendingFileTypeExtension(outputType)))
75-
primaryOutputs.append(TypedVirtualPath(file: output, type: outputType))
119+
primaryOutputs.append(computePrimaryOutput(
120+
for: TypedVirtualPath(file: try! VirtualPath(path: ""),
121+
type: swiftInputFiles[0].type),
122+
outputType: outputType, isTopLevel: isTopLevel))
76123
}
77124

78125
return primaryOutputs

Sources/SwiftDriver/Utilities/FileType.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,3 +246,18 @@ extension FileType {
246246
}
247247
}
248248
}
249+
250+
extension FileType {
251+
var isTextual: Bool {
252+
switch self {
253+
case .swift, .sil, .dependencies, .assembly, .ast, .raw_sil, .llvmIR,
254+
.objcHeader, .autolink, .importedModules, .tbd, .moduleTrace,
255+
.optimizationRecord, .swiftInterface:
256+
return true
257+
case .image, .object, .dSYM, .pch, .sib, .raw_sib, .swiftModule,
258+
.swiftDocumentation, .swiftSourceInfoFile, .llvmBitcode, .diagnostics,
259+
.pcm, .swiftDeps, .remap, .indexData:
260+
return false
261+
}
262+
}
263+
}

Tests/SwiftDriverTests/SwiftDriverTests.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,34 @@ final class SwiftDriverTests: XCTestCase {
227227
}
228228
}
229229

230+
func testBaseOutputPaths() throws {
231+
// Test the combination of -c and -o includes the base output path.
232+
do {
233+
var driver = try Driver(args: ["swiftc", "-c", "foo.swift", "-o", "/some/output/path/bar.o"])
234+
let plannedJobs = try driver.planBuild()
235+
XCTAssertEqual(plannedJobs.count, 1)
236+
XCTAssertEqual(plannedJobs[0].kind, .compile)
237+
XCTAssertTrue(plannedJobs[0].commandLine.contains(.path(try VirtualPath(path: "/some/output/path/bar.o"))))
238+
}
239+
240+
do {
241+
var driver = try Driver(args: ["swiftc", "-emit-sil", "foo.swift", "-o", "/some/output/path/bar.sil"])
242+
let plannedJobs = try driver.planBuild()
243+
XCTAssertEqual(plannedJobs.count, 1)
244+
XCTAssertEqual(plannedJobs[0].kind, .compile)
245+
XCTAssertTrue(plannedJobs[0].commandLine.contains(.path(try VirtualPath(path: "/some/output/path/bar.sil"))))
246+
}
247+
248+
do {
249+
// If no output is specified, verify we print to stdout for textual formats.
250+
var driver = try Driver(args: ["swiftc", "-emit-assembly", "foo.swift"])
251+
let plannedJobs = try driver.planBuild()
252+
XCTAssertEqual(plannedJobs.count, 1)
253+
XCTAssertEqual(plannedJobs[0].kind, .compile)
254+
XCTAssertTrue(plannedJobs[0].commandLine.contains(.path(.standardOutput)))
255+
}
256+
}
257+
230258
func testMultithreading() throws {
231259

232260
XCTAssertEqual(try Driver(args: ["swiftc"]).numThreads, 0)

0 commit comments

Comments
 (0)