@@ -24,33 +24,40 @@ public class PrebuitModuleGenerationDelegate: JobExecutionDelegate {
24
24
let diagnosticsEngine : DiagnosticsEngine
25
25
let verbose : Bool
26
26
var failingCriticalOutputs : Set < VirtualPath >
27
- public init ( _ jobs: [ Job ] , _ diagnosticsEngine: DiagnosticsEngine , _ verbose: Bool ) {
27
+ let logPath : AbsolutePath ?
28
+ public init ( _ jobs: [ Job ] , _ diagnosticsEngine: DiagnosticsEngine , _ verbose: Bool , logPath: AbsolutePath ? ) {
28
29
self . diagnosticsEngine = diagnosticsEngine
29
30
self . verbose = verbose
30
31
self . failingCriticalOutputs = Set < VirtualPath > ( jobs. compactMap ( PrebuitModuleGenerationDelegate . getCriticalOutput) )
32
+ self . logPath = logPath
31
33
}
32
34
33
35
/// Dangling jobs are macabi-only modules. We should run those jobs if foundation
34
36
/// is built successfully for macabi.
35
37
public var shouldRunDanglingJobs : Bool {
36
38
return !failingCriticalOutputs. contains ( where: isIosMac)
37
39
}
38
- func printJobInfo( _ job: Job , _ start: Bool ) {
39
- guard verbose else {
40
- return
41
- }
40
+
41
+ func getInputInterfacePath( _ job: Job ) -> AbsolutePath {
42
42
for arg in job. commandLine {
43
43
if case . path( let p) = arg {
44
44
if p. extension == " swiftinterface " {
45
- Driver . stdErrQueue. sync {
46
- stderrStream <<< ( start ? " started: " : " finished: " )
47
- stderrStream <<< p. absolutePath!. pathString <<< " \n "
48
- stderrStream. flush ( )
49
- }
50
- return
45
+ return p. absolutePath!
51
46
}
52
47
}
53
48
}
49
+ fatalError ( )
50
+ }
51
+
52
+ func printJobInfo( _ job: Job , _ start: Bool ) {
53
+ guard verbose else {
54
+ return
55
+ }
56
+ Driver . stdErrQueue. sync {
57
+ stderrStream <<< ( start ? " started: " : " finished: " )
58
+ stderrStream <<< getInputInterfacePath ( job) . pathString <<< " \n "
59
+ stderrStream. flush ( )
60
+ }
54
61
}
55
62
56
63
static func getCriticalOutput( _ job: Job ) -> VirtualPath ? {
@@ -66,6 +73,24 @@ public class PrebuitModuleGenerationDelegate: JobExecutionDelegate {
66
73
return !failingCriticalOutputs. isEmpty
67
74
}
68
75
76
+ fileprivate func logOutput( _ job: Job , _ result: ProcessResult , _ stdout: Bool ) throws {
77
+ guard let logPath = logPath else {
78
+ return
79
+ }
80
+ let content = stdout ? try result. utf8Output ( ) : try result. utf8stderrOutput ( )
81
+ guard !content. isEmpty else {
82
+ return
83
+ }
84
+ if !localFileSystem. exists ( logPath) {
85
+ try localFileSystem. createDirectory ( logPath, recursive: true )
86
+ }
87
+ let interfaceBase = getInputInterfacePath ( job) . basenameWithoutExt
88
+ let fileName = " \( job. moduleName) - \( interfaceBase) - \( stdout ? " out " : " err " ) .txt "
89
+ try localFileSystem. writeFileContents ( logPath. appending ( component: fileName) ) {
90
+ $0 <<< content
91
+ }
92
+ }
93
+
69
94
public func jobFinished( job: Job , result: ProcessResult , pid: Int ) {
70
95
switch result. exitStatus {
71
96
case . terminated( code: let code) :
@@ -86,6 +111,15 @@ public class PrebuitModuleGenerationDelegate: JobExecutionDelegate {
86
111
diagnosticsEngine. emit ( . remark( " \( job. moduleName) interrupted " ) )
87
112
#endif
88
113
}
114
+ do {
115
+ try logOutput ( job, result, true )
116
+ try logOutput ( job, result, false )
117
+ } catch {
118
+ Driver . stdErrQueue. sync {
119
+ stderrStream <<< " Failed to generate log file "
120
+ stderrStream. flush ( )
121
+ }
122
+ }
89
123
}
90
124
91
125
public func jobSkipped( job: Job ) {
@@ -236,6 +270,57 @@ public struct SDKPrebuiltModuleInputsCollector {
236
270
}
237
271
}
238
272
273
+ extension InterModuleDependencyGraph {
274
+ func dumpDotGraph( _ path: AbsolutePath , _ includingPCM: Bool ) throws {
275
+ func isPCM( _ dep: ModuleDependencyId ) -> Bool {
276
+ switch dep {
277
+ case . clang:
278
+ return true
279
+ default :
280
+ return false
281
+ }
282
+ }
283
+ func dumpModuleName( _ stream: WritableByteStream , _ dep: ModuleDependencyId ) {
284
+ switch dep {
285
+ case . swift( let name) :
286
+ stream <<< " \" \( name) .swiftmodule \" "
287
+ case . clang( let name) :
288
+ stream <<< " \" \( name) .pcm \" "
289
+ default :
290
+ break
291
+ }
292
+ }
293
+ try localFileSystem. writeFileContents ( path) { Stream in
294
+ Stream <<< " digraph { \n "
295
+ for key in modules. keys {
296
+ switch key {
297
+ case . swift( let name) :
298
+ if name == mainModuleName {
299
+ break
300
+ }
301
+ fallthrough
302
+ case . clang:
303
+ if !includingPCM && isPCM ( key) {
304
+ break
305
+ }
306
+ modules [ key] !. directDependencies? . forEach { dep in
307
+ if !includingPCM && isPCM ( dep) {
308
+ return
309
+ }
310
+ dumpModuleName ( Stream, key)
311
+ Stream <<< " -> "
312
+ dumpModuleName ( Stream, dep)
313
+ Stream <<< " ; \n "
314
+ }
315
+ default :
316
+ break
317
+ }
318
+ }
319
+ Stream <<< " } \n "
320
+ }
321
+ }
322
+ }
323
+
239
324
extension Driver {
240
325
241
326
private mutating func generateSingleModuleBuildingJob( _ moduleName: String , _ prebuiltModuleDir: AbsolutePath ,
@@ -261,7 +346,14 @@ extension Driver {
261
346
commandLine. appendFlag ( . Fsystem)
262
347
commandLine. append ( . path( iosMacFrameworksSearchPath) )
263
348
}
349
+ // Use the specified module cache dir
350
+ if let mcp = parsedOptions. getLastArgument ( . moduleCachePath) ? . asSingle {
351
+ commandLine. appendFlag ( . moduleCachePath)
352
+ commandLine. append ( . path( try VirtualPath ( path: mcp) ) )
353
+ }
264
354
commandLine. appendFlag ( . serializeParseableModuleInterfaceDependencyHashes)
355
+ commandLine. appendFlag ( . badFileDescriptorRetryCount)
356
+ commandLine. appendFlag ( " 30 " )
265
357
return Job (
266
358
moduleName: moduleName,
267
359
kind: . compile,
@@ -275,12 +367,16 @@ extension Driver {
275
367
276
368
public mutating func generatePrebuitModuleGenerationJobs( with inputMap: [ String : [ PrebuiltModuleInput ] ] ,
277
369
into prebuiltModuleDir: AbsolutePath ,
278
- exhaustive: Bool ) throws -> ( [ Job ] , [ Job ] ) {
370
+ exhaustive: Bool ,
371
+ dotGraphPath: AbsolutePath ? = nil ) throws -> ( [ Job ] , [ Job ] ) {
279
372
assert ( sdkPath != nil )
280
373
// Run the dependency scanner and update the dependency oracle with the results
281
374
// We only need Swift dependencies here, so we don't need to invoke gatherModuleDependencies,
282
375
// which also resolves versioned clang modules.
283
376
let dependencyGraph = try performDependencyScan ( )
377
+ if let dotGraphPath = dotGraphPath {
378
+ try dependencyGraph. dumpDotGraph ( dotGraphPath, false )
379
+ }
284
380
var jobs : [ Job ] = [ ]
285
381
var danglingJobs : [ Job ] = [ ]
286
382
var inputCount = 0
0 commit comments