@@ -773,6 +773,79 @@ final class ExplicitModuleBuildTests: XCTestCase {
773
773
}
774
774
}
775
775
776
+ // This is a regression test for the following scenario:
777
+ // 1. The user does a clean build of their project with explicit modules
778
+ // 2. The user starts a subsequent build using changed flags/environment which do not affect incremental builds (e.g. color diagnostics)
779
+ // 3. That flag/environment change does affect PCM hashes returned by the clang dependency scanner.
780
+ // 4. The driver determines that modules need to rebuild, sources don't need to rebuild, and verification needs to re-run.
781
+ // 5. The driver decides it's safe to skip the pre-compile jobs (the module builds) because the only post-compile jobs are for verification.
782
+ // 6. Verification fails because the modules with the new PCM hashes are missing.
783
+ // Ideally, this should never happen. If a flag doesn't invalidate Swift compilation, it shouldn;t be impacting module hashes either. But I
784
+ // think we should be resilient to this by rebuilding the modules in this scenario.
785
+ //
786
+ // The below test is somewhat fragile in that it will be redundant if we canonicalize away -fcolor-diagnostics in clang, but it's useful to ensure
787
+ // end to end behavior does not regress again.
788
+ func testExplicitModuleBuildDoesNotSkipPrecompiledModulesWhenOnlyVerificationIsInvalidated( ) throws {
789
+ try withTemporaryDirectory { path in
790
+ try localFileSystem. changeCurrentWorkingDirectory ( to: path)
791
+ let moduleCachePath = path. appending ( component: " ModuleCache " )
792
+ try localFileSystem. createDirectory ( moduleCachePath)
793
+ let main = path. appending ( component: " testExplicitModuleBuildEndToEnd.swift " )
794
+ try localFileSystem. writeFileContents ( main, bytes:
795
+ """
796
+ import C;
797
+ import E;
798
+ import G;
799
+
800
+ func foo() {
801
+ funcE()
802
+ }
803
+ """
804
+ )
805
+ let outputFileMap = path. appending ( component: " output-file-map.json " )
806
+ try localFileSystem. writeFileContents ( outputFileMap, bytes: ByteString ( encodingAsUTF8: """
807
+ {
808
+ " " : {
809
+ " swift-dependencies " : " \( path. appending ( component: " main.swiftdeps " ) . nativePathString ( escaped: true ) ) "
810
+ },
811
+ " \( path. appending ( component: " testExplicitModuleBuildEndToEnd.swift " ) . nativePathString ( escaped: true ) ) " : {
812
+ " swift-dependencies " : " \( path. appending ( component: " testExplicitModuleBuildEndToEnd.swiftdeps " ) . nativePathString ( escaped: true ) ) " ,
813
+ " object " : " \( path. appending ( component: " testExplicitModuleBuildEndToEnd.o " ) . nativePathString ( escaped: true ) ) "
814
+ }
815
+ }
816
+ """ ) )
817
+
818
+ let cHeadersPath : AbsolutePath =
819
+ try testInputsPath. appending ( component: " ExplicitModuleBuilds " )
820
+ . appending ( component: " CHeaders " )
821
+ let swiftModuleInterfacesPath : AbsolutePath =
822
+ try testInputsPath. appending ( component: " ExplicitModuleBuilds " )
823
+ . appending ( component: " Swift " )
824
+ let sdkArgumentsForTesting = ( try ? Driver . sdkArgumentsForTesting ( ) ) ?? [ ]
825
+ let invocationArguments = [ " swiftc " ,
826
+ " -incremental " , " -c " ,
827
+ " -emit-module " ,
828
+ " -enable-library-evolution " , " -emit-module-interface " , " -driver-show-incremental " , " -v " ,
829
+ " -Xcc " , " -Xclang " , " -Xcc " , " -fbuiltin-headers-in-system-modules " ,
830
+ " -I " , cHeadersPath. nativePathString ( escaped: true ) ,
831
+ " -I " , swiftModuleInterfacesPath. nativePathString ( escaped: true ) ,
832
+ " -explicit-module-build " ,
833
+ " -output-file-map " , outputFileMap. nativePathString ( escaped: true ) ,
834
+ " -module-cache-path " , moduleCachePath. nativePathString ( escaped: true ) ,
835
+ " -working-directory " , path. nativePathString ( escaped: true ) ,
836
+ main. nativePathString ( escaped: true ) ] + sdkArgumentsForTesting
837
+ var driver = try Driver ( args: invocationArguments)
838
+ let jobs = try driver. planBuild ( )
839
+ try driver. run ( jobs: jobs)
840
+ XCTAssertFalse ( driver. diagnosticEngine. hasErrors)
841
+
842
+ var incrementalDriver = try Driver ( args: invocationArguments + [ " -color-diagnostics " ] )
843
+ let incrementalJobs = try incrementalDriver. planBuild ( )
844
+ try incrementalDriver. run ( jobs: incrementalJobs)
845
+ XCTAssertFalse ( incrementalDriver. diagnosticEngine. hasErrors)
846
+ }
847
+ }
848
+
776
849
/// Test generation of explicit module build jobs for dependency modules when the driver
777
850
/// is invoked with -explicit-module-build, -verify-emitted-module-interface and -enable-library-evolution.
778
851
func testExplicitModuleVerifyInterfaceJobs( ) throws {
0 commit comments