Skip to content
This repository was archived by the owner on Feb 4, 2020. It is now read-only.

Commit 33e5a0c

Browse files
committed
Support CLCACHE_BASEDIR in nodirect mode
Do a simple case-insensitive find-and-replace to transform absolute paths into relative paths within the preprocessor output that is used to compute the hash. This makes CLCACHE_NODIRECT mode usable in the presence of the __FILE__ macro. Fixes a bug in _normalizedCommandLine that caused the source filename to be included in the hash computation.
1 parent dd7bf50 commit 33e5a0c

File tree

5 files changed

+47
-6
lines changed

5 files changed

+47
-6
lines changed

README.asciidoc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,11 @@ CLCACHE_NODIRECT::
8686
key. Use this if you experience problems with direct mode or if you need
8787
built-in macroses like \__TIME__ to work correctly.
8888
CLCACHE_BASEDIR::
89-
Has effect only when direct mode is on. Set this to path to root directory
90-
of your project. This allows clcache to cache relative paths, so if you
91-
move your project to different directory, clcache will produce cache hits as
92-
before.
89+
Set this to path to root directory of your project. In direct mode, this allows
90+
clcache to cache relative paths, so if you move your project to different directory,
91+
clcache will produce cache hits as before. When direct mode is disabled, clcache will
92+
translate any absolute paths in the preprocessor output into relative paths before
93+
computing the hash.
9394
CLCACHE_OBJECT_CACHE_TIMEOUT_MS::
9495
Overrides the default ObjectCacheLock timeout (Default is 10 * 1000 ms).
9596
The ObjectCacheLock is used to give exclusive access to the cache, which is

clcache/__main__.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,19 @@ def normalizeBaseDir(baseDir):
118118
return None
119119

120120

121+
def caseInsensitiveReplace(data, old, new):
122+
dataLower = data.lower()
123+
oldLower = old.lower()
124+
output = b''
125+
index = 0
126+
while True:
127+
nextIndex = dataLower.find(oldLower, index)
128+
if nextIndex < 0:
129+
return output + data[index:]
130+
output += data[index:nextIndex] + new
131+
index = nextIndex + len(old)
132+
133+
121134
def getCachedCompilerConsoleOutput(path):
122135
try:
123136
with open(path, 'rb') as f:
@@ -469,6 +482,11 @@ def computeKeyNodirect(compilerBinary, commandLine, environment):
469482
compilerHash = getCompilerHash(compilerBinary)
470483
normalizedCmdLine = CompilerArtifactsRepository._normalizedCommandLine(commandLine)
471484

485+
if "CLCACHE_BASEDIR" in os.environ:
486+
baseDir = normalizeBaseDir(os.environ["CLCACHE_BASEDIR"]).replace("\\", "\\\\").encode("UTF-8")
487+
baseDirReplacement = BASEDIR_REPLACEMENT.encode("UTF-8")
488+
preprocessedSourceCode = caseInsensitiveReplace(preprocessedSourceCode, baseDir, baseDirReplacement)
489+
472490
h = HashAlgorithm()
473491
h.update(compilerHash.encode("UTF-8"))
474492
h.update(' '.join(normalizedCmdLine).encode("UTF-8"))
@@ -495,7 +513,7 @@ def _normalizedCommandLine(cmdline):
495513
argsToStrip += ("MP",)
496514

497515
return [arg for arg in cmdline
498-
if not (arg[0] in "/-" and arg[1:].startswith(argsToStrip))]
516+
if arg[0] in "/-" and not arg[1:].startswith(argsToStrip)]
499517

500518
class CacheFileStrategy:
501519
def __init__(self, cacheDirectory=None):
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include <iostream>
2+
3+
int main()
4+
{
5+
std::cout << __FILE__ << '\n';
6+
}
7+
8+

tests/test_integration.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1069,12 +1069,14 @@ def tearDown(self):
10691069
os.chdir(self.savedCwd)
10701070
self.tempDir.cleanup()
10711071

1072-
def _runCompiler(self, cppFile, extraArgs=None):
1072+
def _runCompiler(self, cppFile, extraArgs=None, direct=True):
10731073
cmd = CLCACHE_CMD + ["/nologo", "/EHsc", "/c"]
10741074
if extraArgs:
10751075
cmd.extend(extraArgs)
10761076
cmd.append(cppFile)
10771077
env = dict(os.environ, CLCACHE_DIR=self.clcacheDir, CLCACHE_BASEDIR=os.getcwd())
1078+
if not direct:
1079+
env["CLCACHE_NODIRECT"] = "1"
10781080
self.assertEqual(subprocess.call(cmd, env=env), 0)
10791081

10801082
def expectHit(self, runCompiler):
@@ -1140,6 +1142,11 @@ def runCompiler():
11401142
self._runCompiler("main.cpp", ["/DRESOURCES_DIR={}".format(os.getcwd())])
11411143
self.expectMiss([runCompiler, runCompiler])
11421144

1145+
def testBasedirNoDirect(self):
1146+
def runCompiler():
1147+
self._runCompiler(os.path.join(os.getcwd(), "nodirect.cpp"), direct=False)
1148+
self.expectHit([runCompiler, runCompiler])
1149+
11431150
def testBasedirRelativeIncludeArg(self):
11441151
basedir = os.getcwd()
11451152

tests/test_unit.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ def testFilesBeneathRecursive(self):
109109
self.assertIn(r".\d\4.txt", files)
110110
self.assertIn(r".\d\e\5.txt", files)
111111

112+
def testCaseInsensitiveReplace(self):
113+
replace = lambda s: clcache.caseInsensitiveReplace(s, b"PaTtErN", b"replacement")
114+
self.assertEqual(replace(b"pattern may appear"), b"replacement may appear")
115+
self.assertEqual(replace(b"infix paTTErn embed"), b"infix replacement embed")
116+
self.assertEqual(replace(b"Pattern and PATTERN and pattern"), b"replacement and replacement and replacement")
117+
self.assertEqual(replace(b"and finally PATTERN"), b"and finally replacement")
118+
112119

113120
class TestExtendCommandLineFromEnvironment(unittest.TestCase):
114121
def testEmpty(self):

0 commit comments

Comments
 (0)