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})
}
}
|