diff --git a/clcache.py b/clcache.py index cd299de8..c37c5fb9 100644 --- a/clcache.py +++ b/clcache.py @@ -1468,30 +1468,38 @@ def processDirect(cache, objectFile, compiler, cmdLine, sourceFile): baseDir = normalizeBaseDir(os.environ.get('CLCACHE_BASEDIR')) manifestHash = ManifestRepository.getManifestHash(compiler, cmdLine, sourceFile) manifestSection = cache.manifestRepository.section(manifestHash) + invalidManifest = False + with cache.lock: manifest = manifestSection.getManifest(manifestHash) if manifest is not None: - # NOTE: command line options already included in hash for manifest name - includesContentHash = ManifestRepository.getIncludesContentHashForFiles( - [expandBasedirPlaceholder(include, baseDir) for include in manifest.includeFiles]) - cachekey = manifest.includesContentToObjectMap.get(includesContentHash) - if cachekey is not None: - if cache.compilerArtifactsRepository.section(cachekey).hasEntry(cachekey): - return processCacheHit(cache, objectFile, cachekey) + try: + # NOTE: command line options already included in hash for manifest name + includesContentHash = ManifestRepository.getIncludesContentHashForFiles( + [expandBasedirPlaceholder(include, baseDir) for include in manifest.includeFiles]) + cachekey = manifest.includesContentToObjectMap.get(includesContentHash) + if cachekey is not None: + if cache.compilerArtifactsRepository.section(cachekey).hasEntry(cachekey): + return processCacheHit(cache, objectFile, cachekey) + else: + postProcessing = lambda compilerResult: postprocessObjectEvicted( + cache, objectFile, cachekey, compilerResult) else: - postProcessing = lambda compilerResult: postprocessObjectEvicted( - cache, objectFile, cachekey, compilerResult) - else: - postProcessing = lambda compilerResult: postprocessHeaderChangedMiss( - cache, objectFile, manifestSection, manifest, manifestHash, includesContentHash, compilerResult) + postProcessing = lambda compilerResult: postprocessHeaderChangedMiss( + cache, objectFile, manifestSection, manifest, manifestHash, includesContentHash, compilerResult) + except FileNotFoundError: + # A header file may have disappeared, consider the manifest as invalid and invoke the compiler + invalidManifest = True else: - origCmdLine = cmdLine - stripIncludes = False - if '/showIncludes' not in cmdLine: - cmdLine = ['/showIncludes'] + origCmdLine - stripIncludes = True - postProcessing = lambda compilerResult: postprocessNoManifestMiss( - cache, objectFile, manifestSection, manifestHash, baseDir, sourceFile, compilerResult, stripIncludes) + invalidManifest = True + + if invalidManifest: + stripIncludes = False + if '/showIncludes' not in cmdLine: + cmdLine = ['/showIncludes'] + cmdLine + stripIncludes = True + postProcessing = lambda compilerResult: postprocessNoManifestMiss( + cache, objectFile, manifestSection, manifestHash, baseDir, sourceFile, compilerResult, stripIncludes) compilerResult = invokeRealCompiler(compiler, cmdLine, captureOutput=True) compilerResult = postProcessing(compilerResult) diff --git a/integrationtests.py b/integrationtests.py index 39ae2f75..84200b44 100644 --- a/integrationtests.py +++ b/integrationtests.py @@ -311,6 +311,45 @@ def testNoDirect(self): output = subprocess.check_output(cmdRun).decode("ascii").strip() self.assertEqual(output, "2") + def testHeaderRemovedDirect(self): + with cd(os.path.join(ASSETS_DIR, "header-change")): + self._clean() + + with open("version.h", "w") as header: + header.write("#define VERSION 1") + + self._compileAndLink() + cmdRun = [os.path.abspath("main.exe")] + output = subprocess.check_output(cmdRun).decode("ascii").strip() + self.assertEqual(output, "1") + + self._clean() + + os.remove("version.h") + + # should fail now + self._compileAndLink() + + def testNoDirect(self): + with cd(os.path.join(ASSETS_DIR, "header-change")): + self._clean() + + with open("version.h", "w") as header: + header.write("#define VERSION 1") + + testEnvironment = dict(os.environ, CLCACHE_NODIRECT="1") + + self._compileAndLink(testEnvironment) + cmdRun = [os.path.abspath("main.exe")] + output = subprocess.check_output(cmdRun).decode("ascii").strip() + self.assertEqual(output, "1") + + self._clean() + + os.remove("version.h") + + # should fail now + self._compileAndLink() class TestRunParallel(unittest.TestCase): def _zeroStats(self):