Skip to content

Commit 90bb63e

Browse files
committed
[Explicit Module Builds] Rely on the dependency scanner to produce complete compile commands for Swift dependencies
This change removes instances where the driver modified command-line invocations used to build Swift module dependencies, as produced by the dependency scanner. Instead, the scanner will now emit command lines that are sufficient to build all such module dependencies, including explicit dependency inputs.
1 parent 65e0b28 commit 90bb63e

File tree

3 files changed

+69
-137
lines changed

3 files changed

+69
-137
lines changed

Sources/SwiftDriver/ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift

Lines changed: 28 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -162,24 +162,11 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
162162
// Add precompiled module candidates, if present
163163
if let compiledCandidateList = moduleDetails.compiledModuleCandidates {
164164
for compiledCandidate in compiledCandidateList {
165-
commandLine.appendFlag("-candidate-module-file")
166-
let compiledCandidatePath = compiledCandidate
167-
commandLine.appendPath(VirtualPath.lookup(compiledCandidatePath.path))
168-
inputs.append(TypedVirtualPath(file: compiledCandidatePath.path,
165+
inputs.append(TypedVirtualPath(file: compiledCandidate.path,
169166
type: .swiftModule))
170167
}
171168
}
172169

173-
if supportsExplicitInterfaceBuild {
174-
// Ensure the compiler flags specified in the interface are ignored
175-
// because they are already captured in the dependency scanner output
176-
commandLine.appendFlag(.explicitInterfaceModuleBuild)
177-
}
178-
179-
// Set the output path
180-
commandLine.appendFlag(.o)
181-
commandLine.appendPath(VirtualPath.lookup(moduleInfo.modulePath.path))
182-
183170
jobs.append(Job(
184171
moduleName: moduleId.moduleName,
185172
kind: .compileModuleFromInterface,
@@ -232,23 +219,6 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
232219
let moduleMapPath = moduleDetails.moduleMapPath.path
233220
let modulePCMPath = moduleInfo.modulePath
234221
outputs.append(TypedVirtualPath(file: modulePCMPath.path, type: .pcm))
235-
236-
// TODO: Remove this once toolchain is updated
237-
// If the dependency scanner did not append its own "-o", add it here.
238-
// This is temporary and is meant to handle both: the scanner that
239-
// appends '-o' and one that doesn't, until we have a toolchain snapshot with the scanner
240-
// that appends '-o' always.
241-
let outputFlagIndeces = commandLine.enumerated().compactMap { $1 == .flag("-o") ? $0 : nil }
242-
// One '-o' is expected as an `-Xcc` flag.
243-
if outputFlagIndeces.count <= 1 {
244-
commandLine.appendFlags("-o", modulePCMPath.path.description)
245-
}
246-
247-
// TODO: Remove this once toolchain is updated
248-
// Fixup "-o -Xcc '<replace-me>'"
249-
if let outputIndex = commandLine.firstIndex(of: .flag("<replace-me>")) {
250-
commandLine[outputIndex] = .path(VirtualPath.lookup(modulePCMPath.path))
251-
}
252222

253223
// The only required input is the .modulemap for this module.
254224
// Command line options in the dependency scanner output will include the
@@ -276,31 +246,19 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
276246
inputs: inout [TypedVirtualPath],
277247
commandLine: inout [Job.ArgTemplate]) throws {
278248
// Prohibit the frontend from implicitly building textual modules into binary modules.
279-
commandLine.appendFlags("-disable-implicit-swift-modules",
280-
"-Xcc", "-fno-implicit-modules",
281-
"-Xcc", "-fno-implicit-module-maps")
282249
var swiftDependencyArtifacts: [SwiftModuleArtifactInfo] = []
283250
var clangDependencyArtifacts: [ClangModuleArtifactInfo] = []
284251
try addModuleDependencies(moduleId: moduleId, pcmArgs: pcmArgs,
285252
clangDependencyArtifacts: &clangDependencyArtifacts,
286253
swiftDependencyArtifacts: &swiftDependencyArtifacts)
287254

288-
// Swift Module dependencies are passed encoded in a JSON file as described by
289-
// SwiftModuleArtifactInfo
290-
if !swiftDependencyArtifacts.isEmpty {
291-
let dependencyFile =
292-
try serializeModuleDependencies(for: moduleId, dependencyArtifacts: swiftDependencyArtifacts)
293-
commandLine.appendFlag("-explicit-swift-module-map-file")
294-
commandLine.appendPath(dependencyFile)
295-
inputs.append(TypedVirtualPath(file: dependencyFile.intern(),
296-
type: .jsonSwiftArtifacts))
297-
// Each individual module binary is still an "input" to ensure the build system gets the
298-
// order correctly.
299-
for dependencyModule in swiftDependencyArtifacts {
300-
inputs.append(TypedVirtualPath(file: dependencyModule.modulePath.path,
301-
type: .swiftModule))
302-
}
255+
// Each individual module binary is still an "input" to ensure the build system gets the
256+
// order correctly.
257+
for dependencyModule in swiftDependencyArtifacts {
258+
inputs.append(TypedVirtualPath(file: dependencyModule.modulePath.path,
259+
type: .swiftModule))
303260
}
261+
304262
// Clang module dependencies are specified on the command line explicitly
305263
for moduleArtifactInfo in clangDependencyArtifacts {
306264
let clangModulePath =
@@ -311,18 +269,19 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
311269
type: .clangModuleMap)
312270
inputs.append(clangModulePath)
313271
inputs.append(clangModuleMapPath)
272+
}
314273

315-
// If an existing dependency module path stub exists, replace it.
316-
if let existingIndex = commandLine.firstIndex(of: .flag("-fmodule-file=" + moduleArtifactInfo.moduleName + "=<replace-me>")) {
317-
commandLine[existingIndex] = .flag("-fmodule-file=\(moduleArtifactInfo.moduleName)=\(clangModulePath.file.description)")
318-
} else if case .swift(_) = moduleId {
319-
commandLine.appendFlags("-Xcc",
320-
"-fmodule-file=\(moduleArtifactInfo.moduleName)=\(clangModulePath.file.description)")
321-
}
322-
if case .swift(_) = moduleId {
323-
commandLine.appendFlags("-Xcc",
324-
"-fmodule-map-file=\(clangModuleMapPath.file.description)")
325-
}
274+
// Swift Main Module dependencies are passed encoded in a JSON file as described by
275+
// SwiftModuleArtifactInfo
276+
if moduleId.moduleName == mainModuleName {
277+
let dependencyFile =
278+
try serializeModuleDependencies(for: moduleId,
279+
swiftDependencyArtifacts: swiftDependencyArtifacts,
280+
clangDependencyArtifacts: clangDependencyArtifacts)
281+
commandLine.appendFlag("-explicit-swift-module-map-file")
282+
commandLine.appendPath(dependencyFile)
283+
inputs.append(TypedVirtualPath(file: dependencyFile.intern(),
284+
type: .jsonSwiftArtifacts))
326285
}
327286
}
328287

@@ -401,6 +360,9 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
401360
public mutating func resolveMainModuleDependencies(inputs: inout [TypedVirtualPath],
402361
commandLine: inout [Job.ArgTemplate]) throws {
403362
let mainModuleId: ModuleDependencyId = .swift(dependencyGraph.mainModuleName)
363+
commandLine.appendFlags("-disable-implicit-swift-modules",
364+
"-Xcc", "-fno-implicit-modules",
365+
"-Xcc", "-fno-implicit-module-maps")
404366
try resolveExplicitModuleDependencies(moduleId: mainModuleId,
405367
pcmArgs:
406368
try dependencyGraph.swiftModulePCMArgs(of: mainModuleId),
@@ -410,11 +372,15 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
410372

411373
/// Store the output file artifacts for a given module in a JSON file, return the file's path.
412374
private func serializeModuleDependencies(for moduleId: ModuleDependencyId,
413-
dependencyArtifacts: [SwiftModuleArtifactInfo]
375+
swiftDependencyArtifacts: [SwiftModuleArtifactInfo],
376+
clangDependencyArtifacts: [ClangModuleArtifactInfo]
414377
) throws -> VirtualPath {
378+
let allDependencyArtifacts: [ModuleDependencyArtifactInfo] =
379+
swiftDependencyArtifacts.map {ModuleDependencyArtifactInfo($0)} +
380+
clangDependencyArtifacts.map {ModuleDependencyArtifactInfo($0)}
415381
let encoder = JSONEncoder()
416382
encoder.outputFormatting = [.prettyPrinted]
417-
let contents = try encoder.encode(dependencyArtifacts)
383+
let contents = try encoder.encode(allDependencyArtifacts)
418384
return VirtualPath.createUniqueTemporaryFileWithKnownContents(.init("\(moduleId.moduleName)-dependencies.json"), contents)
419385
}
420386

Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift

Lines changed: 0 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,6 @@ extension Diagnostic.Message {
6262
// This is currently disabled because we are investigating it being unnecessary
6363
// try resolveVersionedClangDependencies(dependencyGraph: &dependencyGraph)
6464

65-
// Set dependency modules' paths to be saved in the module cache.
66-
try resolveDependencyModulePaths(dependencyGraph: &dependencyGraph)
67-
6865
if parsedOptions.hasArgument(.printExplicitDependencyGraph) {
6966
let outputFormat = parsedOptions.getLastArgument(.explicitDependencyGraphFormat)?.asSingle
7067
if outputFormat == nil || outputFormat == "json" {
@@ -77,78 +74,6 @@ extension Diagnostic.Message {
7774

7875
return dependencyGraph
7976
}
80-
81-
/// Update the given inter-module dependency graph to set module paths to be within the module cache,
82-
/// if one is present, and for Swift modules to use the context hash in the file name.
83-
private mutating func resolveDependencyModulePaths(dependencyGraph: inout InterModuleDependencyGraph)
84-
throws {
85-
// If a module cache path is specified, update all module dependencies
86-
// to be output into it.
87-
if let moduleCachePath = parsedOptions.getLastArgument(.moduleCachePath)?.asSingle {
88-
try resolveDependencyModulePathsRelativeToModuleCache(dependencyGraph: &dependencyGraph,
89-
moduleCachePath: moduleCachePath)
90-
}
91-
92-
// Set the output path to include the module's context hash
93-
try resolveDependencyModuleFileNamesWithContextHash(dependencyGraph: &dependencyGraph)
94-
}
95-
96-
/// For Swift module dependencies, set the output path to include the module's context hash
97-
private mutating func resolveDependencyModuleFileNamesWithContextHash(dependencyGraph: inout InterModuleDependencyGraph)
98-
throws {
99-
for (moduleId, moduleInfo) in dependencyGraph.modules {
100-
// Output path on the main module is determined by the invocation arguments.
101-
guard moduleId.moduleName != dependencyGraph.mainModuleName else {
102-
continue
103-
}
104-
105-
let plainPath = VirtualPath.lookup(dependencyGraph.modules[moduleId]!.modulePath.path)
106-
if case .swift(let swiftDetails) = moduleInfo.details {
107-
guard let contextHash = swiftDetails.contextHash else {
108-
throw Driver.Error.missingContextHashOnSwiftDependency(moduleId.moduleName)
109-
}
110-
let updatedPath = plainPath.parentDirectory.appending(component: "\(plainPath.basenameWithoutExt)-\(contextHash).\(plainPath.extension!)")
111-
dependencyGraph.modules[moduleId]!.modulePath = TextualVirtualPath(path: updatedPath.intern())
112-
}
113-
// TODO: Remove this once toolchain is updated
114-
else if case .clang(let clangDetails) = moduleInfo.details {
115-
if !moduleInfo.modulePath.path.description.contains(clangDetails.contextHash) {
116-
let contextHash = clangDetails.contextHash
117-
let updatedPath = plainPath.parentDirectory.appending(component: "\(plainPath.basenameWithoutExt)-\(contextHash).\(plainPath.extension!)")
118-
dependencyGraph.modules[moduleId]!.modulePath = TextualVirtualPath(path: updatedPath.intern())
119-
}
120-
}
121-
}
122-
}
123-
124-
/// Resolve all paths to dependency binary module files to be relative to the module cache path.
125-
private mutating func resolveDependencyModulePathsRelativeToModuleCache(dependencyGraph: inout InterModuleDependencyGraph,
126-
moduleCachePath: String)
127-
throws {
128-
for (moduleId, moduleInfo) in dependencyGraph.modules {
129-
// Output path on the main module is determined by the invocation arguments.
130-
if case .swift(let name) = moduleId {
131-
if name == dependencyGraph.mainModuleName {
132-
continue
133-
}
134-
let modulePath = VirtualPath.lookup(moduleInfo.modulePath.path)
135-
// Use VirtualPath to get the OS-specific path separators right.
136-
let modulePathInCache =
137-
try VirtualPath(path: moduleCachePath).appending(component: modulePath.basename)
138-
dependencyGraph.modules[moduleId]!.modulePath =
139-
TextualVirtualPath(path: modulePathInCache.intern())
140-
}
141-
// TODO: Remove this once toolchain is updated
142-
else if case .clang(_) = moduleId {
143-
let modulePath = VirtualPath.lookup(moduleInfo.modulePath.path)
144-
// Use VirtualPath to get the OS-specific path separators right.
145-
let modulePathInCache =
146-
try VirtualPath(path: moduleCachePath).appending(component: modulePath.basename)
147-
dependencyGraph.modules[moduleId]!.modulePath =
148-
TextualVirtualPath(path: modulePathInCache.intern())
149-
}
150-
}
151-
}
15277
}
15378

15479
public extension Driver {

Sources/SwiftDriver/ExplicitModuleBuilds/SerializableModuleArtifacts.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,47 @@
5656
}
5757
}
5858

59+
struct ModuleDependencyArtifactInfo: Codable {
60+
/// The module's name.
61+
public let moduleName: String
62+
/// The path for the module's .swiftmodule file (nil for Clang modules)
63+
public let modulePath: TextualVirtualPath?
64+
/// The path for the module's .swiftdoc file
65+
public let docPath: TextualVirtualPath?
66+
/// The path for the module's .swiftsourceinfo file
67+
public let sourceInfoPath: TextualVirtualPath?
68+
/// A flag to indicate whether this module is a framework
69+
public let isFramework: Bool
70+
// A flag to indicate whether this is a system framework
71+
public let isSystem: Bool
72+
/// Path of the Clang module map file (nil for all Swift modules)
73+
public let clangModuleMapPath: TextualVirtualPath?
74+
/// Path of a compiled Clang explicit module file (nil for all Swift modules)
75+
public let clangModulePath: TextualVirtualPath?
76+
77+
init(_ swiftModuleArtifactInfo: SwiftModuleArtifactInfo) {
78+
self.moduleName = swiftModuleArtifactInfo.moduleName
79+
self.modulePath = swiftModuleArtifactInfo.modulePath
80+
self.docPath = swiftModuleArtifactInfo.docPath
81+
self.sourceInfoPath = swiftModuleArtifactInfo.sourceInfoPath
82+
self.isFramework = swiftModuleArtifactInfo.isFramework
83+
self.isSystem = false
84+
self.clangModuleMapPath = nil
85+
self.clangModulePath = nil
86+
}
87+
88+
init(_ clangModuleArtifactInfo: ClangModuleArtifactInfo) {
89+
self.moduleName = clangModuleArtifactInfo.moduleName
90+
self.modulePath = nil
91+
self.docPath = nil
92+
self.sourceInfoPath = nil
93+
self.isFramework = false
94+
self.isSystem = false
95+
self.clangModuleMapPath = clangModuleArtifactInfo.moduleMapPath
96+
self.clangModulePath = clangModuleArtifactInfo.modulePath
97+
}
98+
}
99+
59100
/// Describes a given module's batch dependency scanning input info
60101
/// - Module Name
61102
/// - Extra PCM build arguments (for Clang modules only)

0 commit comments

Comments
 (0)