Skip to content

[Explicit Module Builds][Target Variant] Refactor build planning to allow for a second, separate emit-module task for the target variant #1856

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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 @@ -85,7 +85,6 @@ add_library(SwiftDriver
Jobs/InterpretJob.swift
Jobs/Job.swift
Jobs/LinkJob.swift
Jobs/MergeModuleJob.swift
Jobs/ModuleWrapJob.swift
Jobs/Planning.swift
Jobs/PrintTargetInfoJob.swift
Expand Down
79 changes: 19 additions & 60 deletions Sources/SwiftDriver/Driver/Driver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public struct Driver {
case cannotSpecify_OForMultipleOutputs
case conflictingOptions(Option, Option)
case unableToLoadOutputFileMap(String, String)
case malformedChainedBridgingHeader(String)
case unableToDecodeFrontendTargetInfo(String?, [String], String)
case failedToRetrieveFrontendTargetInfo
case failedToRunFrontendToRetrieveTargetInfo(Int, String?)
Expand Down Expand Up @@ -111,6 +112,8 @@ public struct Driver {
return "failed to retrieve frontend target info"
case .unableToReadFrontendTargetInfo:
return "could not read frontend target info"
case .malformedChainedBridgingHeader(let content):
return "could not convert bridging header content to utf-8: \(content)"
case let .failedToRunFrontendToRetrieveTargetInfo(returnCode, stderr):
return "frontend job retrieving target info failed with code \(returnCode)"
+ (stderr.map {": \($0)"} ?? "")
Expand Down Expand Up @@ -330,7 +333,7 @@ public struct Driver {
case .relative(let path):
let cwd = workingDirectory ?? fileSystem.currentWorkingDirectory
return cwd.map { AbsolutePath($0, path) }
case .standardInput, .standardOutput, .temporary, .temporaryWithKnownContents, .fileList:
case .standardInput, .standardOutput, .temporary, .temporaryWithKnownContents, .fileList, .buildArtifactWithKnownContents:
fatalError("Frontend target information will never include a path of this type.")
}
}
Expand All @@ -341,38 +344,15 @@ public struct Driver {
/// Original ObjC Header passed from command-line
let originalObjCHeaderFile: VirtualPath.Handle?


/// Enable bridging header chaining.
let bridgingHeaderChaining: Bool

/// The path to the imported Objective-C header.
lazy var importedObjCHeader: VirtualPath.Handle? = {
assert(explicitDependencyBuildPlanner != nil ||
!parsedOptions.hasArgument(.driverExplicitModuleBuild) ||
!inputFiles.contains { $0.type == .swift },
"should not be queried before scanning")
let chainedBridgingHeader = try? explicitDependencyBuildPlanner?.getChainedBridgingHeaderFile()
return try? computeImportedObjCHeader(&parsedOptions, compilerMode: compilerMode,
chainedBridgingHeader: chainedBridgingHeader) ?? originalObjCHeaderFile
}()

/// The directory to emit PCH file.
lazy var bridgingPrecompiledHeaderOutputDir: VirtualPath? = {
return try? computePrecompiledBridgingHeaderDir(&parsedOptions,
compilerMode: compilerMode)
}()

/// The path to the pch for the imported Objective-C header.
lazy var bridgingPrecompiledHeader: VirtualPath.Handle? = {
let contextHash = try? explicitDependencyBuildPlanner?.getMainModuleContextHash()
return computeBridgingPrecompiledHeader(&parsedOptions,
compilerMode: compilerMode,
importedObjCHeader: importedObjCHeader,
outputFileMap: outputFileMap,
outputDirectory: bridgingPrecompiledHeaderOutputDir,
contextHash: contextHash)
}()

/// Path to the dependencies file.
let dependenciesFilePath: VirtualPath.Handle?

Expand Down Expand Up @@ -621,14 +601,6 @@ public struct Driver {
/// The mode the API digester should run in.
let digesterMode: DigesterMode

// FIXME: We should soon be able to remove this from being in the Driver's state.
// Its only remaining use outside of actual dependency build planning is in
// command-line input option generation for the explicit main module compile job.
/// Planner for constructing module build jobs using Explicit Module Builds.
/// Constructed during the planning phase only when all module dependencies will be prebuilt and treated
/// as explicit inputs by the various compilation jobs.
@_spi(Testing) public var explicitDependencyBuildPlanner: ExplicitDependencyBuildPlanner? = nil

/// A reference to the instance of libSwiftScan which is shared with the driver's
/// `InterModuleDependencyOracle`, but also used for non-scanning tasks, such as target info
/// and supported compiler feature queries
Expand Down Expand Up @@ -1365,9 +1337,9 @@ public struct Driver {
}

public mutating func planBuild() throws -> [Job] {
let (jobs, incrementalCompilationState, intermoduleDependencyGraph) = try planPossiblyIncrementalBuild()
let (jobs, incrementalCompilationState, explicitModulePlanner) = try planPossiblyIncrementalBuild()
self.incrementalCompilationState = incrementalCompilationState
self.intermoduleDependencyGraph = intermoduleDependencyGraph
self.intermoduleDependencyGraph = explicitModulePlanner?.dependencyGraph
return jobs
}
}
Expand Down Expand Up @@ -1756,11 +1728,9 @@ extension Diagnostic.Message {
}

extension Driver {
func explainModuleDependency(_ explainModuleName: String, allPaths: Bool) throws {
guard let dependencyPlanner = explicitDependencyBuildPlanner else {
fatalError("Cannot explain dependency without Explicit Build Planner")
}
guard let dependencyPaths = try dependencyPlanner.explainDependency(explainModuleName, allPaths: allPaths) else {
func explainModuleDependency(_ explainModuleName: String, allPaths: Bool,
moduleDependencyGraph: InterModuleDependencyGraph) throws {
guard let dependencyPaths = try moduleDependencyGraph.explainDependency(explainModuleName, allPaths: allPaths) else {
diagnosticEngine.emit(.remark("No such module dependency found: '\(explainModuleName)'"))
return
}
Expand Down Expand Up @@ -1832,13 +1802,6 @@ extension Driver {
return
}

// If we're only supposed to explain a dependency on a given module, do so now.
if let explainModuleName = parsedOptions.getLastArgument(.explainModuleDependencyDetailed) {
try explainModuleDependency(explainModuleName.asSingle, allPaths: true)
} else if let explainModuleNameDetailed = parsedOptions.getLastArgument(.explainModuleDependency) {
try explainModuleDependency(explainModuleNameDetailed.asSingle, allPaths: false)
}

if parsedOptions.contains(.driverPrintOutputFileMap) {
if let outputFileMap = self.outputFileMap {
stderrStream.send(outputFileMap.description)
Expand Down Expand Up @@ -2031,7 +1994,7 @@ extension Driver {

// Put bridging header as first input if we have it
let allInputs: [TypedVirtualPath]
if let objcHeader = importedObjCHeader, bridgingPrecompiledHeader != nil {
if let objcHeader = originalObjCHeaderFile {
allInputs = [TypedVirtualPath(file: objcHeader, type: .objcHeader)] + inputFiles
} else {
allInputs = inputFiles
Expand All @@ -2056,10 +2019,7 @@ extension Driver {
// All input action IDs for this action.
var inputIds = [UInt]()

var jobInputs = job.primaryInputs.isEmpty ? job.inputs : job.primaryInputs
if let pchPath = bridgingPrecompiledHeader, job.kind == .compile {
jobInputs.append(TypedVirtualPath(file: pchPath, type: .pch))
}
let jobInputs = job.primaryInputs.isEmpty ? job.inputs : job.primaryInputs
// Collect input job IDs.
for input in jobInputs {
if let id = inputIdMap[input] {
Expand Down Expand Up @@ -3130,15 +3090,14 @@ extension Driver {
chainedBridgingHeader: ChainedBridgingHeaderFile?) throws -> VirtualPath.Handle? {
// handle chained bridging header.
if let chainedHeader = chainedBridgingHeader, !chainedHeader.path.isEmpty {
let path = try VirtualPath(path: chainedHeader.path)
let dirExists = try fileSystem.exists(path.parentDirectory)
if !dirExists, let dirToCreate = path.parentDirectory.absolutePath {
try fileSystem.createDirectory(dirToCreate, recursive: true)
}
try fileSystem.writeFileContents(path,
bytes: ByteString(encodingAsUTF8: chainedHeader.content),
atomically: true)
return path.intern()
let path = try AbsolutePath(validating: chainedHeader.path)
if !fileSystem.exists(path.parentDirectory) {
try fileSystem.createDirectory(path.parentDirectory, recursive: true)
}
guard let headerData = chainedHeader.content.data(using: .utf8) else {
throw Driver.Error.malformedChainedBridgingHeader(chainedHeader.content)
}
return try VirtualPath.createBuildProductFileWithKnownContents(path, headerData).intern()
}
return originalObjCHeaderFile
}
Expand Down
8 changes: 7 additions & 1 deletion Sources/SwiftDriver/Execution/ArgsResolver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public final class ArgsResolver {
try createFileList(path: actualPath, contents: items)
case let .fileList(_, .outputFileMap(map)):
try createFileList(path: actualPath, outputFileMap: map)
case .relative, .absolute, .standardInput, .standardOutput:
case .relative, .absolute, .standardInput, .standardOutput, .buildArtifactWithKnownContents:
fatalError("Not a temporary path.")
}

Expand All @@ -143,6 +143,12 @@ public final class ArgsResolver {
return result
}

// First time resolving a build product with a known path and driver-computed
// contents, write it to the filesystem.
if case let .buildArtifactWithKnownContents(absolutePath, contents) = path {
try fileSystem.writeFileContents(absolutePath, bytes: .init(contents))
}

// Otherwise, return the path.
let result = path.name
pathMapping[path] = result
Expand Down
Loading