File: EmitSupportedFeaturesJob.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 (126 lines) | stat: -rw-r--r-- 5,450 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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//===---- EmitSupportedFeatures.swift - Swift Compiler Features Info Job ----===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2020 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 SwiftOptions
import struct Foundation.Data
import class Foundation.JSONDecoder
import struct TSCBasic.Diagnostic
import class TSCBasic.DiagnosticsEngine
import protocol TSCBasic.FileSystem
import struct TSCBasic.RelativePath
import var TSCBasic.localFileSystem

/// Describes information about the compiler's supported arguments and features
@_spi(Testing) public struct SupportedCompilerFeatures: Codable {
  var SupportedArguments: [String]
  var SupportedFeatures: [String]
}

extension Toolchain {
  func emitSupportedCompilerFeaturesJob(requiresInPlaceExecution: Bool = false,
                                        swiftCompilerPrefixArgs: [String]) throws -> Job {
    var commandLine: [Job.ArgTemplate] = swiftCompilerPrefixArgs.map { Job.ArgTemplate.flag($0) }
    var inputs: [TypedVirtualPath] = []
    commandLine.append(contentsOf: [.flag("-frontend"),
                                    .flag("-emit-supported-features")])

    // This action does not require any input files, but all frontend actions require
    // at least one so we fake it.
    // FIXME: Teach -emit-supported-features to not expect any inputs, like -print-target-info does.
    let dummyInputPath =
      try VirtualPath.createUniqueTemporaryFileWithKnownContents(.init(validating: "dummyInput.swift"),
                                                                 "".data(using: .utf8)!)
    commandLine.appendPath(dummyInputPath)
    inputs.append(TypedVirtualPath(file: dummyInputPath.intern(), type: .swift))

    return Job(
      moduleName: "",
      kind: .emitSupportedFeatures,
      tool: try resolvedTool(.swiftCompiler),
      commandLine: commandLine,
      displayInputs: [],
      inputs: inputs,
      primaryInputs: [],
      outputs: [.init(file: .standardOutput, type: .jsonCompilerFeatures)],
      requiresInPlaceExecution: requiresInPlaceExecution
    )
  }
}

extension Driver {

  static func computeSupportedCompilerArgs(of toolchain: Toolchain,
                                           parsedOptions: inout ParsedOptions,
                                           diagnosticsEngine: DiagnosticsEngine,
                                           fileSystem: FileSystem,
                                           executor: DriverExecutor)
  throws -> Set<String> {
    // Disable in-process supported features query due to a race condition in the compiler's current
    // build system where libSwiftScan may not be ready when building the Swift standard library.
//    do {
//      if let supportedArgs =
//          try querySupportedCompilerArgsInProcess(of: toolchain, fileSystem: fileSystem) {
//        return supportedArgs
//      }
//    } catch {
//      diagnosticsEngine.emit(.remark_inprocess_supported_features_query_failed(error.localizedDescription))
//    }

    // Fallback: Invoke `swift-frontend -emit-supported-features` and decode the output
    let frontendOverride = try FrontendOverride(&parsedOptions, diagnosticsEngine)
    frontendOverride.setUpForTargetInfo(toolchain)
    defer { frontendOverride.setUpForCompilation(toolchain) }
    let frontendFeaturesJob =
      try toolchain.emitSupportedCompilerFeaturesJob(swiftCompilerPrefixArgs:
                                                      frontendOverride.prefixArgsForTargetInfo)
    let decodedSupportedFlagList = try executor.execute(
      job: frontendFeaturesJob,
      capturingJSONOutputAs: SupportedCompilerFeatures.self,
      forceResponseFiles: false,
      recordedInputModificationDates: [:]).SupportedArguments
    return Set(decodedSupportedFlagList)
  }

  static func querySupportedCompilerArgsInProcess(of toolchain: Toolchain,
                                                  fileSystem: FileSystem)
  throws -> Set<String>? {
    let optionalSwiftScanLibPath = try toolchain.lookupSwiftScanLib()
    if let swiftScanLibPath = optionalSwiftScanLibPath,
       fileSystem.exists(swiftScanLibPath) {
      let libSwiftScanInstance = try SwiftScan(dylib: swiftScanLibPath)
      if libSwiftScanInstance.canQuerySupportedArguments() {
        return try libSwiftScanInstance.querySupportedArguments()
      }
    }
    return nil
  }

  static func computeSupportedCompilerFeatures(of toolchain: Toolchain,
                                               env: [String: String]) throws -> Set<String> {
    struct FeatureInfo: Codable {
      var name: String
    }
    struct FeatureList: Codable {
      var features: [FeatureInfo]
    }
    let jsonPath = try getRootPath(of: toolchain, env: env)
      .appending(component: "share")
      .appending(component: "swift")
      .appending(component: "features.json")
    guard localFileSystem.exists(jsonPath) else {
      return Set<String>()
    }
    let content = try localFileSystem.readFileContents(jsonPath)
    let result = try JSONDecoder().decode(FeatureList.self, from: Data(content.contents))
    return Set(result.features.map {$0.name})
  }
}