1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
|
//===------- ToolingUtil.swift - Swift Driver Source Version--------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import class TSCBasic.DiagnosticsEngine
import struct TSCBasic.Diagnostic
import class TSCBasic.ProcessSet
import enum TSCBasic.ProcessEnv
import var TSCBasic.localFileSystem
import SwiftOptions
/// Generates the list of arguments that would be passed to the compiler
/// frontend from the given driver arguments.
///
/// \param ArgList The driver arguments (i.e. normal arguments for \c swiftc).
/// \param ForceNoOutputs If true, override the output mode to "-typecheck" and
/// produce no outputs. For example, this disables "-emit-module" and "-c" and
/// prevents the creation of temporary files.
/// \param outputFrontendArgs Contains the resulting frontend invocation command
/// \param emittedDiagnostics Contains the diagnostics emitted by the driver
///
/// \returns true on error
///
/// \note This function is not intended to create invocations which are
/// suitable for use in REPL or immediate modes.
public func getSingleFrontendInvocationFromDriverArguments(argList: [String],
outputFrontendArgs: inout [String],
emittedDiagnostics: inout [Diagnostic],
forceNoOutputs: Bool = false) -> Bool {
var args: [String] = []
args.append(contentsOf: argList)
// When creating a CompilerInvocation, ensure that the driver creates a single
// frontend command.
args.append("-whole-module-optimization")
// Explicitly disable batch mode to avoid a spurious warning when combining
// -enable-batch-mode with -whole-module-optimization. This is an
// implementation detail.
args.append("-disable-batch-mode");
// Prevent having a separate job for emit-module, we would like
// to just have one job
args.append("-no-emit-module-separately-wmo")
// Avoid using filelists
args.append("-driver-filelist-threshold");
args.append(String(Int.max));
let diagnosticsEngine = DiagnosticsEngine()
defer { emittedDiagnostics = diagnosticsEngine.diagnostics }
do {
args = try ["swiftc"] + Driver.expandResponseFiles(args,
fileSystem: localFileSystem,
diagnosticsEngine: diagnosticsEngine)
let optionTable = OptionTable()
var parsedOptions = try optionTable.parse(Array(args), for: .batch, delayThrows: true)
if forceNoOutputs {
// Clear existing output modes and supplementary outputs.
parsedOptions.eraseAllArguments(in: .modes)
parsedOptions.eraseSupplementaryOutputs()
parsedOptions.addOption(.typecheck, argument: .none)
}
// Instantiate the driver, setting up the toolchain in the process, etc.
let resolver = try ArgsResolver(fileSystem: localFileSystem)
let executor = SimpleExecutor(resolver: resolver,
fileSystem: localFileSystem,
env: ProcessEnv.vars)
var driver = try Driver(args: parsedOptions.commandLine,
diagnosticsOutput: .engine(diagnosticsEngine),
executor: executor)
if diagnosticsEngine.hasErrors {
return true
}
let buildPlan = try driver.planBuild()
if diagnosticsEngine.hasErrors {
return true
}
let compileJobs = buildPlan.filter({ $0.kind == .compile })
guard let compileJob = compileJobs.spm_only else {
diagnosticsEngine.emit(.error_expected_one_frontend_job())
return true
}
if !compileJob.commandLine.starts(with: [.flag("-frontend")]) {
diagnosticsEngine.emit(.error_expected_frontend_command())
return true
}
outputFrontendArgs = try executor.description(of: compileJob,
forceResponseFiles: false).components(separatedBy: " ")
} catch {
print("Unexpected error: \(error).")
return true
}
return false
}
|