in Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift [302:510]
mutating func addFrontendSupplementaryOutputArguments(commandLine: inout [Job.ArgTemplate],
primaryInputs: [TypedVirtualPath],
inputsGeneratingCodeCount: Int,
inputOutputMap: inout [TypedVirtualPath: [TypedVirtualPath]],
includeModuleTracePath: Bool,
indexFilePath: TypedVirtualPath?) throws -> [TypedVirtualPath] {
var flaggedInputOutputPairs: [(flag: String, input: TypedVirtualPath?, output: TypedVirtualPath)] = []
/// Add output of a particular type, if needed.
func addOutputOfType(
outputType: FileType,
finalOutputPath: VirtualPath.Handle?,
input: TypedVirtualPath?,
flag: String
) {
// If there is no final output, there's nothing to do.
guard let finalOutputPath = finalOutputPath else { return }
// If the whole of the compiler output is this type, there's nothing to
// do.
if outputType == compilerOutputType { return }
// Compute the output path based on the input path (if there is one), or
// use the final output.
let outputPath: VirtualPath.Handle
if let input = input {
if let outputFileMapPath = outputFileMap?.existingOutput(inputFile: input.fileHandle, outputType: outputType) {
outputPath = outputFileMapPath
} else if let output = inputOutputMap[input]?.first, output.file != .standardOutput, compilerOutputType != nil {
// Alongside primary output
outputPath = output.file.replacingExtension(with: outputType).intern()
} else {
outputPath = VirtualPath.createUniqueTemporaryFile(RelativePath(input.file.basenameWithoutExt.appendingFileTypeExtension(outputType))).intern()
}
// Update the input-output file map.
let output = TypedVirtualPath(file: outputPath, type: outputType)
if inputOutputMap[input] != nil {
inputOutputMap[input]!.append(output)
} else {
inputOutputMap[input] = [output]
}
} else {
outputPath = finalOutputPath
}
flaggedInputOutputPairs.append((flag: flag, input: input, output: TypedVirtualPath(file: outputPath, type: outputType)))
}
/// Add all of the outputs needed for a given input.
func addAllOutputsFor(input: TypedVirtualPath?) {
if !emitModuleSeparately {
// Generate the module files with the main job.
addOutputOfType(
outputType: .swiftModule,
finalOutputPath: moduleOutputInfo.output?.outputPath,
input: input,
flag: "-emit-module-path")
addOutputOfType(
outputType: .swiftDocumentation,
finalOutputPath: moduleDocOutputPath,
input: input,
flag: "-emit-module-doc-path")
addOutputOfType(
outputType: .swiftSourceInfoFile,
finalOutputPath: moduleSourceInfoPath,
input: input,
flag: "-emit-module-source-info-path")
}
addOutputOfType(
outputType: .dependencies,
finalOutputPath: dependenciesFilePath,
input: input,
flag: "-emit-dependencies-path")
addOutputOfType(
outputType: .swiftDeps,
finalOutputPath: referenceDependenciesPath,
input: input,
flag: "-emit-reference-dependencies-path")
addOutputOfType(
outputType: self.optimizationRecordFileType ?? .yamlOptimizationRecord,
finalOutputPath: optimizationRecordPath,
input: input,
flag: "-save-optimization-record-path")
addOutputOfType(
outputType: .diagnostics,
finalOutputPath: serializedDiagnosticsFilePath,
input: input,
flag: "-serialize-diagnostics-path")
}
if compilerMode.usesPrimaryFileInputs {
for input in primaryInputs {
addAllOutputsFor(input: input)
}
} else {
addAllOutputsFor(input: nil)
if !emitModuleSeparately {
// Outputs that only make sense when the whole module is processed
// together.
addOutputOfType(
outputType: .objcHeader,
finalOutputPath: objcGeneratedHeaderPath,
input: nil,
flag: "-emit-objc-header-path")
addOutputOfType(
outputType: .swiftInterface,
finalOutputPath: swiftInterfacePath,
input: nil,
flag: "-emit-module-interface-path")
addOutputOfType(
outputType: .privateSwiftInterface,
finalOutputPath: swiftPrivateInterfacePath,
input: nil,
flag: "-emit-private-module-interface-path")
addOutputOfType(
outputType: .tbd,
finalOutputPath: tbdPath,
input: nil,
flag: "-emit-tbd-path")
if let abiDescriptorPath = abiDescriptorPath {
addOutputOfType(outputType: .jsonABIBaseline,
finalOutputPath: abiDescriptorPath.fileHandle,
input: nil,
flag: "-emit-abi-descriptor-path")
}
}
}
if parsedOptions.hasArgument(.updateCode) {
guard compilerMode == .standardCompile else {
diagnosticEngine.emit(.error_update_code_not_supported(in: compilerMode))
throw Diagnostics.fatalError
}
assert(primaryInputs.count == 1, "Standard compile job had more than one primary input")
let input = primaryInputs[0]
let remapOutputPath: VirtualPath
if let outputFileMapPath = outputFileMap?.existingOutput(inputFile: input.fileHandle, outputType: .remap) {
remapOutputPath = VirtualPath.lookup(outputFileMapPath)
} else if let output = inputOutputMap[input]?.first, output.file != .standardOutput {
// Alongside primary output
remapOutputPath = output.file.replacingExtension(with: .remap)
} else {
remapOutputPath =
VirtualPath.createUniqueTemporaryFile(RelativePath(input.file.basenameWithoutExt.appendingFileTypeExtension(.remap)))
}
flaggedInputOutputPairs.append((flag: "-emit-remap-file-path",
input: input,
output: TypedVirtualPath(file: remapOutputPath.intern(), type: .remap)))
}
if includeModuleTracePath, let tracePath = loadedModuleTracePath {
flaggedInputOutputPairs.append((flag: "-emit-loaded-module-trace-path",
input: nil,
output: TypedVirtualPath(file: tracePath, type: .moduleTrace)))
}
if inputsGeneratingCodeCount * FileType.allCases.count > fileListThreshold {
var entries = [VirtualPath.Handle: [FileType: VirtualPath.Handle]]()
for input in primaryInputs {
if let output = inputOutputMap[input]?.first {
addEntry(&entries, input: input, output: output)
} else {
// Primary inputs are expected to appear in the output file map even
// if they have no corresponding outputs.
entries[input.fileHandle] = [:]
}
}
if primaryInputs.isEmpty {
// To match the legacy driver behavior, make sure we add the first input file
// to the output file map if compiling without primary inputs (WMO), even
// if there aren't any corresponding outputs.
entries[inputFiles[0].fileHandle] = [:]
}
for flaggedPair in flaggedInputOutputPairs {
addEntry(&entries, input: flaggedPair.input, output: flaggedPair.output)
}
// To match the legacy driver behavior, make sure we add an entry for the
// file under indexing and the primary output file path.
if let indexFilePath = indexFilePath, let idxOutput = inputOutputMap[indexFilePath]?.first {
entries[indexFilePath.fileHandle] = [.indexData: idxOutput.fileHandle]
}
let outputFileMap = OutputFileMap(entries: entries)
let fileList = VirtualPath.createUniqueFilelist(RelativePath("supplementaryOutputs"),
.outputFileMap(outputFileMap))
commandLine.appendFlag(.supplementaryOutputFileMap)
commandLine.appendPath(fileList)
} else {
for flaggedPair in flaggedInputOutputPairs {
// Add the appropriate flag.
commandLine.appendFlag(flaggedPair.flag)
commandLine.appendPath(flaggedPair.output.file)
}
}
return flaggedInputOutputPairs.map { $0.output }
}