// Test build session validation with parallel compilation for incremental builds. // RUN: rm -rf %t // RUN: split-file %s %t // Use the same command line arguments to ensure .pcm files are in the same location. // RUN: echo "-fsyntax-only -I %/t/include" > %t/ctx.rsp // RUN: echo "-fmodules -fmodules-cache-path=%/t/module-cache" >> %t/ctx.rsp // RUN: echo "-fbuild-session-file=%/t/session.timestamp" >> %t/ctx.rsp // RUN: echo "-fmodules-validate-once-per-build-session" >> %t/ctx.rsp // // Add a build session file to avoid errors that it's missing. Doesn't do anything as we start with a clean build. // RUN: touch %t/session.timestamp // Generate headers that take noticeable time to parse. The purpose is to tweak the timing, so can reproduce the error. // RUN: %python %t/generate-expensive-header.py A 2000000 > %t/include/expensive-header.h // RUN: %python %t/generate-expensive-header.py B 500000 > %t/include/less-expensive-header.h // // Create SignatureExpectation.pcm with a specific Target signature. // RUN: cp %t/version1.h %t/include/target.h // RUN: sed "s|DIR|%/t|g" %t/prepare-expected-signature.json.template > %t/prepare-expected-signature.json // RUN: clang-scan-deps -compilation-database %t/prepare-expected-signature.json > /dev/null // // Built a different Target.pcm with a different signature. // RUN: cp %t/version2.h %t/include/target.h // Update the build session to rebuild Target. // RUN: touch %t/session.timestamp // RUN: sed "s|DIR|%/t|g" %t/create-outdated-module.json.template > %t/create-outdated-module.json // RUN: clang-scan-deps -compilation-database %t/create-outdated-module.json > /dev/null // // Simulate the incremental build. // RUN: cp %t/version3.h %t/include/target.h // RUN: touch %t/session.timestamp // Scan 2 files in parallel. // RUN: sed "s|DIR|%/t|g" %t/incremental.json.template > %t/incremental.json // RUN: clang-scan-deps -compilation-database %t/incremental.json > /dev/null //--- include/module.modulemap module Target { header "target.h" export * } module SignatureExpectation { header "signature-expectation.h" textual header "expensive-header.h" export * } //--- version1.h // empty //--- version2.h void some_func(void); //--- version3.h void some_func(void); #define TARGET_MACRO 1 //--- generate-expensive-header.py import sys num_items = int(sys.argv[2]) suffix = sys.argv[1] for i in range(num_items): if i == 0: print(f"#define MACRO_{suffix}_{i} 0") else: print(f"#define MACRO_{suffix}_{i} MACRO_{suffix}_{i-1} + 1") //--- include/signature-expectation.h // Expensive header is used to slow down the build of SignatureExpectation module. // Without the slow down we are able to validate and rebuild Target before another thread can do it. #include #include //--- prepare-expected-signature.c #include //--- prepare-expected-signature.json.template [{ "file": "DIR/prepare-expected-signature.c", "directory": "DIR", "command": "clang @DIR/ctx.rsp DIR/prepare-expected-signature.c" }] //--- create-outdated-module.c #include //--- create-outdated-module.json.template [{ "file": "DIR/create-outdated-module.c", "directory": "DIR", "command": "clang @DIR/ctx.rsp DIR/create-outdated-module.c" }] //--- use-outdated-module.c // At first load SignatureExpectation module, so it would load Target but // reject it due to a signature mismatch. // After this we rebuild SignatureExpectation and try to use already loaded // Target buffer when encounter corresponding include in the source code. // The problem is that it corresponds to version2.h and not version3.h. #include #ifndef TARGET_MACRO # error Macro is missing, probably using outdated Target module # include #endif //--- rebuild-outdated-module.c // We aim for another thread to load the outdated module Target with // the wrong signature before we rebuild it. #include #include //--- incremental.json.template [{ "file": "DIR/use-outdated-module.c", "directory": "DIR", "command": "clang @DIR/ctx.rsp DIR/use-outdated-module.c" }, { "file": "DIR/rebuild-outdated-module.c", "directory": "DIR", "command": "clang @DIR/ctx.rsp DIR/rebuild-outdated-module.c" }]