File: ToolingUtil.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (109 lines) | stat: -rw-r--r-- 4,507 bytes parent folder | download
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
}