summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2018-04-13 04:01:35 +0530
committerNirbheek Chauhan <nirbheek@centricular.com>2018-04-13 04:09:49 +0530
commitfac1d09ac55338817728c1bb09387b6914eaf324 (patch)
treecab13e6b8a30615222b667436a01ecfd84338e31
parentc04862e24c94000a4e8a7b9c1012178b3b6195d8 (diff)
downloadmeson-nirbheek/cache-compiler-checks.tar.gz
compilers: Cache compiler checks where we don't want the outputnirbheek/cache-compiler-checks
This caching is only for a single run, so it doesn't help reconfigure. However, it is useful for subproject setups where different subprojects will run the same compiler checks. The cache is also per compiler instance and is not used for functions that want to read or run the outputted object file or binary. For gst-build, this halves the number of compiler checks that are run and reduces configuration time by 20%.
-rw-r--r--mesonbuild/compilers/c.py10
-rw-r--r--mesonbuild/compilers/compilers.py26
2 files changed, 28 insertions, 8 deletions
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index 27cf43a74..dee5125f4 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -319,16 +319,16 @@ class CCompiler(Compiler):
args += extra_args
return args
- def compiles(self, code, env, extra_args=None, dependencies=None, mode='compile'):
+ def compiles(self, code, env, extra_args=None, dependencies=None, mode='compile', want_output=False):
args = self._get_compiler_check_args(env, extra_args, dependencies, mode)
# We only want to compile; not link
with self.compile(code, args.to_native(), mode) as p:
return p.returncode == 0
- def _links_wrapper(self, code, env, extra_args, dependencies):
+ def _links_wrapper(self, code, env, extra_args, dependencies, want_output=False):
"Shares common code between self.links and self.run"
args = self._get_compiler_check_args(env, extra_args, dependencies, mode='link')
- return self.compile(code, args)
+ return self.compile(code, args, want_output=want_output)
def links(self, code, env, extra_args=None, dependencies=None):
with self._links_wrapper(code, env, extra_args, dependencies) as p:
@@ -337,7 +337,7 @@ class CCompiler(Compiler):
def run(self, code, env, extra_args=None, dependencies=None):
if self.is_cross and self.exe_wrapper is None:
raise CrossNoRunException('Can not run test applications in this cross environment.')
- with self._links_wrapper(code, env, extra_args, dependencies) as p:
+ with self._links_wrapper(code, env, extra_args, dependencies, True) as p:
if p.returncode != 0:
mlog.debug('Could not compile test file %s: %d\n' % (
p.input_name,
@@ -736,7 +736,7 @@ class CCompiler(Compiler):
args = self.get_cross_extra_flags(env, link=False)
args += self.get_compiler_check_args()
n = 'symbols_have_underscore_prefix'
- with self.compile(code, args, 'compile') as p:
+ with self.compile(code, args, 'compile', want_output=True) as p:
if p.returncode != 0:
m = 'BUG: Unable to compile {!r} check: {}'
raise RuntimeError(m.format(n, p.stdo))
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index a28a225f3..8a5296190 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -601,6 +601,8 @@ class Compiler:
# Libraries to ignore in find_library() since they are provided by the
# compiler or the C library. Currently only used for MSVC.
ignore_libs = ()
+ # Cache for the result of compiler checks which can be cached
+ compiler_check_cache = {}
def __init__(self, exelist, version, **kwargs):
if isinstance(exelist, str):
@@ -753,9 +755,23 @@ class Compiler:
return os.path.join(dirname, 'output.' + suffix)
@contextlib.contextmanager
- def compile(self, code, extra_args=None, mode='link'):
+ def compile(self, code, extra_args=None, mode='link', want_output=False):
if extra_args is None:
+ textra_args = None
extra_args = []
+ else:
+ textra_args = tuple(extra_args)
+ key = (code, textra_args, mode)
+ if not want_output:
+ if key in self.compiler_check_cache:
+ p = self.compiler_check_cache[key]
+ mlog.debug('Using cached compile:')
+ mlog.debug('Cached command line: ', ' '.join(p.commands), '\n')
+ mlog.debug('Code:\n', code)
+ mlog.debug('Cached compiler stdout:\n', p.stdo)
+ mlog.debug('Cached compiler stderr:\n', p.stde)
+ yield p
+ raise StopIteration
try:
with tempfile.TemporaryDirectory() as tmpdirname:
if isinstance(code, str):
@@ -765,7 +781,6 @@ class Compiler:
ofile.write(code)
elif isinstance(code, mesonlib.File):
srcname = code.fname
- output = self._get_compile_output(tmpdirname, mode)
# Construct the compiler command-line
commands = CompilerArgs(self)
@@ -778,6 +793,7 @@ class Compiler:
if mode == 'preprocess':
commands += self.get_preprocess_only_args()
else:
+ output = self._get_compile_output(tmpdirname, mode)
commands += self.get_output_args(output)
# Generate full command-line with the exelist
commands = self.get_exelist() + commands.to_native()
@@ -788,8 +804,12 @@ class Compiler:
p, p.stdo, p.stde = Popen_safe(commands, cwd=tmpdirname)
mlog.debug('Compiler stdout:\n', p.stdo)
mlog.debug('Compiler stderr:\n', p.stde)
+ p.commands = commands
p.input_name = srcname
- p.output_name = output
+ if want_output:
+ p.output_name = output
+ else:
+ self.compiler_check_cache[key] = p
yield p
except (PermissionError, OSError):
# On Windows antivirus programs and the like hold on to files so