Skip to content

Commit 5bb1359

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 5bb1359

File tree

3 files changed

+52
-143
lines changed

3 files changed

+52
-143
lines changed

Sources/SwiftDriver/ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift

Lines changed: 30 additions & 64 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,53 +246,42 @@ 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 =
307-
TypedVirtualPath(file: moduleArtifactInfo.modulePath.path,
265+
TypedVirtualPath(file: moduleArtifactInfo.clangModulePath.path,
308266
type: .pcm)
309267
let clangModuleMapPath =
310-
TypedVirtualPath(file: moduleArtifactInfo.moduleMapPath.path,
268+
TypedVirtualPath(file: moduleArtifactInfo.clangModuleMapPath.path,
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.swift($0)} +
380+
clangDependencyArtifacts.map {ModuleDependencyArtifactInfo.clang($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: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,32 @@
4545
/// The module's name
4646
public let moduleName: String
4747
/// The path for the module's .pcm file
48-
public let modulePath: TextualVirtualPath
48+
public let clangModulePath: TextualVirtualPath
4949
/// The path for this module's .modulemap file
50-
public let moduleMapPath: TextualVirtualPath
50+
public let clangModuleMapPath: TextualVirtualPath
51+
/// A flag to indicate whether this module is a framework
52+
public let isFramework: Bool
5153

5254
init(name: String, modulePath: TextualVirtualPath, moduleMapPath: TextualVirtualPath) {
5355
self.moduleName = name
54-
self.modulePath = modulePath
55-
self.moduleMapPath = moduleMapPath
56+
self.clangModulePath = modulePath
57+
self.clangModuleMapPath = moduleMapPath
58+
self.isFramework = false
59+
}
60+
}
61+
62+
enum ModuleDependencyArtifactInfo: Codable {
63+
case clang(ClangModuleArtifactInfo)
64+
case swift(SwiftModuleArtifactInfo)
65+
66+
func encode(to encoder: Encoder) throws {
67+
var container = encoder.singleValueContainer()
68+
switch self {
69+
case .swift(let swiftInfo):
70+
try container.encode(swiftInfo)
71+
case .clang(let clangInfo):
72+
try container.encode(clangInfo)
73+
}
5674
}
5775
}
5876

0 commit comments

Comments
 (0)