@@ -24,33 +24,40 @@ public class PrebuitModuleGenerationDelegate: JobExecutionDelegate {
2424 let diagnosticsEngine : DiagnosticsEngine
2525 let verbose : Bool
2626 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 ? ) {
2829 self . diagnosticsEngine = diagnosticsEngine
2930 self . verbose = verbose
3031 self . failingCriticalOutputs = Set < VirtualPath > ( jobs. compactMap ( PrebuitModuleGenerationDelegate . getCriticalOutput) )
32+ self . logPath = logPath
3133 }
3234
3335 /// Dangling jobs are macabi-only modules. We should run those jobs if foundation
3436 /// is built successfully for macabi.
3537 public var shouldRunDanglingJobs : Bool {
3638 return !failingCriticalOutputs. contains ( where: isIosMac)
3739 }
38- func printJobInfo( _ job: Job , _ start: Bool ) {
39- guard verbose else {
40- return
41- }
40+
41+ func getInputInterfacePath( _ job: Job ) -> AbsolutePath {
4242 for arg in job. commandLine {
4343 if case . path( let p) = arg {
4444 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!
5146 }
5247 }
5348 }
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+ }
5461 }
5562
5663 static func getCriticalOutput( _ job: Job ) -> VirtualPath ? {
@@ -66,6 +73,24 @@ public class PrebuitModuleGenerationDelegate: JobExecutionDelegate {
6673 return !failingCriticalOutputs. isEmpty
6774 }
6875
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+
6994 public func jobFinished( job: Job , result: ProcessResult , pid: Int ) {
7095 switch result. exitStatus {
7196 case . terminated( code: let code) :
@@ -86,6 +111,15 @@ public class PrebuitModuleGenerationDelegate: JobExecutionDelegate {
86111 diagnosticsEngine. emit ( . remark( " \( job. moduleName) interrupted " ) )
87112#endif
88113 }
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+ }
89123 }
90124
91125 public func jobSkipped( job: Job ) {
@@ -236,6 +270,57 @@ public struct SDKPrebuiltModuleInputsCollector {
236270 }
237271}
238272
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+
239324extension Driver {
240325
241326 private mutating func generateSingleModuleBuildingJob( _ moduleName: String , _ prebuiltModuleDir: AbsolutePath ,
@@ -261,7 +346,14 @@ extension Driver {
261346 commandLine. appendFlag ( . Fsystem)
262347 commandLine. append ( . path( iosMacFrameworksSearchPath) )
263348 }
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+ }
264354 commandLine. appendFlag ( . serializeParseableModuleInterfaceDependencyHashes)
355+ commandLine. appendFlag ( . badFileDescriptorRetryCount)
356+ commandLine. appendFlag ( " 30 " )
265357 return Job (
266358 moduleName: moduleName,
267359 kind: . compile,
@@ -275,12 +367,16 @@ extension Driver {
275367
276368 public mutating func generatePrebuitModuleGenerationJobs( with inputMap: [ String : [ PrebuiltModuleInput ] ] ,
277369 into prebuiltModuleDir: AbsolutePath ,
278- exhaustive: Bool ) throws -> ( [ Job ] , [ Job ] ) {
370+ exhaustive: Bool ,
371+ dotGraphPath: AbsolutePath ? = nil ) throws -> ( [ Job ] , [ Job ] ) {
279372 assert ( sdkPath != nil )
280373 // Run the dependency scanner and update the dependency oracle with the results
281374 // We only need Swift dependencies here, so we don't need to invoke gatherModuleDependencies,
282375 // which also resolves versioned clang modules.
283376 let dependencyGraph = try performDependencyScan ( )
377+ if let dotGraphPath = dotGraphPath {
378+ try dependencyGraph. dumpDotGraph ( dotGraphPath, false )
379+ }
284380 var jobs : [ Job ] = [ ]
285381 var danglingJobs : [ Job ] = [ ]
286382 var inputCount = 0
0 commit comments