Skip to content

Commit 1009e66

Browse files
committed
PrebuiltModuleGen: teach the tool to dump a .dot file for module dependency visualization
1 parent 3f5f55a commit 1009e66

File tree

2 files changed

+64
-2
lines changed

2 files changed

+64
-2
lines changed

Sources/SwiftDriver/Jobs/PrebuiltModulesJob.swift

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,14 +283,68 @@ extension Driver {
283283
)
284284
}
285285

286+
287+
func dumpDotGraph(_ graph: InterModuleDependencyGraph, _ path: AbsolutePath, _ includingPCM: Bool) throws {
288+
func isPCM(_ dep: ModuleDependencyId) -> Bool {
289+
switch dep {
290+
case .clang:
291+
return true
292+
default:
293+
return false
294+
}
295+
}
296+
func dumpModuleName(_ stream: WritableByteStream, _ dep: ModuleDependencyId) {
297+
switch dep {
298+
case .swift(let name):
299+
stream <<< "\"\(name).swiftmodule\""
300+
case .clang(let name):
301+
stream <<< "\"\(name).pcm\""
302+
default:
303+
break
304+
}
305+
}
306+
try localFileSystem.writeFileContents(path) {Stream in
307+
Stream <<< "digraph {\n"
308+
for key in graph.modules.keys {
309+
switch key {
310+
case .swift(let name):
311+
if name == graph.mainModuleName {
312+
break
313+
}
314+
fallthrough
315+
case .clang:
316+
if !includingPCM && isPCM(key) {
317+
break
318+
}
319+
graph.modules[key]!.directDependencies?.forEach { dep in
320+
if !includingPCM && isPCM(dep) {
321+
return
322+
}
323+
dumpModuleName(Stream, key)
324+
Stream <<< " -> "
325+
dumpModuleName(Stream, dep)
326+
Stream <<< ";\n"
327+
}
328+
default:
329+
break
330+
}
331+
}
332+
Stream <<< "}\n"
333+
}
334+
}
335+
286336
public mutating func generatePrebuitModuleGenerationJobs(with inputMap: [String: [PrebuiltModuleInput]],
287337
into prebuiltModuleDir: AbsolutePath,
288-
exhaustive: Bool) throws -> ([Job], [Job]) {
338+
exhaustive: Bool,
339+
dotGraphPath: AbsolutePath? = nil) throws -> ([Job], [Job]) {
289340
assert(sdkPath != nil)
290341
// Run the dependency scanner and update the dependency oracle with the results
291342
// We only need Swift dependencies here, so we don't need to invoke gatherModuleDependencies,
292343
// which also resolves versioned clang modules.
293344
let dependencyGraph = try performDependencyScan()
345+
if let dotGraphPath = dotGraphPath {
346+
try dumpDotGraph(dependencyGraph, dotGraphPath, false)
347+
}
294348
var jobs: [Job] = []
295349
var danglingJobs: [Job] = []
296350
var inputCount = 0

Sources/swift-build-sdk-interfaces/main.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ func getArgument(_ flag: String) -> String? {
3232
return nil
3333
}
3434

35+
func getArgumentAsPath(_ flag: String) throws -> AbsolutePath? {
36+
if let raw = getArgument(flag) {
37+
return try VirtualPath(path: raw).absolutePath
38+
}
39+
return nil
40+
}
41+
3542
guard let rawOutputDir = getArgument("-o") else {
3643
diagnosticsEngine.emit(.error("need to specify -o"))
3744
exit(1)
@@ -119,7 +126,8 @@ do {
119126
diagnosticsEngine: diagnosticsEngine,
120127
executor: executor,
121128
compilerExecutableDir: swiftcPath.parentDirectory)
122-
let (jobs, danglingJobs) = try driver.generatePrebuitModuleGenerationJobs(with: inputMap, into: outputDir, exhaustive: !coreMode)
129+
let (jobs, danglingJobs) = try driver.generatePrebuitModuleGenerationJobs(with: inputMap,
130+
into: outputDir, exhaustive: !coreMode, dotGraphPath: getArgumentAsPath("-dot-graph-path"))
123131
if verbose {
124132
Driver.stdErrQueue.sync {
125133
stderrStream <<< "job count: \(jobs.count + danglingJobs.count)\n"

0 commit comments

Comments
 (0)