Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Sources/SwiftDriver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ add_library(SwiftDriver
"ExplicitModuleBuilds/ClangVersionedDependencyResolution.swift"
"ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift"
"ExplicitModuleBuilds/ModuleDependencyScanning.swift"
"ExplicitModuleBuilds/PlaceholderDependencyResolution.swift"
"ExplicitModuleBuilds/SerializableModuleArtifacts.swift"
"ExplicitModuleBuilds/InterModuleDependencies/CommonDependencyOperations.swift"
"ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyGraph.swift"
Expand Down
37 changes: 13 additions & 24 deletions Sources/SwiftDriver/Driver/Driver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -305,12 +305,9 @@ public struct Driver {
/// is shared across many targets; otherwise, a new instance is created by the driver itself.
@_spi(Testing) public let interModuleDependencyOracle: InterModuleDependencyOracle

// TODO: Once the clients have transitioned to using the InterModuleDependencyOracle API,
// this must convey information about the externally-prebuilt targets only
/// All external artifacts a build system (e.g. SwiftPM) may pass in as input to the explicit
/// build of the current module. Consists of a map of externally-built targets, and a map of all previously
/// discovered/scanned modules and their infos.
@_spi(Testing) public var externalBuildArtifacts: ExternalBuildArtifacts? = nil
/// A dictionary of external targets that are a part of the same build, mapping to filesystem paths
/// of their module files
@_spi(Testing) public var externalTargetModulePathMap: ExternalTargetModulePathMap? = nil

/// A collection of all the flags the selected toolchain's `swift-frontend` supports
public let supportedFrontendFlags: Set<String>
Expand Down Expand Up @@ -387,9 +384,14 @@ public struct Driver {
/// expand response files, etc. By default this is the local filesystem.
/// - Parameter executor: Used by the driver to execute jobs. The default argument
/// is present to streamline testing, it shouldn't be used in production.
/// - Parameter externalBuildArtifacts: All external artifacts a build system may pass in as input to the explicit
/// build of the current module. Consists of a map of externally-built targets, and a map of all previously
/// discovered/scanned modules.
/// - Parameter integratedDriver: Used to distinguish whether the driver is being used as
/// an executable or as a library.
/// - Parameter compilerExecutableDir: Directory that contains the compiler executable to be used.
/// Used when in `integratedDriver` mode as a substitute for the driver knowing its executable path.
/// - Parameter externalTargetModulePathMap: A dictionary of external targets that are a part of
/// the same build, mapping to filesystem paths of their module files.
/// - Parameter interModuleDependencyOracle: An oracle for querying inter-module dependencies,
/// shared across different module builds by a build system.
public init(
args: [String],
env: [String: String] = ProcessEnv.vars,
Expand All @@ -398,9 +400,6 @@ public struct Driver {
executor: DriverExecutor,
integratedDriver: Bool = true,
compilerExecutableDir: AbsolutePath? = nil,
// FIXME: Duplication with externalBuildArtifacts and externalTargetModulePathMap
// is a temporary backwards-compatibility shim to help transition SwiftPM to the new API
externalBuildArtifacts: ExternalBuildArtifacts? = nil,
externalTargetModulePathMap: ExternalTargetModulePathMap? = nil,
interModuleDependencyOracle: InterModuleDependencyOracle? = nil
) throws {
Expand All @@ -411,10 +410,8 @@ public struct Driver {
self.diagnosticEngine = diagnosticsEngine
self.executor = executor

if let externalArtifacts = externalBuildArtifacts {
self.externalBuildArtifacts = externalArtifacts
} else if let externalTargetPaths = externalTargetModulePathMap {
self.externalBuildArtifacts = (externalTargetPaths, [:])
if let externalTargetPaths = externalTargetModulePathMap {
self.externalTargetModulePathMap = externalTargetPaths
}

if case .subcommand = try Self.invocationRunMode(forArgs: args).mode {
Expand Down Expand Up @@ -507,14 +504,6 @@ public struct Driver {
self.interModuleDependencyOracle = dependencyOracle
} else {
self.interModuleDependencyOracle = InterModuleDependencyOracle()

// This is a shim for backwards-compatibility with ModuleInfoMap-based API
// used by SwiftPM
if let externalArtifacts = externalBuildArtifacts {
if !externalArtifacts.1.isEmpty {
try self.interModuleDependencyOracle.mergeModules(from: externalArtifacts.1)
}
}
}

self.fileListThreshold = try Self.computeFileListThreshold(&self.parsedOptions, diagnosticsEngine: diagnosticsEngine)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@ import Foundation
/// A map from a module identifier to a path to its .swiftmodule file.
public typealias ExternalTargetModulePathMap = [ModuleDependencyId: AbsolutePath]

// FIXME: ExternalBuildArtifacts is a temporary backwards-compatibility shim
// to help transition SwiftPM to the new API.
/// A tuple all external artifacts a build system may pass in as input to the explicit build of the current module
/// Consists of a map of externally-built targets, and a map of all previously discovered/scanned modules.
public typealias ExternalBuildArtifacts = (ExternalTargetModulePathMap, ModuleInfoMap)

/// In Explicit Module Build mode, this planner is responsible for generating and providing
/// build jobs for all module dependencies and providing compile command options
/// that specify said explicit module dependencies.
Expand Down Expand Up @@ -444,7 +438,7 @@ extension ExplicitDependencyBuildPlanner {

/// Encapsulates some of the common queries of the ExplicitDependencyBuildPlanner with error-checking
/// on the dependency graph's structure.
internal extension InterModuleDependencyGraph {
@_spi(Testing) public extension InterModuleDependencyGraph {
func moduleInfo(of moduleId: ModuleDependencyId) throws -> ModuleInfo {
guard let moduleInfo = modules[moduleId] else {
throw Driver.Error.missingModuleDependency(moduleId.moduleName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@ import TSCBasic
/// For targets that are built alongside the driver's current module, the scanning action will report them as
/// textual targets to be built from source. Because we can rely on these targets to have been built prior
/// to the driver's current target, we resolve such external targets as prebuilt binary modules, in the graph.
mutating func resolveExternalDependencies(for externalBuildArtifacts: ExternalBuildArtifacts)
mutating func resolveExternalDependencies(for externalTargetModulePathMap: ExternalTargetModulePathMap)
throws {
let externalTargetModulePathMap = externalBuildArtifacts.0

for (externalModuleId, externalModulePath) in externalTargetModulePathMap {
for (externalModuleId, externalModulePath) in externalTargetModulePathMap {
// Replace the occurence of a Swift module to-be-built from source-file
// to an info that describes a pre-built binary module.
let swiftModuleId: ModuleDependencyId = .swift(externalModuleId.moduleName)
Expand All @@ -30,57 +28,22 @@ import TSCBasic
// a dependency on a target that is not actually used.
continue
}

let newModuleId: ModuleDependencyId = .swiftPrebuiltExternal(externalModuleId.moduleName)
let newModuleId: ModuleDependencyId = .swiftPrebuiltExternal(externalModuleId.moduleName)
let newExternalModuleDetails =
try SwiftPrebuiltExternalModuleDetails(compiledModulePath:
TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()))
try SwiftPrebuiltExternalModuleDetails(compiledModulePath:
TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()))
let newInfo = ModuleInfo(modulePath: TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()),
sourceFiles: [],
directDependencies: currentInfo.directDependencies,
details: .swiftPrebuiltExternal(newExternalModuleDetails))

Self.replaceModule(originalId: swiftModuleId, replacementId: newModuleId,
Self.replaceModule(originalId: swiftModuleId, replacementId: newModuleId,
replacementInfo: newInfo, in: &modules)
}
}
}

@_spi(Testing) public extension InterModuleDependencyOracle {
/// An API to allow clients to accumulate InterModuleDependencyGraphs across mutiple main externalModules/targets
/// into a single collection of discovered externalModules.
func mergeModules(from dependencyGraph: InterModuleDependencyGraph) throws {
try queue.sync {
for (moduleId, moduleInfo) in dependencyGraph.modules {
try InterModuleDependencyGraph.mergeModule(moduleId, moduleInfo, into: &externalModules)
}
}
}

// This is a backwards-compatibility shim to handle existing ModuleInfoMap-based API
// used by SwiftPM
func mergeModules(from moduleInfoMap: ModuleInfoMap) throws {
try queue.sync {
for (moduleId, moduleInfo) in moduleInfoMap {
try InterModuleDependencyGraph.mergeModule(moduleId, moduleInfo, into: &externalModules)
}
}
}
}

public extension InterModuleDependencyGraph {
// This is a shim for backwards-compatibility with existing API used by SwiftPM.
// TODO: After SwiftPM switches to using the oracle, this should be deleted.
static func mergeModules(
from dependencyGraph: InterModuleDependencyGraph,
into discoveredModules: inout ModuleInfoMap
) throws {
for (moduleId, moduleInfo) in dependencyGraph.modules {
try mergeModule(moduleId, moduleInfo, into: &discoveredModules)
}
}
}

extension InterModuleDependencyGraph {
/// Compute a set of modules that are "reachable" (form direct or transitive dependency)
/// from each module in the graph.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,44 +118,5 @@ public class InterModuleDependencyOracle {

/// A reference to an instance of the compiler's libSwiftScan shared library
private var swiftScanLibInstance: SwiftScan? = nil

// The below API is a legacy implementation of the oracle that is in-place to allow clients to
// transition to the new API. It is to be removed once that transition is complete.
/// The complete set of modules discovered so far, spanning potentially multiple targets,
/// accumulated across builds of multiple targets.
/// TODO: This is currently only used for placeholder resolution. libSwiftScan should allow us to move away
/// from the concept of a placeholder module so we should be able to get rid of this in the future.
internal var externalModules: ModuleInfoMap = [:]
/// Query the ModuleInfo of a module with a given ID
@_spi(Testing) public func getExternalModuleInfo(of moduleId: ModuleDependencyId) -> ModuleInfo? {
queue.sync {
return externalModules[moduleId]
}
}
}

// This is a shim for backwards-compatibility with existing API used by SwiftPM.
// TODO: After SwiftPM switches to using the oracle, this should be deleted.
extension Driver {
public var interModuleDependencyGraph: InterModuleDependencyGraph? {
let mainModuleId : ModuleDependencyId = .swift(moduleOutputInfo.name)
var mainModuleDependencyGraph =
InterModuleDependencyGraph(mainModuleName: moduleOutputInfo.name)

addModule(moduleId: mainModuleId,
moduleInfo: interModuleDependencyOracle.getExternalModuleInfo(of: mainModuleId)!,
into: &mainModuleDependencyGraph)
return mainModuleDependencyGraph
}

private func addModule(moduleId: ModuleDependencyId,
moduleInfo: ModuleInfo,
into dependencyGraph: inout InterModuleDependencyGraph) {
dependencyGraph.modules[moduleId] = moduleInfo
moduleInfo.directDependencies?.forEach { dependencyId in
addModule(moduleId: dependencyId,
moduleInfo: interModuleDependencyOracle.getExternalModuleInfo(of: dependencyId)!,
into: &dependencyGraph)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,48 +52,11 @@ public extension Driver {
moduleDependencyGraphUse: .dependencyScan)
// FIXME: MSVC runtime flags

// Pass in external target dependencies to be treated as placeholder dependencies by the scanner
if let externalBuildArtifacts = externalBuildArtifacts {
let dependencyPlaceholderMapFile =
try serializeExternalDependencyArtifacts(externalBuildArtifacts: externalBuildArtifacts)
commandLine.appendFlag("-placeholder-dependency-module-map-file")
commandLine.appendPath(dependencyPlaceholderMapFile)
}

// Pass on the input files
commandLine.append(contentsOf: inputFiles.map { .path($0.file) })
return (inputs, commandLine)
}

/// Serialize a map of placeholder (external) dependencies for the dependency scanner.
private func serializeExternalDependencyArtifacts(externalBuildArtifacts: ExternalBuildArtifacts)
throws -> VirtualPath {
let (externalTargetModulePathMap, externalModuleInfoMap) = externalBuildArtifacts
var placeholderArtifacts: [SwiftModuleArtifactInfo] = []

// Explicit external targets
for (moduleId, binaryModulePath) in externalTargetModulePathMap {
let modPath = TextualVirtualPath(path: VirtualPath.absolute(binaryModulePath).intern())
placeholderArtifacts.append(
SwiftModuleArtifactInfo(name: moduleId.moduleName,
modulePath: modPath))
}

// All other already-scanned Swift modules
for (moduleId, moduleInfo) in externalModuleInfoMap
where !externalTargetModulePathMap.keys.contains(moduleId) {
guard case .swift(_) = moduleId else { continue }
placeholderArtifacts.append(
SwiftModuleArtifactInfo(name: moduleId.moduleName,
modulePath: moduleInfo.modulePath))
}
let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted]
let contents = try encoder.encode(placeholderArtifacts)
return VirtualPath.createUniqueTemporaryFileWithKnownContents(.init("\(moduleOutputInfo.name)-placeholder-modules.json"),
contents)
}

/// Returns false if the lib is available and ready to use
private func initSwiftScanLib() throws -> Bool {
// If `-nonlib-dependency-scanner` was specified or the libSwiftScan library cannot be found,
Expand Down
Loading