@@ -270,6 +270,138 @@ final class CachingBuildTests: XCTestCase {
270270 }
271271 }
272272
273+ /// Test generation of explicit module build jobs for dependency modules when the driver
274+ /// is invoked with -explicit-module-build, -verify-emitted-module-interface and -enable-library-evolution.
275+ func testExplicitModuleVerifyInterfaceJobs( ) throws {
276+ try withTemporaryDirectory { path in
277+ let main = path. appending ( component: " testExplicitModuleVerifyInterfaceJobs.swift " )
278+ try localFileSystem. writeFileContents ( main) {
279+ $0 <<< " import C; "
280+ $0 <<< " import E; "
281+ $0 <<< " import G; "
282+ }
283+
284+ let swiftModuleInterfacesPath : AbsolutePath =
285+ testInputsPath. appending ( component: " ExplicitModuleBuilds " )
286+ . appending ( component: " Swift " )
287+ let cHeadersPath : AbsolutePath =
288+ testInputsPath. appending ( component: " ExplicitModuleBuilds " )
289+ . appending ( component: " CHeaders " )
290+ let casPath = path. appending ( component: " cas " )
291+ let swiftInterfacePath : AbsolutePath = path. appending ( component: " testExplicitModuleVerifyInterfaceJobs.swiftinterface " )
292+ let privateSwiftInterfacePath : AbsolutePath = path. appending ( component: " testExplicitModuleVerifyInterfaceJobs.private.swiftinterface " )
293+ let sdkArgumentsForTesting = ( try ? Driver . sdkArgumentsForTesting ( ) ) ?? [ ]
294+ var driver = try Driver ( args: [ " swiftc " ,
295+ " -target " , " x86_64-apple-macosx11.0 " ,
296+ " -I " , cHeadersPath. nativePathString ( escaped: true ) ,
297+ " -I " , swiftModuleInterfacesPath. nativePathString ( escaped: true ) ,
298+ " -emit-module-interface-path " , swiftInterfacePath. nativePathString ( escaped: true ) ,
299+ " -emit-private-module-interface-path " , privateSwiftInterfacePath. nativePathString ( escaped: true ) ,
300+ " -explicit-module-build " , " -verify-emitted-module-interface " ,
301+ " -enable-library-evolution " ,
302+ " -cache-compile-job " , " -cas-path " , casPath. nativePathString ( escaped: true ) ,
303+ main. nativePathString ( escaped: true ) ] + sdkArgumentsForTesting)
304+
305+ let jobs = try driver. planBuild ( )
306+ // Figure out which Triples to use.
307+ let dependencyGraph = try driver. gatherModuleDependencies ( )
308+ let mainModuleInfo = try dependencyGraph. moduleInfo ( of: . swift( " testExplicitModuleVerifyInterfaceJobs " ) )
309+ guard case . swift( _) = mainModuleInfo. details else {
310+ XCTFail ( " Main module does not have Swift details field " )
311+ return
312+ }
313+
314+ for job in jobs {
315+ if ( job. outputs. count == 0 ) {
316+ // This is the verify module job as it should be the only job scheduled to have no output.
317+ XCTAssertTrue ( job. kind == . verifyModuleInterface)
318+ // Check the explicit module flags exists.
319+ XCTAssertTrue ( job. commandLine. contains ( . flag( String ( " -explicit-interface-module-build " ) ) ) )
320+ XCTAssertTrue ( job. commandLine. contains ( . flag( String ( " -explicit-swift-module-map-file " ) ) ) )
321+ XCTAssertTrue ( job. commandLine. contains ( . flag( String ( " -disable-implicit-swift-modules " ) ) ) )
322+ XCTAssertTrue ( job. commandLine. contains ( . flag( String ( " -input-file-key " ) ) ) )
323+ continue
324+ }
325+ let outputFilePath = job. outputs [ 0 ] . file
326+
327+ // Swift dependencies
328+ if outputFilePath. extension != nil ,
329+ outputFilePath. extension! == FileType . swiftModule. rawValue {
330+ if pathMatchesSwiftModule ( path: outputFilePath, " A " ) {
331+ try checkCachingBuildJob ( job: job, moduleId: . swift( " A " ) ,
332+ dependencyGraph: dependencyGraph)
333+ } else if pathMatchesSwiftModule ( path: outputFilePath, " E " ) {
334+ try checkCachingBuildJob ( job: job, moduleId: . swift( " E " ) ,
335+ dependencyGraph: dependencyGraph)
336+ } else if pathMatchesSwiftModule ( path: outputFilePath, " G " ) {
337+ try checkCachingBuildJob ( job: job, moduleId: . swift( " G " ) ,
338+ dependencyGraph: dependencyGraph)
339+ } else if pathMatchesSwiftModule ( path: outputFilePath, " Swift " ) {
340+ try checkCachingBuildJob ( job: job, moduleId: . swift( " Swift " ) ,
341+ dependencyGraph: dependencyGraph)
342+ } else if pathMatchesSwiftModule ( path: outputFilePath, " _Concurrency " ) {
343+ try checkCachingBuildJob ( job: job, moduleId: . swift( " _Concurrency " ) ,
344+ dependencyGraph: dependencyGraph)
345+ } else if pathMatchesSwiftModule ( path: outputFilePath, " _StringProcessing " ) {
346+ try checkCachingBuildJob ( job: job, moduleId: . swift( " _StringProcessing " ) ,
347+ dependencyGraph: dependencyGraph)
348+ } else if pathMatchesSwiftModule ( path: outputFilePath, " SwiftOnoneSupport " ) {
349+ try checkCachingBuildJob ( job: job, moduleId: . swift( " SwiftOnoneSupport " ) ,
350+ dependencyGraph: dependencyGraph)
351+ }
352+ // Clang Dependencies
353+ } else if let outputExtension = outputFilePath. extension,
354+ outputExtension == FileType . pcm. rawValue {
355+ let relativeOutputPathFileName = outputFilePath. basename
356+ if relativeOutputPathFileName. starts ( with: " A- " ) {
357+ try checkCachingBuildJob ( job: job, moduleId: . clang( " A " ) ,
358+ dependencyGraph: dependencyGraph)
359+ }
360+ else if relativeOutputPathFileName. starts ( with: " B- " ) {
361+ try checkCachingBuildJob ( job: job, moduleId: . clang( " B " ) ,
362+ dependencyGraph: dependencyGraph)
363+ }
364+ else if relativeOutputPathFileName. starts ( with: " C- " ) {
365+ try checkCachingBuildJob ( job: job, moduleId: . clang( " C " ) ,
366+ dependencyGraph: dependencyGraph)
367+ }
368+ else if relativeOutputPathFileName. starts ( with: " G- " ) {
369+ try checkCachingBuildJob ( job: job, moduleId: . clang( " G " ) ,
370+ dependencyGraph: dependencyGraph)
371+ }
372+ else if relativeOutputPathFileName. starts ( with: " F- " ) {
373+ try checkCachingBuildJob ( job: job, moduleId: . clang( " F " ) ,
374+ dependencyGraph: dependencyGraph)
375+ }
376+ else if relativeOutputPathFileName. starts ( with: " SwiftShims- " ) {
377+ try checkCachingBuildJob ( job: job, moduleId: . clang( " SwiftShims " ) ,
378+ dependencyGraph: dependencyGraph)
379+ }
380+ else if relativeOutputPathFileName. starts ( with: " _SwiftConcurrencyShims- " ) {
381+ try checkCachingBuildJob ( job: job, moduleId: . clang( " _SwiftConcurrencyShims " ) ,
382+ dependencyGraph: dependencyGraph)
383+ }
384+ else {
385+ XCTFail ( " Unexpected module dependency build job output: \( outputFilePath) " )
386+ }
387+ } else {
388+ switch ( outputFilePath) {
389+ case . relative( RelativePath ( " testExplicitModuleVerifyInterfaceJobs " ) ) :
390+ XCTAssertTrue ( driver. isExplicitMainModuleJob ( job: job) )
391+ XCTAssertEqual ( job. kind, . link)
392+ case . temporary( _) :
393+ let baseName = " testExplicitModuleVerifyInterfaceJobs "
394+ XCTAssertTrue ( matchTemporary ( outputFilePath, basename: baseName, fileExtension: " o " ) ||
395+ matchTemporary ( outputFilePath, basename: baseName, fileExtension: " autolink " ) )
396+ default :
397+ XCTFail ( " Unexpected module dependency build job output: \( outputFilePath) " )
398+ }
399+ }
400+ }
401+ }
402+ }
403+
404+
273405 func testCacheBuildEndToEndBuild( ) throws {
274406 try withTemporaryDirectory { path in
275407 try localFileSystem. changeCurrentWorkingDirectory ( to: path)
0 commit comments