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
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ import Foundation
extension Driver {
/// For the current moduleDependencyGraph, plan the order and generate jobs
/// for explicitly building all dependency modules.
mutating func planExplicitModuleDependenciesCompile(dependencyGraph: InterModuleDependencyGraph)
throws -> [Job] {
mutating func planExplicitModuleDependenciesCompile(
dependencyGraph: InterModuleDependencyGraph
) throws -> [Job] {
var jobs: [Job] = []
for (id, moduleInfo) in dependencyGraph.modules {
// The generation of the main module file will be handled elsewhere in the driver.
Expand All @@ -26,23 +27,27 @@ extension Driver {
}
switch id {
case .swift(let moduleName):
let swiftModuleBuildJob = try genSwiftModuleDependencyBuildJob(moduleInfo: moduleInfo,
moduleName: moduleName)
let swiftModuleBuildJob =
try genSwiftModuleDependencyBuildJob(moduleInfo: moduleInfo,
moduleName: moduleName,
dependencyGraph: dependencyGraph)
jobs.append(swiftModuleBuildJob)
case .clang(let moduleName):
let clangModuleBuildJob = try genClangModuleDependencyBuildJob(moduleInfo: moduleInfo,
moduleName: moduleName)
let clangModuleBuildJob =
try genClangModuleDependencyBuildJob(moduleInfo: moduleInfo,
moduleName: moduleName,
dependencyGraph: dependencyGraph)
jobs.append(clangModuleBuildJob)

}
}
return jobs
}

/// For a given swift module dependency, generate a build job
mutating private func genSwiftModuleDependencyBuildJob(moduleInfo: ModuleInfo,
moduleName: String) throws -> Job {
// FIXIT: Needs more error handling
moduleName: String,
dependencyGraph: InterModuleDependencyGraph
) throws -> Job {
guard case .swift(let swiftModuleDetails) = moduleInfo.details else {
throw Error.malformedModuleDependency(moduleName, "no `details` object")
}
Expand All @@ -52,7 +57,18 @@ extension Driver {
TypedVirtualPath(file: try VirtualPath(path: moduleInfo.modulePath), type: .swiftModule)
]
var commandLine: [Job.ArgTemplate] = swiftCompilerPrefixArgs.map { Job.ArgTemplate.flag($0) }
commandLine.appendFlag("-frontend")
// First, take the command line options provided in the dependency information
swiftModuleDetails.commandLine?.forEach { commandLine.appendFlags($0) }

if (swiftModuleDetails.commandLine == nil ||
!swiftModuleDetails.commandLine!.contains("-frontend")) {
commandLine.appendFlag("-frontend")
}

try addModuleDependencies(moduleInfo: moduleInfo,
dependencyGraph: dependencyGraph,
inputs: &inputs,
commandLine: &commandLine)

// Build the .swiftinterfaces file using a list of command line options specified in the
// `details` field.
Expand All @@ -62,7 +78,6 @@ extension Driver {
inputs.append(TypedVirtualPath(file: try VirtualPath(path: moduleInterfacePath),
type: .swiftInterface))
try addCommonModuleOptions(commandLine: &commandLine, outputs: &outputs)
swiftModuleDetails.commandLine?.forEach { commandLine.appendFlag($0) }

return Job(
moduleName: moduleName,
Expand All @@ -76,7 +91,9 @@ extension Driver {

/// For a given clang module dependency, generate a build job
mutating private func genClangModuleDependencyBuildJob(moduleInfo: ModuleInfo,
moduleName: String) throws -> Job {
moduleName: String,
dependencyGraph: InterModuleDependencyGraph
) throws -> Job {
// For clang modules, the Fast Dependency Scanner emits a list of source
// files (with a .modulemap among them), and a list of compile command
// options.
Expand All @@ -89,15 +106,27 @@ extension Driver {
TypedVirtualPath(file: try VirtualPath(path: moduleInfo.modulePath), type: .pcm)
]
var commandLine: [Job.ArgTemplate] = swiftCompilerPrefixArgs.map { Job.ArgTemplate.flag($0) }
commandLine.appendFlag("-frontend")

// First, take the command line options provided in the dependency information
clangModuleDetails.commandLine?.forEach { commandLine.appendFlags($0) }

if (clangModuleDetails.commandLine == nil ||
!clangModuleDetails.commandLine!.contains("-frontend")) {
commandLine.appendFlag("-frontend")
}
commandLine.appendFlags("-emit-pcm", "-module-name", moduleName)

try addModuleDependencies(moduleInfo: moduleInfo,
dependencyGraph: dependencyGraph,
inputs: &inputs,
commandLine: &commandLine)

// The only required input is the .modulemap for this module.
commandLine.append(Job.ArgTemplate.path(try VirtualPath(path: clangModuleDetails.moduleMapPath)))
commandLine.append(Job.ArgTemplate.path(
try VirtualPath(path: clangModuleDetails.moduleMapPath)))
inputs.append(TypedVirtualPath(file: try VirtualPath(path: clangModuleDetails.moduleMapPath),
type: .clangModuleMap))
try addCommonModuleOptions(commandLine: &commandLine, outputs: &outputs)
clangModuleDetails.commandLine?.forEach { commandLine.appendFlags("-Xcc", $0) }

return Job(
moduleName: moduleName,
Expand All @@ -108,4 +137,24 @@ extension Driver {
outputs: outputs
)
}


/// For the specified module, update its command line flags and inputs
/// to use explicitly-built module dependencies.
private func addModuleDependencies(moduleInfo: ModuleInfo,
dependencyGraph: InterModuleDependencyGraph,
inputs: inout [TypedVirtualPath],
commandLine: inout [Job.ArgTemplate]) throws {
// Prohibit the frontend from implicitly building textual modules into binary modules.
commandLine.appendFlags("-disable-implicit-swift-modules", "-Xcc", "-Xclang", "-Xcc",
"-fno-implicit-modules")
for moduleId in moduleInfo.directDependencies {
guard let dependencyInfo = dependencyGraph.modules[moduleId] else {
throw Error.missingModuleDependency(moduleId.moduleName)
}
try addModuleAsExplicitDependency(moduleInfo: dependencyInfo,
dependencyGraph: dependencyGraph,
commandLine: &commandLine, inputs: &inputs)
}
}
}
13 changes: 13 additions & 0 deletions Sources/SwiftDriver/Driver/Driver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ public struct Driver {
case subcommandPassedToDriver
case integratedReplRemoved
case conflictingOptions(Option, Option)
// Explicit Module Build Failures
case malformedModuleDependency(String, String)
case missingModuleDependency(String)
case dependencyScanningFailure(Int, String)

public var description: String {
switch self {
Expand All @@ -69,8 +72,13 @@ public struct Driver {
return "Compiler-internal integrated REPL has been removed; use the LLDB-enhanced REPL instead."
case .conflictingOptions(let one, let two):
return "conflicting options '\(one.spelling)' and '\(two.spelling)'"
// Explicit Module Build Failures
case .malformedModuleDependency(let moduleName, let errorDescription):
return "Malformed Module Dependency: \(moduleName), \(errorDescription)"
case .missingModuleDependency(let moduleName):
return "Missing Module Dependency Info: \(moduleName)"
case .dependencyScanningFailure(let code, let error):
return "Module Dependency Scanner returned with non-zero exit status: \(code), \(error)"
}
}
}
Expand Down Expand Up @@ -200,6 +208,11 @@ public struct Driver {
/// This will force the driver to first emit the module and then run compile jobs.
public var forceEmitModuleInSingleInvocation: Bool = false

/// The module dependency graph, which is populated during the planning phase
/// only when all modules will be prebuilt and treated as explicit by the
/// various compilation jobs.
var interModuleDependencyGraph: InterModuleDependencyGraph? = nil

/// Handler for emitting diagnostics to stderr.
public static let stderrDiagnosticsHandler: DiagnosticsEngine.DiagnosticsHandler = { diagnostic in
let stream = stderrStream
Expand Down
16 changes: 15 additions & 1 deletion Sources/SwiftDriver/Driver/ModuleDependencyScanning.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ extension Driver {
let resolver = try ArgsResolver()
let compilerPath = VirtualPath.absolute(try toolchain.getToolPath(.swiftCompiler))
let tool = try resolver.resolve(.path(compilerPath))
var inputs: [TypedVirtualPath] = []

// Aggregate the fast dependency scanner arguments
var commandLine: [Job.ArgTemplate] = swiftCompilerPrefixArgs.map { Job.ArgTemplate.flag($0) }
Expand All @@ -31,7 +32,9 @@ extension Driver {
if parsedOptions.hasArgument(.parseStdlib) {
commandLine.appendFlag(.disableObjcAttrRequiresFoundationModule)
}
try addCommonFrontendOptions(commandLine: &commandLine)
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs,
bridgingHeaderHandling: .precompiled,
moduleDependencyGraphUse: .dependencyScan)
// FIXME: MSVC runtime flags

// Pass on the input files
Expand All @@ -41,6 +44,17 @@ extension Driver {
let arguments = [tool] + (try commandLine.map { try resolver.resolve($0) })
let scanProcess = try Process.launchProcess(arguments: arguments, env: env)
let result = try scanProcess.waitUntilExit()
// Error on dependency scanning failure
if (result.exitStatus != .terminated(code: 0)) {
var returnCode = 0
switch result.exitStatus {
case .terminated(let code):
returnCode = Int(code)
case .signalled(let signal):
returnCode = Int(signal)
}
throw Error.dependencyScanningFailure(returnCode, try result.utf8stderrOutput())
}
guard let outputData = try? Data(result.utf8Output().utf8) else {
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftDriver/Jobs/CompileJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ extension Driver {
commandLine.appendFlag(.disableObjcAttrRequiresFoundationModule)
}

try addCommonFrontendOptions(commandLine: &commandLine)
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs)
// FIXME: MSVC runtime flags

if parsedOptions.hasArgument(.parseAsLibrary, .emitLibrary) {
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftDriver/Jobs/EmitModuleJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ extension Driver {
inputs.append(input)
}

try addCommonFrontendOptions(commandLine: &commandLine)
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs)
// FIXME: Add MSVC runtime library flags

try addCommonModuleOptions(commandLine: &commandLine, outputs: &outputs)
Expand Down
83 changes: 82 additions & 1 deletion Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,21 @@ extension Driver {
/// Use the precompiled bridging header.
case precompiled
}
/// Whether the driver has already constructed a module dependency graph or is in the process
/// of doing so
enum ModuleDependencyGraphUse {
/// Even though the driver may be in ExplicitModuleBuild mode, the dependency graph has not yet
/// been constructed, omit processing module dependencies
case dependencyScan
/// If the driver is in Explicit Module Build mode, the dependency graph has been computed
case computed
}
/// Add frontend options that are common to different frontend invocations.
mutating func addCommonFrontendOptions(
commandLine: inout [Job.ArgTemplate],
bridgingHeaderHandling: BridgingHeaderHandling = .precompiled
inputs: inout [TypedVirtualPath],
bridgingHeaderHandling: BridgingHeaderHandling = .precompiled,
moduleDependencyGraphUse: ModuleDependencyGraphUse = .computed
) throws {
// Only pass -target to the REPL or immediate modes if it was explicitly
// specified on the command line.
Expand All @@ -54,6 +65,18 @@ extension Driver {
}
}

// If in ExplicitModuleBuild mode and the dependency graph has been computed, add module
// dependencies.
// May also be used for generation of the dependency graph itself in ExplicitModuleBuild mode.
if (parsedOptions.contains(.driverExplicitModuleBuild) &&
moduleDependencyGraphUse == .computed) {
guard let dependencyGraph = interModuleDependencyGraph else {
fatalError("Attempting to add Explicit Module job dependencies, but the Inter Module Dependency Graph does not exist.")
}
try addExplicitModuleBuildArguments(dependencyGraph: dependencyGraph,
commandLine: &commandLine, inputs: &inputs)
}

if let variant = parsedOptions.getLastArgument(.targetVariant)?.asSingle {
commandLine.appendFlag(.targetVariant)
commandLine.appendFlag(Triple(variant, normalizing: true).triple)
Expand Down Expand Up @@ -304,4 +327,62 @@ extension Driver {

return outputs
}

/// Adds the specified module as an explicit module dependency to given
/// inputs and command line arguments of a compile job.
/// Also adds transitive dependencies that arise from dependencies of this module.
func addModuleAsExplicitDependency(moduleInfo: ModuleInfo,
dependencyGraph: InterModuleDependencyGraph,
commandLine: inout [Job.ArgTemplate],
inputs: inout [TypedVirtualPath]) throws {
switch moduleInfo.details {
case .swift:
let swiftModulePath = TypedVirtualPath(file: try VirtualPath(path: moduleInfo.modulePath),
type: .swiftModule)
commandLine.appendFlags("-swift-module-file")
commandLine.appendPath(swiftModulePath.file)
inputs.append(swiftModulePath)
case .clang(let clangDependencyDetails):
let clangModulePath = TypedVirtualPath(file: try VirtualPath(path: moduleInfo.modulePath),
type: .pcm)
let clangModuleMapPath = TypedVirtualPath(file: try VirtualPath(path: clangDependencyDetails.moduleMapPath),
type: .pcm)
commandLine.appendFlags("-Xcc", "-Xclang", "-Xcc",
"-fmodule-map-file=\(clangModuleMapPath.file.description)")
commandLine.appendFlags("-Xcc", "-Xclang", "-Xcc",
"-fmodule-file=\(clangModulePath.file.description)")
inputs.append(clangModulePath)
inputs.append(clangModuleMapPath)
}
// Add transitive dependencies to the command line as well
for transitiveDependencyId in moduleInfo.directDependencies {
guard let transitiveDependencyInfo = dependencyGraph.modules[transitiveDependencyId] else {
throw Error.missingModuleDependency(transitiveDependencyId.moduleName)
}
try addModuleAsExplicitDependency(moduleInfo: transitiveDependencyInfo,
dependencyGraph: dependencyGraph,
commandLine: &commandLine,
inputs: &inputs)
}
}

/// Adds all dependecies required for an explicit module build
/// to inputs and comman line arguments of a compile job.
func addExplicitModuleBuildArguments(dependencyGraph: InterModuleDependencyGraph,
commandLine: inout [Job.ArgTemplate],
inputs: inout [TypedVirtualPath]) throws {
// Prohibit the frontend from implicitly building textual modules into binary modules.
commandLine.appendFlags("-disable-implicit-swift-modules", "-Xcc", "-Xclang", "-Xcc",
"-fno-implicit-modules")

// Provide the frontend with a list of explicitly pre-built modules.
for (moduleId, moduleInfo) in dependencyGraph.modules {
// Skip the main output module as it is not its own dependency
guard moduleId.moduleName != dependencyGraph.mainModuleName else {
continue
}
try addModuleAsExplicitDependency(moduleInfo: moduleInfo, dependencyGraph: dependencyGraph,
commandLine: &commandLine, inputs: &inputs)
}
}
}
2 changes: 1 addition & 1 deletion Sources/SwiftDriver/Jobs/GeneratePCHJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ extension Driver {
commandLine.appendFlag("-frontend")

try addCommonFrontendOptions(
commandLine: &commandLine, bridgingHeaderHandling: .parsed)
commandLine: &commandLine, inputs: &inputs, bridgingHeaderHandling: .parsed)

try commandLine.appendLast(.indexStorePath, from: &parsedOptions)

Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftDriver/Jobs/GeneratePCMJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ extension Driver {
commandLine.appendPath(output.file)

try addCommonFrontendOptions(
commandLine: &commandLine, bridgingHeaderHandling: .ignored)
commandLine: &commandLine, inputs: &inputs, bridgingHeaderHandling: .ignored)

try commandLine.appendLast(.indexStorePath, from: &parsedOptions)

Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftDriver/Jobs/InterpretJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ extension Driver {
commandLine.appendFlag(.disableObjcAttrRequiresFoundationModule)
}

try addCommonFrontendOptions(commandLine: &commandLine)
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs)
// FIXME: MSVC runtime flags

try commandLine.appendLast(.parseSil, from: &parsedOptions)
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftDriver/Jobs/MergeModuleJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ extension Driver {
commandLine.appendFlag(.disableDiagnosticPasses)
commandLine.appendFlag(.disableSilPerfOptzns)

try addCommonFrontendOptions(commandLine: &commandLine)
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs)
// FIXME: Add MSVC runtime library flags

try addCommonModuleOptions(commandLine: &commandLine, outputs: &outputs)
Expand Down
Loading