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
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2022-2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
@_spi(SwiftPMInternal)
import Basics
import PackageModel
import SwiftDriver
import class TSCBasic.Process
import struct TSCBasic.ProcessResult
public enum DriverSupport {
private static var flagsMap = ThreadSafeBox<[String: Set<String>]>()
/// This checks _frontend_ supported flags, which are not necessarily supported in the driver.
public static func checkSupportedFrontendFlags(
flags: Set<String>,
toolchain: PackageModel.Toolchain,
fileSystem: FileSystem
) -> Bool {
let trimmedFlagSet = Set(flags.map { $0.trimmingCharacters(in: ["-"]) })
let swiftcPathString = toolchain.swiftCompilerPath.pathString
if let entry = flagsMap.get(), let cachedSupportedFlagSet = entry[swiftcPathString + "-frontend"] {
return cachedSupportedFlagSet.intersection(trimmedFlagSet) == trimmedFlagSet
}
do {
let executor = try SPMSwiftDriverExecutor(
resolver: ArgsResolver(fileSystem: fileSystem),
fileSystem: fileSystem,
env: [:]
)
let driver = try Driver(
args: ["swiftc"],
executor: executor,
compilerExecutableDir: TSCAbsolutePath(toolchain.swiftCompilerPath.parentDirectory)
)
let supportedFlagSet = Set(driver.supportedFrontendFlags.map { $0.trimmingCharacters(in: ["-"]) })
flagsMap.put([swiftcPathString + "-frontend": supportedFlagSet])
return supportedFlagSet.intersection(trimmedFlagSet) == trimmedFlagSet
} catch {
return false
}
}
// This checks if given flags are supported in the built-in toolchain driver. Currently
// there's no good way to get the supported flags from it, so run `swiftc -h` directly
// to get the flags and cache the result.
static func checkToolchainDriverFlags(
flags: Set<String>,
toolchain: PackageModel.Toolchain,
fileSystem: FileSystem
) -> Bool {
let trimmedFlagSet = Set(flags.map { $0.trimmingCharacters(in: ["-"]) })
let swiftcPathString = toolchain.swiftCompilerPath.pathString
if let entry = flagsMap.get(), let cachedSupportedFlagSet = entry[swiftcPathString + "-driver"] {
return cachedSupportedFlagSet.intersection(trimmedFlagSet) == trimmedFlagSet
}
do {
let helpJob = try TSCBasic.Process.launchProcess(
arguments: [swiftcPathString, "-h"],
env: .init(Environment.current)
)
let processResult = try helpJob.waitUntilExit()
guard processResult.exitStatus == .terminated(code: 0) else {
return false
}
let helpOutput = try processResult.utf8Output()
let helpFlags = helpOutput.components(separatedBy: " ").map { $0.trimmingCharacters(in: ["-"]) }
let supportedFlagSet = Set(helpFlags)
flagsMap.put([swiftcPathString + "-driver": supportedFlagSet])
return supportedFlagSet.intersection(trimmedFlagSet) == trimmedFlagSet
} catch {
return false
}
}
@_spi(SwiftPMInternal)
public static func isPackageNameSupported(toolchain: PackageModel.Toolchain, fileSystem: FileSystem) -> Bool {
DriverSupport.checkToolchainDriverFlags(flags: ["-package-name"], toolchain: toolchain, fileSystem: fileSystem)
}
}
|