@@ -374,6 +374,138 @@ final class ExplicitModuleBuildTests: XCTestCase {
374
374
}
375
375
}
376
376
377
+ /// Test generation of explicit module build jobs for dependency modules when the driver
378
+ /// is invoked with -explicit-module-build and -pch-output-dir
379
+ func testExplicitModuleBuildPCHOutputJobs( ) throws {
380
+ try withTemporaryDirectory { path in
381
+ let main = path. appending ( component: " testExplicitModuleBuildPCHOutputJobs.swift " )
382
+ try localFileSystem. writeFileContents ( main) {
383
+ $0 <<< " import C; "
384
+ $0 <<< " import E; "
385
+ $0 <<< " import G; "
386
+ }
387
+
388
+ let cHeadersPath : AbsolutePath =
389
+ testInputsPath. appending ( component: " ExplicitModuleBuilds " )
390
+ . appending ( component: " CHeaders " )
391
+ let bridgingHeaderpath : AbsolutePath =
392
+ cHeadersPath. appending ( component: " Bridging.h " )
393
+ let swiftModuleInterfacesPath : AbsolutePath =
394
+ testInputsPath. appending ( component: " ExplicitModuleBuilds " )
395
+ . appending ( component: " Swift " )
396
+ let sdkArgumentsForTesting = ( try ? Driver . sdkArgumentsForTesting ( ) ) ?? [ ]
397
+ let pchOutputDir : AbsolutePath = path
398
+ var driver = try Driver ( args: [ " swiftc " ,
399
+ " -target " , " x86_64-apple-macosx11.0 " ,
400
+ " -I " , cHeadersPath. nativePathString ( escaped: true ) ,
401
+ " -I " , swiftModuleInterfacesPath. nativePathString ( escaped: true ) ,
402
+ " -explicit-module-build " ,
403
+ " -import-objc-header " , bridgingHeaderpath. nativePathString ( escaped: true ) ,
404
+ " -pch-output-dir " , pchOutputDir. nativePathString ( escaped: true ) ,
405
+ main. nativePathString ( escaped: true ) ] + sdkArgumentsForTesting)
406
+
407
+ let jobs = try driver. planBuild ( )
408
+ // Figure out which Triples to use.
409
+ let dependencyGraph = try driver. gatherModuleDependencies ( )
410
+ let mainModuleInfo = try dependencyGraph. moduleInfo ( of: . swift( " testExplicitModuleBuildPCHOutputJobs " ) )
411
+ guard case . swift( _) = mainModuleInfo. details else {
412
+ XCTFail ( " Main module does not have Swift details field " )
413
+ return
414
+ }
415
+
416
+ for job in jobs {
417
+ XCTAssertEqual ( job. outputs. count, 1 )
418
+ let outputFilePath = job. outputs [ 0 ] . file
419
+
420
+ // Swift dependencies
421
+ if outputFilePath. extension != nil ,
422
+ outputFilePath. extension! == FileType . swiftModule. rawValue {
423
+ if pathMatchesSwiftModule ( path: outputFilePath, " A " ) {
424
+ try checkExplicitModuleBuildJob ( job: job, moduleId: . swift( " A " ) ,
425
+ dependencyGraph: dependencyGraph)
426
+ } else if pathMatchesSwiftModule ( path: outputFilePath, " E " ) {
427
+ try checkExplicitModuleBuildJob ( job: job, moduleId: . swift( " E " ) ,
428
+ dependencyGraph: dependencyGraph)
429
+ } else if pathMatchesSwiftModule ( path: outputFilePath, " G " ) {
430
+ try checkExplicitModuleBuildJob ( job: job, moduleId: . swift( " G " ) ,
431
+ dependencyGraph: dependencyGraph)
432
+ } else if pathMatchesSwiftModule ( path: outputFilePath, " Swift " ) {
433
+ try checkExplicitModuleBuildJob ( job: job, moduleId: . swift( " Swift " ) ,
434
+ dependencyGraph: dependencyGraph)
435
+ } else if pathMatchesSwiftModule ( path: outputFilePath, " _Concurrency " ) {
436
+ try checkExplicitModuleBuildJob ( job: job, moduleId: . swift( " _Concurrency " ) ,
437
+ dependencyGraph: dependencyGraph)
438
+ } else if pathMatchesSwiftModule ( path: outputFilePath, " _StringProcessing " ) {
439
+ try checkExplicitModuleBuildJob ( job: job, moduleId: . swift( " _StringProcessing " ) ,
440
+ dependencyGraph: dependencyGraph)
441
+ } else if pathMatchesSwiftModule ( path: outputFilePath, " SwiftOnoneSupport " ) {
442
+ try checkExplicitModuleBuildJob ( job: job, moduleId: . swift( " SwiftOnoneSupport " ) ,
443
+ dependencyGraph: dependencyGraph)
444
+ }
445
+ // Clang Dependencies
446
+ } else if let outputExtension = outputFilePath. extension,
447
+ outputExtension == FileType . pcm. rawValue {
448
+ let relativeOutputPathFileName = outputFilePath. basename
449
+ if relativeOutputPathFileName. starts ( with: " A- " ) {
450
+ try checkExplicitModuleBuildJob ( job: job, moduleId: . clang( " A " ) ,
451
+ dependencyGraph: dependencyGraph)
452
+ }
453
+ else if relativeOutputPathFileName. starts ( with: " B- " ) {
454
+ try checkExplicitModuleBuildJob ( job: job, moduleId: . clang( " B " ) ,
455
+ dependencyGraph: dependencyGraph)
456
+ }
457
+ else if relativeOutputPathFileName. starts ( with: " C- " ) {
458
+ try checkExplicitModuleBuildJob ( job: job, moduleId: . clang( " C " ) ,
459
+ dependencyGraph: dependencyGraph)
460
+ }
461
+ else if relativeOutputPathFileName. starts ( with: " G- " ) {
462
+ try checkExplicitModuleBuildJob ( job: job, moduleId: . clang( " G " ) ,
463
+ dependencyGraph: dependencyGraph)
464
+ }
465
+ else if relativeOutputPathFileName. starts ( with: " F- " ) {
466
+ try checkExplicitModuleBuildJob ( job: job, moduleId: . clang( " F " ) ,
467
+ dependencyGraph: dependencyGraph)
468
+ }
469
+ else if relativeOutputPathFileName. starts ( with: " SwiftShims- " ) {
470
+ try checkExplicitModuleBuildJob ( job: job, moduleId: . clang( " SwiftShims " ) ,
471
+ dependencyGraph: dependencyGraph)
472
+ }
473
+ else if relativeOutputPathFileName. starts ( with: " _SwiftConcurrencyShims- " ) {
474
+ try checkExplicitModuleBuildJob ( job: job, moduleId: . clang( " _SwiftConcurrencyShims " ) ,
475
+ dependencyGraph: dependencyGraph)
476
+ }
477
+ else {
478
+ XCTFail ( " Unexpected module dependency build job output: \( outputFilePath) " )
479
+ }
480
+ // Bridging header
481
+ } else if let outputExtension = outputFilePath. extension,
482
+ outputExtension == FileType . pch. rawValue {
483
+ switch ( outputFilePath) {
484
+ case . absolute:
485
+ // pch output is a computed absolute path.
486
+ XCTAssertFalse ( job. commandLine. contains ( " -pch-output-dir " ) )
487
+ default :
488
+ XCTFail ( " Unexpected module dependency build job output: \( outputFilePath) " )
489
+ }
490
+ } else {
491
+ // Check we don't use `-pch-output-dir` anymore during main module job.
492
+ XCTAssertFalse ( job. commandLine. contains ( " -pch-output-dir " ) )
493
+ switch ( outputFilePath) {
494
+ case . relative( RelativePath ( " testExplicitModuleBuildPCHOutputJobs " ) ) :
495
+ XCTAssertTrue ( driver. isExplicitMainModuleJob ( job: job) )
496
+ XCTAssertEqual ( job. kind, . link)
497
+ case . temporary( _) :
498
+ let baseName = " testExplicitModuleBuildPCHOutputJobs "
499
+ XCTAssertTrue ( matchTemporary ( outputFilePath, basename: baseName, fileExtension: " o " ) ||
500
+ matchTemporary ( outputFilePath, basename: baseName, fileExtension: " autolink " ) )
501
+ default :
502
+ XCTFail ( " Unexpected module dependency build job output: \( outputFilePath) " )
503
+ }
504
+ }
505
+ }
506
+ }
507
+ }
508
+
377
509
func testImmediateModeExplicitModuleBuild( ) throws {
378
510
try withTemporaryDirectory { path in
379
511
let main = path. appending ( component: " testExplicitModuleBuildJobs.swift " )
0 commit comments