aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Reference-manual.md4
-rw-r--r--docs/markdown/snippets/link_language.md10
-rw-r--r--mesonbuild/ast/introspection.py8
-rw-r--r--mesonbuild/ast/visitor.py2
-rw-r--r--mesonbuild/backend/backends.py4
-rw-r--r--mesonbuild/backend/ninjabackend.py16
-rw-r--r--mesonbuild/backend/vs2010backend.py6
-rw-r--r--mesonbuild/backend/xcodebackend.py4
-rw-r--r--mesonbuild/build.py23
-rw-r--r--mesonbuild/compilers/c.py65
-rw-r--r--mesonbuild/compilers/compilers.py96
-rw-r--r--mesonbuild/compilers/cpp.py11
-rw-r--r--mesonbuild/compilers/cs.py4
-rw-r--r--mesonbuild/compilers/cuda.py5
-rw-r--r--mesonbuild/compilers/d.py4
-rw-r--r--mesonbuild/compilers/fortran.py24
-rw-r--r--mesonbuild/compilers/vala.py4
-rw-r--r--mesonbuild/coredata.py1
-rw-r--r--mesonbuild/dependencies/base.py8
-rw-r--r--mesonbuild/dependencies/boost.py2
-rw-r--r--mesonbuild/dependencies/misc.py4
-rw-r--r--mesonbuild/dependencies/ui.py10
-rw-r--r--mesonbuild/envconfig.py10
-rw-r--r--mesonbuild/interpreter.py109
-rw-r--r--mesonbuild/interpreterbase.py2
-rw-r--r--mesonbuild/mesonlib.py19
-rw-r--r--mesonbuild/mesonmain.py30
-rw-r--r--mesonbuild/minstall.py4
-rw-r--r--mesonbuild/mintro.py6
-rw-r--r--mesonbuild/mlog.py51
-rw-r--r--mesonbuild/modules/python.py6
-rw-r--r--mesonbuild/modules/unstable_simd.py2
-rw-r--r--mesonbuild/modules/windows.py4
-rw-r--r--mesonbuild/mparser.py2
-rw-r--r--mesonbuild/munstable_coredata.py21
-rw-r--r--mesonbuild/scripts/depfixer.py4
-rw-r--r--mesonbuild/wrap/wrap.py4
-rw-r--r--mesonbuild/wrap/wraptool.py2
-rwxr-xr-xrun_project_tests.py8
-rwxr-xr-xrun_tests.py2
-rwxr-xr-xrun_unittests.py18
-rw-r--r--setup.cfg2
-rw-r--r--sideci.yml4
-rw-r--r--test cases/fortran/14 fortran links c/clib.c7
-rw-r--r--test cases/fortran/14 fortran links c/f_call_c.f9010
-rw-r--r--test cases/fortran/14 fortran links c/meson.build13
-rwxr-xr-xtools/boost_names.py2
47 files changed, 388 insertions, 269 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 056612d..d86d825 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -518,6 +518,8 @@ be passed to [shared and static libraries](#library).
depends on such as a symbol visibility map. The purpose is to
automatically trigger a re-link (but not a re-compile) of the target
when this file changes.
+- `link_language` since 0.51.0 makes the linker for this target
+ be for the specified language. This is helpful for multi-language targets.
- `link_whole` links all contents of the given static libraries
whether they are used by not, equivalent to the
`-Wl,--whole-archive` argument flag of GCC, available since 0.40.0.
@@ -568,7 +570,7 @@ be passed to [shared and static libraries](#library).
the keyword argument for the default behaviour.
- `override_options` takes an array of strings in the same format as
`project`'s `default_options` overriding the values of these options
- for this target only, since 0.40.0
+ for this target only, since 0.40.0.
- `gnu_symbol_visibility` specifies how symbols should be exported, see
e.g [the GCC Wiki](https://gcc.gnu.org/wiki/Visibility) for more
information. This value can either be an empty string or one of
diff --git a/docs/markdown/snippets/link_language.md b/docs/markdown/snippets/link_language.md
new file mode 100644
index 0000000..28ebe8b
--- /dev/null
+++ b/docs/markdown/snippets/link_language.md
@@ -0,0 +1,10 @@
+## New target keyword argument: `link_language`
+There may be situations for which the user wishes to manually specify the linking language.
+For example, a C++ target may link C, Fortran, etc. and perhaps the automatic detection in Meson does not pick the desired compiler.
+The user can manually choose the linker by language per-target like this example of a target where one wishes to link with the Fortran compiler:
+```meson
+executable(..., link_language : 'fortran')
+```
+
+A specific case this option fixes is where for example the main program is Fortran that calls C and/or C++ code.
+The automatic language detection of Meson prioritizes C/C++, and so an compile-time error results like `undefined reference to main`, because the linker is C or C++ instead of Fortran, which is fixed by this per-target override.
diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py
index 49d531f..b6ec450 100644
--- a/mesonbuild/ast/introspection.py
+++ b/mesonbuild/ast/introspection.py
@@ -122,7 +122,7 @@ class IntrospectionInterpreter(AstInterpreter):
subi.analyze()
subi.project_data['name'] = dirname
self.project_data['subprojects'] += [subi.project_data]
- except:
+ except (mesonlib.MesonException, RuntimeError):
return
def func_add_languages(self, node, args, kwargs):
@@ -173,9 +173,9 @@ class IntrospectionInterpreter(AstInterpreter):
arg_node = curr.args
elif isinstance(curr, IdNode):
# Try to resolve the ID and append the node to the queue
- id = curr.value
- if id in self.assignments and self.assignments[id]:
- tmp_node = self.assignments[id][0]
+ var_name = curr.value
+ if var_name in self.assignments and self.assignments[var_name]:
+ tmp_node = self.assignments[var_name][0]
if isinstance(tmp_node, (ArrayNode, IdNode, FunctionNode)):
srcqueue += [tmp_node]
elif isinstance(curr, ArithmeticNode):
diff --git a/mesonbuild/ast/visitor.py b/mesonbuild/ast/visitor.py
index c8769d4..fab4ed2 100644
--- a/mesonbuild/ast/visitor.py
+++ b/mesonbuild/ast/visitor.py
@@ -134,7 +134,5 @@ class AstVisitor:
self.visit_default_func(node)
for i in node.arguments:
i.accept(self)
- for i in node.commas:
- pass
for val in node.kwargs.values():
val.accept(self)
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index e40bcbc..d0b4bb5 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -322,12 +322,14 @@ class Backend:
raise MesonException('Unknown data type in object list.')
return obj_list
- def serialize_executable(self, tname, exe, cmd_args, workdir, env={},
+ def serialize_executable(self, tname, exe, cmd_args, workdir, env=None,
extra_paths=None, capture=None):
'''
Serialize an executable for running with a generator or a custom target
'''
import hashlib
+ if env is None:
+ env = {}
if extra_paths is None:
# The callee didn't check if we needed extra paths, so check it here
if mesonlib.is_windows() or mesonlib.is_cygwin():
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 9a6fdad..7eafcad 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -406,9 +406,9 @@ int dummy;
}
}
'''
- id = target.get_id()
+ tid = target.get_id()
lang = comp.get_language()
- tgt = self.introspection_data[id]
+ tgt = self.introspection_data[tid]
# Find an existing entry or create a new one
id_hash = (lang, tuple(parameters))
src_block = tgt.get(id_hash, None)
@@ -520,7 +520,7 @@ int dummy;
# This will be set as dependencies of all the target's sources. At the
# same time, also deal with generated sources that need to be compiled.
generated_source_files = []
- for rel_src, gensrc in generated_sources.items():
+ for rel_src in generated_sources.keys():
dirpart, fnamepart = os.path.split(rel_src)
raw_src = File(True, dirpart, fnamepart)
if self.environment.is_source(rel_src) and not self.environment.is_header(rel_src):
@@ -585,7 +585,7 @@ int dummy;
obj_list.append(self.generate_single_compile(target, src, 'vala', [], header_deps))
# Generate compile targets for all the pre-existing sources for this target
- for f, src in target_sources.items():
+ for src in target_sources.values():
if not self.environment.is_header(src):
if self.environment.is_llvm_ir(src):
obj_list.append(self.generate_llvm_ir_compile(target, src))
@@ -912,7 +912,7 @@ int dummy;
# Add possible java generated files to src list
generated_sources = self.get_target_generated_sources(target)
gen_src_list = []
- for rel_src, gensrc in generated_sources.items():
+ for rel_src in generated_sources.keys():
dirpart, fnamepart = os.path.split(rel_src)
raw_src = File(True, dirpart, fnamepart)
if rel_src.endswith('.java'):
@@ -1041,7 +1041,7 @@ int dummy;
def generate_single_java_compile(self, src, target, compiler, args):
deps = [os.path.join(self.get_target_dir(l), l.get_filename()) for l in target.link_targets]
generated_sources = self.get_target_generated_sources(target)
- for rel_src, gensrc in generated_sources.items():
+ for rel_src in generated_sources.keys():
if rel_src.endswith('.java'):
deps.append(rel_src)
rel_src = src.rel_to_builddir(self.build_to_src)
@@ -1227,7 +1227,7 @@ int dummy;
if len(target.install_dir) > 3 and target.install_dir[3] is True:
target.install_dir[3] = os.path.join(self.environment.get_datadir(), 'gir-1.0')
# Detect gresources and add --gresources arguments for each
- for (gres, gensrc) in other_src[1].items():
+ for gensrc in other_src[1].values():
if isinstance(gensrc, modules.GResourceTarget):
gres_xml, = self.get_custom_target_sources(gensrc)
args += ['--gresources=' + gres_xml]
@@ -2751,7 +2751,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
return super().get_introspection_data(target_id, target)
result = []
- for _, i in self.introspection_data[target_id].items():
+ for i in self.introspection_data[target_id].values():
result += [i]
return result
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index afbd59b..d25798e 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -312,7 +312,7 @@ class Vs2010Backend(backends.Backend):
target = self.build.targets[prj[0]]
lang = 'default'
if hasattr(target, 'compilers') and target.compilers:
- for (lang_out, _) in target.compilers.items():
+ for lang_out in target.compilers.keys():
lang = lang_out
break
prj_line = prj_templ % (
@@ -386,7 +386,7 @@ class Vs2010Backend(backends.Backend):
for p in projlist:
if p[1].parent != PurePath('.'):
ofile.write("\t\t{%s} = {%s}\n" % (p[2], self.subdirs[p[1].parent][0]))
- for (_, subdir) in self.subdirs.items():
+ for subdir in self.subdirs.values():
if subdir[1]:
ofile.write("\t\t{%s} = {%s}\n" % (subdir[0], subdir[1]))
ofile.write('\tEndGlobalSection\n')
@@ -463,7 +463,7 @@ class Vs2010Backend(backends.Backend):
def add_target_deps(self, root, target):
target_dict = {target.get_id(): target}
- for name, dep in self.get_target_deps(target_dict).items():
+ for dep in self.get_target_deps(target_dict).values():
if dep.get_id() in self.handled_target_deps[target.get_id()]:
# This dependency was already handled manually.
continue
diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py
index 7dd3674..be22c78 100644
--- a/mesonbuild/backend/xcodebackend.py
+++ b/mesonbuild/backend/xcodebackend.py
@@ -345,7 +345,7 @@ class XCodeBackend(backends.Backend):
self.ofile.write('/* End PBXFileReference section */\n')
def generate_pbx_frameworks_buildphase(self):
- for tname, t in self.build.targets.items():
+ for t in self.build.targets.values():
self.ofile.write('\n/* Begin PBXFrameworksBuildPhase section */\n')
self.write_line('%s /* %s */ = {\n' % (t.buildphasemap['Frameworks'], 'Frameworks'))
self.indent_level += 1
@@ -587,7 +587,7 @@ class XCodeBackend(backends.Backend):
def generate_pbx_sources_build_phase(self):
self.ofile.write('\n/* Begin PBXSourcesBuildPhase section */\n')
- for name, phase_id in self.source_phase.items():
+ for name in self.source_phase.keys():
t = self.build.targets[name]
self.write_line('%s /* Sources */ = {' % (t.buildphasemap[name]))
self.indent_level += 1
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 1fad9e0..603e0d0 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from typing import List
import copy, os, re
from collections import OrderedDict
import itertools, pathlib
@@ -88,7 +89,7 @@ known_build_target_kwargs = (
rust_kwargs |
cs_kwargs)
-known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'pie'}
+known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'link_language', 'pie'}
known_shlib_kwargs = known_build_target_kwargs | {'version', 'soversion', 'vs_module_defs', 'darwin_versions'}
known_shmod_kwargs = known_build_target_kwargs
known_stlib_kwargs = known_build_target_kwargs | {'pic'}
@@ -425,7 +426,7 @@ a hard error in the future.''' % name)
self.option_overrides = self.parse_overrides(kwargs)
- def parse_overrides(self, kwargs):
+ def parse_overrides(self, kwargs) -> dict:
result = {}
overrides = stringlistify(kwargs.get('override_options', []))
for o in overrides:
@@ -437,7 +438,7 @@ a hard error in the future.''' % name)
result[k] = v
return result
- def is_linkable_target(self):
+ def is_linkable_target(self) -> bool:
return False
class BuildTarget(Target):
@@ -454,6 +455,7 @@ class BuildTarget(Target):
self.objects = []
self.external_deps = []
self.include_dirs = []
+ self.link_language = kwargs.get('link_language')
self.link_targets = []
self.link_whole_targets = []
self.link_depends = []
@@ -571,6 +573,9 @@ class BuildTarget(Target):
else:
compilers = self.environment.coredata.compilers
+ # did user override clink_langs for this target?
+ link_langs = [self.link_language] if self.link_language else clink_langs
+
# If this library is linked against another library we need to consider
# the languages of those libraries as well.
if self.link_targets or self.link_whole_targets:
@@ -579,7 +584,7 @@ class BuildTarget(Target):
if isinstance(t, CustomTarget) or isinstance(t, CustomTargetIndex):
continue # We can't know anything about these.
for name, compiler in t.compilers.items():
- if name in clink_langs:
+ if name in link_langs:
extra.add((name, compiler))
for name, compiler in sorted(extra, key=lambda p: sort_clink(p[0])):
self.compilers[name] = compiler
@@ -588,7 +593,7 @@ class BuildTarget(Target):
# No source files or parent targets, target consists of only object
# files of unknown origin. Just add the first clink compiler
# that we have and hope that it can link these objects
- for lang in clink_langs:
+ for lang in link_langs:
if lang in compilers:
self.compilers[lang] = compilers[lang]
break
@@ -1149,7 +1154,7 @@ You probably should put it in link_with instead.''')
def get_aliases(self):
return {}
- def get_langs_used_by_deps(self):
+ def get_langs_used_by_deps(self) -> List[str]:
'''
Sometimes you want to link to a C++ library that exports C API, which
means the linker must link in the C++ stdlib, and we must use a C++
@@ -1159,6 +1164,11 @@ You probably should put it in link_with instead.''')
See: https://github.com/mesonbuild/meson/issues/1653
'''
langs = []
+
+ # User specified link_language of target (for multi-language targets)
+ if self.link_language:
+ return [self.link_language]
+
# Check if any of the external libraries were written in this language
for dep in self.external_deps:
if dep.language is None:
@@ -1173,6 +1183,7 @@ You probably should put it in link_with instead.''')
for language in link_target.compilers:
if language not in langs:
langs.append(language)
+
return langs
def get_clink_dynamic_linker_and_stdlibs(self):
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index 54ca894..1aeb637 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -368,7 +368,7 @@ class CCompiler(Compiler):
return self.compiles(code.format(**fargs), env, extra_args=extra_args,
dependencies=dependencies)
- def has_header(self, hname, prefix, env, *, extra_args=None, dependencies=None):
+ def has_header(self, hname, prefix, env, *, extra_args=None, dependencies=None, disable_cache=False):
fargs = {'prefix': prefix, 'header': hname}
code = '''{prefix}
#ifdef __has_include
@@ -379,7 +379,7 @@ class CCompiler(Compiler):
#include <{header}>
#endif'''
return self.compiles(code.format(**fargs), env, extra_args=extra_args,
- dependencies=dependencies, mode='preprocess')
+ dependencies=dependencies, mode='preprocess', disable_cache=disable_cache)
def has_header_symbol(self, hname, symbol, prefix, env, *, extra_args=None, dependencies=None):
fargs = {'prefix': prefix, 'header': hname, 'symbol': symbol}
@@ -444,17 +444,19 @@ class CCompiler(Compiler):
args += extra_args
return args
- def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile'):
- with self._build_wrapper(code, env, extra_args, dependencies, mode) as p:
- return p.returncode == 0
+ def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile', disable_cache=False):
+ with self._build_wrapper(code, env, extra_args, dependencies, mode, disable_cache=disable_cache) as p:
+ return p.returncode == 0, p.cached
- def _build_wrapper(self, code, env, extra_args, dependencies=None, mode='compile', want_output=False):
+ def _build_wrapper(self, code, env, extra_args, dependencies=None, mode='compile', want_output=False, disable_cache=False):
args = self._get_compiler_check_args(env, extra_args, dependencies, mode)
- return self.compile(code, args, mode, want_output=want_output)
+ if disable_cache or want_output:
+ return self.compile(code, extra_args=args, mode=mode, want_output=want_output)
+ return self.cached_compile(code, env.coredata, extra_args=args, mode=mode)
- def links(self, code, env, *, extra_args=None, dependencies=None):
+ def links(self, code, env, *, extra_args=None, dependencies=None, disable_cache=False):
return self.compiles(code, env, extra_args=extra_args,
- dependencies=dependencies, mode='link')
+ dependencies=dependencies, mode='link', disable_cache=disable_cache)
def run(self, code: str, env, *, extra_args=None, dependencies=None):
if self.is_cross and self.exe_wrapper is None:
@@ -487,7 +489,7 @@ class CCompiler(Compiler):
{prefix}
int main() {{ static int a[1-2*!({expression})]; a[0]=0; return 0; }}'''
return self.compiles(t.format(**fargs), env, extra_args=extra_args,
- dependencies=dependencies)
+ dependencies=dependencies)[0]
def cross_compute_int(self, expression, low, high, guess, prefix, env, extra_args, dependencies):
# Try user's guess first
@@ -567,7 +569,7 @@ class CCompiler(Compiler):
{type} something;
}}'''
if not self.compiles(t.format(**fargs), env, extra_args=extra_args,
- dependencies=dependencies):
+ dependencies=dependencies)[0]:
return -1
return self.cross_compute_int('sizeof(%s)' % typename, None, None, None, prefix, env, extra_args, dependencies)
@@ -602,7 +604,7 @@ class CCompiler(Compiler):
{type} something;
}}'''
if not self.compiles(t.format(**fargs), env, extra_args=extra_args,
- dependencies=dependencies):
+ dependencies=dependencies)[0]:
return -1
t = '''#include <stddef.h>
{prefix}
@@ -641,7 +643,7 @@ class CCompiler(Compiler):
raise EnvironmentException('Could not determine alignment of %s. Sorry. You might want to file a bug.' % typename)
return align
- def get_define(self, dname, prefix, env, extra_args, dependencies):
+ def get_define(self, dname, prefix, env, extra_args, dependencies, disable_cache=False):
delim = '"MESON_GET_DEFINE_DELIMITER"'
fargs = {'prefix': prefix, 'define': dname, 'delim': delim}
code = '''
@@ -652,13 +654,17 @@ class CCompiler(Compiler):
{delim}\n{define}'''
args = self._get_compiler_check_args(env, extra_args, dependencies,
mode='preprocess').to_native()
- with self.compile(code.format(**fargs), args, 'preprocess') as p:
+ func = lambda: self.cached_compile(code.format(**fargs), env.coredata, extra_args=args, mode='preprocess')
+ if disable_cache:
+ func = lambda: self.compile(code.format(**fargs), extra_args=args, mode='preprocess')
+ with func() as p:
+ cached = p.cached
if p.returncode != 0:
raise EnvironmentException('Could not get define {!r}'.format(dname))
# Get the preprocessed value after the delimiter,
# minus the extra newline at the end and
# merge string literals.
- return CCompiler.concatenate_string_literals(p.stdo.split(delim + '\n')[-1][:-1])
+ return CCompiler.concatenate_string_literals(p.stdo.split(delim + '\n')[-1][:-1]), cached
def get_return_value(self, fname, rtype, prefix, env, extra_args, dependencies):
if rtype == 'string':
@@ -762,7 +768,7 @@ class CCompiler(Compiler):
val = env.properties.host.get(varname, None)
if val is not None:
if isinstance(val, bool):
- return val
+ return val, False
raise EnvironmentException('Cross variable {0} is not a boolean.'.format(varname))
fargs = {'prefix': prefix, 'func': funcname}
@@ -792,13 +798,14 @@ class CCompiler(Compiler):
head, main = self._no_prototype_templ()
templ = head + stubs_fail + main
- if self.links(templ.format(**fargs), env, extra_args=extra_args,
- dependencies=dependencies):
- return True
+ res, cached = self.links(templ.format(**fargs), env, extra_args=extra_args,
+ dependencies=dependencies)
+ if res:
+ return True, cached
# MSVC does not have compiler __builtin_-s.
if self.get_id() == 'msvc':
- return False
+ return False, False
# Detect function as a built-in
#
@@ -1020,7 +1027,7 @@ class CCompiler(Compiler):
libname in self.internal_libs):
args = ['-l' + libname]
largs = self.linker_to_compiler_args(self.get_allow_undefined_link_args())
- if self.links(code, env, extra_args=(args + largs)):
+ if self.links(code, env, extra_args=(args + largs), disable_cache=True)[0]:
return args
# Don't do a manual search for internal libs
if libname in self.internal_libs:
@@ -1036,7 +1043,7 @@ class CCompiler(Compiler):
elf_class = 2
else:
elf_class = 1
- except:
+ except (MesonException, KeyError): # TODO evaluate if catching KeyError is wanted here
elf_class = 0
# Search in the specified dirs, and then in the system libraries
for d in itertools.chain(extra_dirs, self.get_library_dirs(env, elf_class)):
@@ -1109,7 +1116,7 @@ class CCompiler(Compiler):
# then we must also pass -L/usr/lib to pick up libSystem.dylib
extra_args = [] if allow_system else ['-Z', '-L/usr/lib']
link_args += ['-framework', name]
- if self.links(code, env, extra_args=(extra_args + link_args)):
+ if self.links(code, env, extra_args=(extra_args + link_args), disable_cache=True)[0]:
return link_args
def find_framework_impl(self, name, env, extra_dirs, allow_system):
@@ -1176,7 +1183,7 @@ class CCompiler(Compiler):
fatal_warnings_args = ['-Wl,--fatal-warnings']
if self.has_fatal_warnings_link_arg is None:
self.has_fatal_warnings_link_arg = False
- self.has_fatal_warnings_link_arg = self.has_multi_link_arguments(fatal_warnings_args, env)
+ self.has_fatal_warnings_link_arg = self.has_multi_link_arguments(fatal_warnings_args, env)[0]
if self.has_fatal_warnings_link_arg:
args = fatal_warnings_args + args
@@ -1201,7 +1208,7 @@ class CCompiler(Compiler):
if not (for_windows(env.is_cross_build(), env) or
for_cygwin(env.is_cross_build(), env)):
if name in ['dllimport', 'dllexport']:
- return False
+ return False, False
# Clang and GCC both return warnings if the __attribute__ is undefined,
# so set -Werror
@@ -1348,7 +1355,7 @@ class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler):
# So we should explicitly fail at this case.
def has_function(self, funcname, prefix, env, *, extra_args=None, dependencies=None):
if funcname == 'lchmod':
- return False
+ return False, False
else:
return super().has_function(funcname, prefix, env,
extra_args=extra_args,
@@ -1609,8 +1616,8 @@ class VisualStudioCCompiler(CCompiler):
args = args + ['-Werror=unknown-argument']
with self._build_wrapper(code, env, extra_args=args, mode=mode) as p:
if p.returncode != 0:
- return False
- return not(warning_text in p.stde or warning_text in p.stdo)
+ return False, p.cached
+ return not(warning_text in p.stde or warning_text in p.stdo), p.cached
def get_compile_debugfile_args(self, rel_obj, pch=False):
pdbarr = rel_obj.split('.')[:-1]
@@ -1706,7 +1713,7 @@ class VisualStudioCCompiler(CCompiler):
def has_func_attribute(self, name, env):
# MSVC doesn't have __attribute__ like Clang and GCC do, so just return
# false without compiling anything
- return name in ['dllimport', 'dllexport']
+ return name in ['dllimport', 'dllexport'], False
def get_argument_syntax(self):
return 'msvc'
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index 04cc31a..2f3c7b7 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -875,8 +875,6 @@ class Compiler:
# Libraries that are internal compiler implementations, and must not be
# manually searched.
internal_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):
@@ -903,7 +901,7 @@ class Compiler:
return repr_str.format(self.__class__.__name__, self.version,
' '.join(self.exelist))
- def can_compile(self, src):
+ def can_compile(self, src) -> bool:
if hasattr(src, 'fname'):
src = src.fname
suffix = os.path.splitext(src)[1].lower()
@@ -911,40 +909,40 @@ class Compiler:
return True
return False
- def get_id(self):
+ def get_id(self) -> str:
return self.id
- def get_version_string(self):
+ def get_version_string(self) -> str:
details = [self.id, self.version]
if self.full_version:
details += ['"%s"' % (self.full_version)]
return '(%s)' % (' '.join(details))
- def get_language(self):
+ def get_language(self) -> str:
return self.language
- def get_display_language(self):
+ def get_display_language(self) -> str:
return self.language.capitalize()
- def get_default_suffix(self):
+ def get_default_suffix(self) -> str:
return self.default_suffix
- def get_define(self, dname, prefix, env, extra_args, dependencies):
+ def get_define(self, dname, prefix, env, extra_args, dependencies) -> Tuple[str, bool]:
raise EnvironmentException('%s does not support get_define ' % self.get_id())
- def compute_int(self, expression, low, high, guess, prefix, env, extra_args, dependencies):
+ def compute_int(self, expression, low, high, guess, prefix, env, extra_args, dependencies) -> int:
raise EnvironmentException('%s does not support compute_int ' % self.get_id())
def compute_parameters_with_absolute_paths(self, parameter_list, build_dir):
raise EnvironmentException('%s does not support compute_parameters_with_absolute_paths ' % self.get_id())
- def has_members(self, typename, membernames, prefix, env, *, extra_args=None, dependencies=None):
+ def has_members(self, typename, membernames, prefix, env, *, extra_args=None, dependencies=None) -> Tuple[bool, bool]:
raise EnvironmentException('%s does not support has_member(s) ' % self.get_id())
- def has_type(self, typename, prefix, env, extra_args, *, dependencies=None):
+ def has_type(self, typename, prefix, env, extra_args, *, dependencies=None) -> Tuple[bool, bool]:
raise EnvironmentException('%s does not support has_type ' % self.get_id())
- def symbols_have_underscore_prefix(self, env):
+ def symbols_have_underscore_prefix(self, env) -> bool:
raise EnvironmentException('%s does not support symbols_have_underscore_prefix ' % self.get_id())
def get_exelist(self):
@@ -1087,31 +1085,31 @@ class Compiler:
def get_option_link_args(self, options):
return []
- def check_header(self, *args, **kwargs):
+ def check_header(self, *args, **kwargs) -> Tuple[bool, bool]:
raise EnvironmentException('Language %s does not support header checks.' % self.get_display_language())
- def has_header(self, *args, **kwargs):
+ def has_header(self, *args, **kwargs) -> Tuple[bool, bool]:
raise EnvironmentException('Language %s does not support header checks.' % self.get_display_language())
- def has_header_symbol(self, *args, **kwargs):
+ def has_header_symbol(self, *args, **kwargs) -> Tuple[bool, bool]:
raise EnvironmentException('Language %s does not support header symbol checks.' % self.get_display_language())
- def compiles(self, *args, **kwargs):
+ def compiles(self, *args, **kwargs) -> Tuple[bool, bool]:
raise EnvironmentException('Language %s does not support compile checks.' % self.get_display_language())
- def links(self, *args, **kwargs):
+ def links(self, *args, **kwargs) -> Tuple[bool, bool]:
raise EnvironmentException('Language %s does not support link checks.' % self.get_display_language())
- def run(self, *args, **kwargs):
+ def run(self, *args, **kwargs) -> RunResult:
raise EnvironmentException('Language %s does not support run checks.' % self.get_display_language())
- def sizeof(self, *args, **kwargs):
+ def sizeof(self, *args, **kwargs) -> int:
raise EnvironmentException('Language %s does not support sizeof checks.' % self.get_display_language())
- def alignment(self, *args, **kwargs):
+ def alignment(self, *args, **kwargs) -> int:
raise EnvironmentException('Language %s does not support alignment checks.' % self.get_display_language())
- def has_function(self, *args, **kwargs):
+ def has_function(self, *args, **kwargs) -> Tuple[bool, bool]:
raise EnvironmentException('Language %s does not support function checks.' % self.get_display_language())
@classmethod
@@ -1125,12 +1123,12 @@ class Compiler:
def get_library_dirs(self, *args, **kwargs):
return ()
- def has_multi_arguments(self, args, env):
+ def has_multi_arguments(self, args, env) -> Tuple[bool, bool]:
raise EnvironmentException(
'Language {} does not support has_multi_arguments.'.format(
self.get_display_language()))
- def has_multi_link_arguments(self, args, env):
+ def has_multi_link_arguments(self, args, env) -> Tuple[bool, bool]:
raise EnvironmentException(
'Language {} does not support has_multi_link_arguments.'.format(
self.get_display_language()))
@@ -1150,21 +1148,7 @@ class Compiler:
@contextlib.contextmanager
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
- return
try:
with tempfile.TemporaryDirectory() as tmpdirname:
if isinstance(code, str):
@@ -1206,8 +1190,7 @@ class Compiler:
p.input_name = srcname
if want_output:
p.output_name = output
- else:
- self.compiler_check_cache[key] = p
+ p.cached = False # Make sure that the cached attribute always exists
yield p
except (PermissionError, OSError):
# On Windows antivirus programs and the like hold on to files so
@@ -1215,6 +1198,39 @@ class Compiler:
# catch OSError because the directory is then no longer empty.
pass
+ @contextlib.contextmanager
+ def cached_compile(self, code, cdata: coredata.CoreData, extra_args=None, mode: str = 'link'):
+ assert(isinstance(cdata, coredata.CoreData))
+
+ # Calculate the key
+ textra_args = tuple(extra_args) if extra_args is not None else None
+ key = (tuple(self.exelist), self.version, code, textra_args, mode)
+
+ # Check if not cached
+ if key not in cdata.compiler_check_cache:
+ with self.compile(code, extra_args=extra_args, mode=mode, want_output=False) as p:
+ # Remove all attributes except the following
+ # This way the object can be serialized
+ tokeep = ['args', 'commands', 'input_name', 'output_name',
+ 'pid', 'returncode', 'stdo', 'stde', 'text_mode']
+ todel = [x for x in vars(p).keys() if x not in tokeep]
+ for i in todel:
+ delattr(p, i)
+ p.cached = False
+ cdata.compiler_check_cache[key] = p
+ yield p
+ return
+
+ # Return cached
+ p = cdata.compiler_check_cache[key]
+ p.cached = True
+ 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
+
def get_colorout_args(self, colortype):
return []
diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py
index 2b2c4a0..e2bcaf0 100644
--- a/mesonbuild/compilers/cpp.py
+++ b/mesonbuild/compilers/cpp.py
@@ -64,10 +64,11 @@ class CPPCompiler(CCompiler):
def has_header_symbol(self, hname, symbol, prefix, env, *, extra_args=None, dependencies=None):
# Check if it's a C-like symbol
- if super().has_header_symbol(hname, symbol, prefix, env,
- extra_args=extra_args,
- dependencies=dependencies):
- return True
+ found, cached = super().has_header_symbol(hname, symbol, prefix, env,
+ extra_args=extra_args,
+ dependencies=dependencies)
+ if found:
+ return True, cached
# Check if it's a class or a template
if extra_args is None:
extra_args = []
@@ -263,7 +264,7 @@ class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler):
# So we should explicitly fail at this case.
def has_function(self, funcname, prefix, env, *, extra_args=None, dependencies=None):
if funcname == 'lchmod':
- return False
+ return False, False
else:
return super().has_function(funcname, prefix, env,
extra_args=extra_args,
diff --git a/mesonbuild/compilers/cs.py b/mesonbuild/compilers/cs.py
index cd67da0..c6355f2 100644
--- a/mesonbuild/compilers/cs.py
+++ b/mesonbuild/compilers/cs.py
@@ -28,10 +28,10 @@ cs_optimization_args = {'0': [],
}
class CsCompiler(Compiler):
- def __init__(self, exelist, version, id, runner=None):
+ def __init__(self, exelist, version, comp_id, runner=None):
self.language = 'cs'
super().__init__(exelist, version)
- self.id = id
+ self.id = comp_id
self.is_cross = False
self.runner = runner
diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py
index 21fa498..51a1300 100644
--- a/mesonbuild/compilers/cuda.py
+++ b/mesonbuild/compilers/cuda.py
@@ -146,8 +146,9 @@ class CudaCompiler(Compiler):
return super().get_compiler_check_args() + []
def has_header_symbol(self, hname, symbol, prefix, env, extra_args=None, dependencies=None):
- if super().has_header_symbol(hname, symbol, prefix, env, extra_args, dependencies):
- return True
+ result, cached = super().has_header_symbol(hname, symbol, prefix, env, extra_args, dependencies)
+ if result:
+ return True, cached
if extra_args is None:
extra_args = []
fargs = {'prefix': prefix, 'header': hname, 'symbol': symbol}
diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py
index 529919b..46cc054 100644
--- a/mesonbuild/compilers/d.py
+++ b/mesonbuild/compilers/d.py
@@ -326,8 +326,8 @@ class DCompiler(Compiler):
def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile'):
args = self._get_compiler_check_args(env, extra_args, dependencies, mode)
- with self.compile(code, args, mode) as p:
- return p.returncode == 0
+ with self.cached_compile(code, env.coredata, extra_args=args, mode=mode) as p:
+ return p.returncode == 0, p.cached
def has_multi_arguments(self, args, env):
return self.compiles('int i;\n', env, extra_args=args)
diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py
index dd54fd0..b4eb327 100644
--- a/mesonbuild/compilers/fortran.py
+++ b/mesonbuild/compilers/fortran.py
@@ -250,16 +250,16 @@ class FortranCompiler(Compiler):
def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'):
return CCompiler._get_compiler_check_args(self, env, extra_args, dependencies, mode=mode)
- def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile'):
+ def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile', disable_cache=False):
return CCompiler.compiles(self, code, env, extra_args=extra_args,
- dependencies=dependencies, mode=mode)
+ dependencies=dependencies, mode=mode, disable_cache=disable_cache)
- def _build_wrapper(self, code, env, extra_args, dependencies=None, mode='compile', want_output=False):
- return CCompiler._build_wrapper(self, code, env, extra_args, dependencies, mode, want_output)
+ def _build_wrapper(self, code, env, extra_args, dependencies=None, mode='compile', want_output=False, disable_cache=False):
+ return CCompiler._build_wrapper(self, code, env, extra_args, dependencies, mode, want_output, disable_cache=disable_cache)
- def links(self, code, env, *, extra_args=None, dependencies=None):
+ def links(self, code, env, *, extra_args=None, dependencies=None, disable_cache=False):
return CCompiler.links(self, code, env, extra_args=extra_args,
- dependencies=dependencies)
+ dependencies=dependencies, disable_cache=disable_cache)
def run(self, code, env, *, extra_args=None, dependencies=None):
return CCompiler.run(self, code, env, extra_args=extra_args, dependencies=dependencies)
@@ -297,11 +297,11 @@ class FortranCompiler(Compiler):
def has_multi_arguments(self, args, env):
return CCompiler.has_multi_arguments(self, args, env)
- def has_header(self, hname, prefix, env, *, extra_args=None, dependencies=None):
- return CCompiler.has_header(self, hname, prefix, env, extra_args=extra_args, dependencies=dependencies)
+ def has_header(self, hname, prefix, env, *, extra_args=None, dependencies=None, disable_cache=False):
+ return CCompiler.has_header(self, hname, prefix, env, extra_args=extra_args, dependencies=dependencies, disable_cache=disable_cache)
- def get_define(self, dname, prefix, env, extra_args, dependencies):
- return CCompiler.get_define(self, dname, prefix, env, extra_args, dependencies)
+ def get_define(self, dname, prefix, env, extra_args, dependencies, disable_cache=False):
+ return CCompiler.get_define(self, dname, prefix, env, extra_args, dependencies, disable_cache=disable_cache)
@classmethod
def _get_trials_from_pattern(cls, pattern, directory, libname):
@@ -333,7 +333,6 @@ class GnuFortranCompiler(GnuCompiler, FortranCompiler):
def language_stdlib_only_link_flags(self):
return ['-lgfortran', '-lm']
-
class ElbrusFortranCompiler(GnuFortranCompiler, ElbrusCompiler):
def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, defines=None, **kwargs):
GnuFortranCompiler.__init__(self, exelist, version, compiler_type, is_cross, exe_wrapper, defines, **kwargs)
@@ -427,6 +426,9 @@ class PGIFortranCompiler(PGICompiler, FortranCompiler):
FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwags)
PGICompiler.__init__(self, compiler_type)
+ def language_stdlib_only_link_flags(self) -> List[str]:
+ return ['-lpgf90rtl', '-lpgf90', '-lpgf90_rpm1', '-lpgf902',
+ '-lpgf90rtl', '-lpgftnrtl', '-lrt']
class FlangFortranCompiler(ClangCompiler, FortranCompiler):
def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags):
diff --git a/mesonbuild/compilers/vala.py b/mesonbuild/compilers/vala.py
index 98b8b42..c0b2a68 100644
--- a/mesonbuild/compilers/vala.py
+++ b/mesonbuild/compilers/vala.py
@@ -96,7 +96,7 @@ class ValaCompiler(Compiler):
extra_flags += self.get_compile_only_args()
else:
extra_flags += environment.coredata.get_external_link_args(for_machine, self.language)
- with self.compile(code, extra_flags, 'compile') as p:
+ with self.cached_compile(code, environment.coredata, extra_args=extra_flags, mode='compile') as p:
if p.returncode != 0:
msg = 'Vala compiler {!r} can not compile programs' \
''.format(self.name_string())
@@ -121,7 +121,7 @@ class ValaCompiler(Compiler):
args = env.coredata.get_external_args(for_machine, self.language)
vapi_args = ['--pkg', libname]
args += vapi_args
- with self.compile(code, args, 'compile') as p:
+ with self.cached_compile(code, env.coredata, extra_args=args, mode='compile') as p:
if p.returncode == 0:
return vapi_args
# Not found? Try to find the vapi file itself.
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index b836086..183b333 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -247,6 +247,7 @@ class CoreData:
self.compilers = OrderedDict()
self.cross_compilers = OrderedDict()
self.deps = OrderedDict()
+ self.compiler_check_cache = OrderedDict()
# Only to print a warning if it changes between Meson invocations.
self.config_files = self.__load_config_files(options.native_file, 'native')
self.libdir_cross_fixup()
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index 8432ab6..7a10d69 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -940,9 +940,11 @@ class CMakeTraceLine:
return s.format(self.file, self.line, self.func, self.args)
class CMakeTarget:
- def __init__(self, name, type, properies = {}):
+ def __init__(self, name, target_type, properies=None):
+ if properies is None:
+ properies = {}
self.name = name
- self.type = type
+ self.type = target_type
self.properies = properies
def __repr__(self):
@@ -1123,7 +1125,7 @@ class CMakeDependency(ExternalDependency):
for l in lexer1:
if l.func == 'set':
self._cmake_set(l)
- except:
+ except MesonException:
return None
# Extract the variables and sanity check them
diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py
index 46a479e..0de1372 100644
--- a/mesonbuild/dependencies/boost.py
+++ b/mesonbuild/dependencies/boost.py
@@ -250,7 +250,7 @@ class BoostDependency(ExternalDependency):
def detect_headers_and_version(self):
try:
- version = self.clib_compiler.get_define('BOOST_LIB_VERSION', '#include <boost/version.hpp>', self.env, self.get_compile_args(), [])
+ version = self.clib_compiler.get_define('BOOST_LIB_VERSION', '#include <boost/version.hpp>', self.env, self.get_compile_args(), [], disable_cache=True)[0]
except mesonlib.EnvironmentException:
return
except TypeError:
diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py
index 55cb569..72ba7b3 100644
--- a/mesonbuild/dependencies/misc.py
+++ b/mesonbuild/dependencies/misc.py
@@ -368,7 +368,7 @@ class OpenMPDependency(ExternalDependency):
self.is_found = False
try:
openmp_date = self.clib_compiler.get_define(
- '_OPENMP', '', self.env, self.clib_compiler.openmp_flags(), [self])
+ '_OPENMP', '', self.env, self.clib_compiler.openmp_flags(), [self], disable_cache=True)[0]
except mesonlib.EnvironmentException as e:
mlog.debug('OpenMP support not available in the compiler')
mlog.debug(e)
@@ -376,7 +376,7 @@ class OpenMPDependency(ExternalDependency):
if openmp_date:
self.version = self.VERSIONS[openmp_date]
- if self.clib_compiler.has_header('omp.h', '', self.env, dependencies=[self]):
+ if self.clib_compiler.has_header('omp.h', '', self.env, dependencies=[self], disable_cache=True)[0]:
self.is_found = True
self.compile_args = self.link_args = self.clib_compiler.openmp_flags()
else:
diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py
index ce1ca68..b1fa632 100644
--- a/mesonbuild/dependencies/ui.py
+++ b/mesonbuild/dependencies/ui.py
@@ -298,8 +298,8 @@ class QtBaseDependency(ExternalDependency):
# the Qt + m_name there is not a symlink, it's a file
mod_private_dir = qt_inc_dir
mod_private_inc = _qt_get_private_includes(mod_private_dir, m_name, m.version)
- for dir in mod_private_inc:
- self.compile_args.append('-I' + dir)
+ for directory in mod_private_inc:
+ self.compile_args.append('-I' + directory)
self.link_args += m.get_link_args()
if 'Core' in modules:
@@ -402,8 +402,8 @@ class QtBaseDependency(ExternalDependency):
if self.private_headers:
priv_inc = self.get_private_includes(mincdir, module)
- for dir in priv_inc:
- self.compile_args.append('-I' + dir)
+ for directory in priv_inc:
+ self.compile_args.append('-I' + directory)
libfile = self.clib_compiler.find_library(self.qtpkgname + module + modules_lib_suffix,
self.env,
libdir)
@@ -641,7 +641,7 @@ class VulkanDependency(ExternalDependency):
else:
# simply try to guess it, usually works on linux
libs = self.clib_compiler.find_library('vulkan', environment, [])
- if libs is not None and self.clib_compiler.has_header('vulkan/vulkan.h', '', environment):
+ if libs is not None and self.clib_compiler.has_header('vulkan/vulkan.h', '', environment, disable_cache=True)[0]:
self.type_name = 'system'
self.is_found = True
for lib in libs:
diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py
index 977d930..70f964e 100644
--- a/mesonbuild/envconfig.py
+++ b/mesonbuild/envconfig.py
@@ -134,7 +134,7 @@ class Properties(HasEnvVarFallback):
def get_sys_root(self) -> typing.Optional[typing.Union[str, typing.List[str]]]:
return self.properties.get('sys_root', None)
- def __eq__(self, other: typing.Any) -> typing.Union[bool, 'NotImplemented']:
+ def __eq__(self, other: typing.Any) -> 'typing.Union[bool, NotImplemented]':
if isinstance(other, type(self)):
return self.properties == other.properties
return NotImplemented
@@ -159,7 +159,7 @@ class MachineInfo:
self.endian = endian
self.is_64_bit = cpu_family in CPU_FAMILES_64_BIT # type: bool
- def __eq__(self, other: typing.Any) -> typing.Union[bool, 'NotImplemented']:
+ def __eq__(self, other: typing.Any) -> 'typing.Union[bool, NotImplemented]':
if self.__class__ is not other.__class__:
return NotImplemented
return \
@@ -168,7 +168,7 @@ class MachineInfo:
self.cpu == other.cpu and \
self.endian == other.endian
- def __ne__(self, other: typing.Any) -> typing.Union[bool, 'NotImplemented']:
+ def __ne__(self, other: typing.Any) -> 'typing.Union[bool, NotImplemented]':
if self.__class__ is not other.__class__:
return NotImplemented
return not self.__eq__(other)
@@ -198,7 +198,7 @@ class MachineInfo:
"""
Machine is windows?
"""
- return self.system == 'windows'
+ return self.system in {'windows', 'mingw'}
def is_cygwin(self) -> bool:
"""
@@ -216,7 +216,7 @@ class MachineInfo:
"""
Machine is Darwin (iOS/OS X)?
"""
- return self.system in ('darwin', 'ios')
+ return self.system in {'darwin', 'ios'}
def is_android(self) -> bool:
"""
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index a3505a4..ba97083 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1134,16 +1134,17 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Prefix argument of has_member must be a string.')
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
- had = self.compiler.has_members(typename, [membername], prefix,
- self.environment,
- extra_args=extra_args,
- dependencies=deps)
+ had, cached = self.compiler.has_members(typename, [membername], prefix,
+ self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
+ cached = '(cached)' if cached else ''
if had:
hadtxt = mlog.green('YES')
else:
hadtxt = mlog.red('NO')
mlog.log('Checking whether type', mlog.bold(typename, True),
- 'has member', mlog.bold(membername, True), msg, hadtxt)
+ 'has member', mlog.bold(membername, True), msg, hadtxt, cached)
return had
@permittedKwargs({
@@ -1163,17 +1164,18 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Prefix argument of has_members must be a string.')
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
- had = self.compiler.has_members(typename, membernames, prefix,
- self.environment,
- extra_args=extra_args,
- dependencies=deps)
+ had, cached = self.compiler.has_members(typename, membernames, prefix,
+ self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
+ cached = '(cached)' if cached else ''
if had:
hadtxt = mlog.green('YES')
else:
hadtxt = mlog.red('NO')
members = mlog.bold(', '.join(['"{}"'.format(m) for m in membernames]))
mlog.log('Checking whether type', mlog.bold(typename, True),
- 'has members', members, msg, hadtxt)
+ 'has members', members, msg, hadtxt, cached)
return had
@permittedKwargs({
@@ -1193,14 +1195,15 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Prefix argument of has_function must be a string.')
extra_args = self.determine_args(kwargs)
deps, msg = self.determine_dependencies(kwargs)
- had = self.compiler.has_function(funcname, prefix, self.environment,
- extra_args=extra_args,
- dependencies=deps)
+ had, cached = self.compiler.has_function(funcname, prefix, self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
+ cached = '(cached)' if cached else ''
if had:
hadtxt = mlog.green('YES')
else:
hadtxt = mlog.red('NO')
- mlog.log('Checking for function', mlog.bold(funcname, True), msg, hadtxt)
+ mlog.log('Checking for function', mlog.bold(funcname, True), msg, hadtxt, cached)
return had
@permittedKwargs({
@@ -1220,13 +1223,14 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Prefix argument of has_type must be a string.')
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
- had = self.compiler.has_type(typename, prefix, self.environment,
- extra_args=extra_args, dependencies=deps)
+ had, cached = self.compiler.has_type(typename, prefix, self.environment,
+ extra_args=extra_args, dependencies=deps)
+ cached = '(cached)' if cached else ''
if had:
hadtxt = mlog.green('YES')
else:
hadtxt = mlog.red('NO')
- mlog.log('Checking for type', mlog.bold(typename, True), msg, hadtxt)
+ mlog.log('Checking for type', mlog.bold(typename, True), msg, hadtxt, cached)
return had
@FeatureNew('compiler.compute_int', '0.40.0')
@@ -1305,10 +1309,11 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Prefix argument of get_define() must be a string.')
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
- value = self.compiler.get_define(element, prefix, self.environment,
- extra_args=extra_args,
- dependencies=deps)
- mlog.log('Fetching value of define', mlog.bold(element, True), msg, value)
+ value, cached = self.compiler.get_define(element, prefix, self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
+ cached = '(cached)' if cached else ''
+ mlog.log('Fetching value of define', mlog.bold(element, True), msg, value, cached)
return value
@permittedKwargs({
@@ -1332,15 +1337,16 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Testname argument must be a string.')
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs, endl=None)
- result = self.compiler.compiles(code, self.environment,
- extra_args=extra_args,
- dependencies=deps)
+ result, cached = self.compiler.compiles(code, self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
if len(testname) > 0:
if result:
h = mlog.green('YES')
else:
h = mlog.red('NO')
- mlog.log('Checking if', mlog.bold(testname, True), msg, 'compiles:', h)
+ cached = '(cached)' if cached else ''
+ mlog.log('Checking if', mlog.bold(testname, True), msg, 'compiles:', h, cached)
return result
@permittedKwargs({
@@ -1364,15 +1370,16 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Testname argument must be a string.')
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs, endl=None)
- result = self.compiler.links(code, self.environment,
- extra_args=extra_args,
- dependencies=deps)
+ result, cached = self.compiler.links(code, self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
+ cached = '(cached)' if cached else ''
if len(testname) > 0:
if result:
h = mlog.green('YES')
else:
h = mlog.red('NO')
- mlog.log('Checking if', mlog.bold(testname, True), msg, 'links:', h)
+ mlog.log('Checking if', mlog.bold(testname, True), msg, 'links:', h, cached)
return result
@FeatureNew('compiler.check_header', '0.47.0')
@@ -1392,16 +1399,17 @@ class CompilerHolder(InterpreterObject):
return False
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
- haz = self.compiler.check_header(hname, prefix, self.environment,
- extra_args=extra_args,
- dependencies=deps)
+ haz, cached = self.compiler.check_header(hname, prefix, self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
+ cached = '(cached)' if cached else ''
if required and not haz:
raise InterpreterException('{} header {!r} not usable'.format(self.compiler.get_display_language(), hname))
elif haz:
h = mlog.green('YES')
else:
h = mlog.red('NO')
- mlog.log('Check usable header', mlog.bold(hname, True), msg, h)
+ mlog.log('Check usable header', mlog.bold(hname, True), msg, h, cached)
return haz
@FeatureNewKwargs('compiler.has_header', '0.50.0', ['required'])
@@ -1420,15 +1428,16 @@ class CompilerHolder(InterpreterObject):
return False
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
- haz = self.compiler.has_header(hname, prefix, self.environment,
- extra_args=extra_args, dependencies=deps)
+ haz, cached = self.compiler.has_header(hname, prefix, self.environment,
+ extra_args=extra_args, dependencies=deps)
+ cached = '(cached)' if cached else ''
if required and not haz:
raise InterpreterException('{} header {!r} not found'.format(self.compiler.get_display_language(), hname))
elif haz:
h = mlog.green('YES')
else:
h = mlog.red('NO')
- mlog.log('Has header', mlog.bold(hname, True), msg, h)
+ mlog.log('Has header', mlog.bold(hname, True), msg, h, cached)
return haz
@FeatureNewKwargs('compiler.has_header_symbol', '0.50.0', ['required'])
@@ -1447,16 +1456,17 @@ class CompilerHolder(InterpreterObject):
return False
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
- haz = self.compiler.has_header_symbol(hname, symbol, prefix, self.environment,
- extra_args=extra_args,
- dependencies=deps)
+ haz, cached = self.compiler.has_header_symbol(hname, symbol, prefix, self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
if required and not haz:
raise InterpreterException('{} symbol {} not found in header {}'.format(self.compiler.get_display_language(), symbol, hname))
elif haz:
h = mlog.green('YES')
else:
h = mlog.red('NO')
- mlog.log('Header <{0}> has symbol'.format(hname), mlog.bold(symbol, True), msg, h)
+ cached = '(cached)' if cached else ''
+ mlog.log('Header <{0}> has symbol'.format(hname), mlog.bold(symbol, True), msg, h, cached)
return haz
def notfound_library(self, libname):
@@ -1518,15 +1528,16 @@ class CompilerHolder(InterpreterObject):
@permittedKwargs({})
def has_multi_arguments_method(self, args, kwargs):
args = mesonlib.stringlistify(args)
- result = self.compiler.has_multi_arguments(args, self.environment)
+ result, cached = self.compiler.has_multi_arguments(args, self.environment)
if result:
h = mlog.green('YES')
else:
h = mlog.red('NO')
+ cached = '(cached)' if cached else ''
mlog.log(
'Compiler for {} supports arguments {}:'.format(
self.compiler.get_display_language(), ' '.join(args)),
- h)
+ h, cached)
return result
@FeatureNew('compiler.get_supported_arguments', '0.43.0')
@@ -1560,7 +1571,8 @@ class CompilerHolder(InterpreterObject):
@permittedKwargs({})
def has_multi_link_arguments_method(self, args, kwargs):
args = mesonlib.stringlistify(args)
- result = self.compiler.has_multi_link_arguments(args, self.environment)
+ result, cached = self.compiler.has_multi_link_arguments(args, self.environment)
+ cached = '(cached)' if cached else ''
if result:
h = mlog.green('YES')
else:
@@ -1568,7 +1580,7 @@ class CompilerHolder(InterpreterObject):
mlog.log(
'Compiler for {} supports link arguments {}:'.format(
self.compiler.get_display_language(), ' '.join(args)),
- h)
+ h, cached)
return result
@FeatureNew('compiler.get_supported_link_arguments_method', '0.46.0')
@@ -1597,9 +1609,10 @@ class CompilerHolder(InterpreterObject):
args = mesonlib.stringlistify(args)
if len(args) != 1:
raise InterpreterException('has_func_attribute takes exactly one argument.')
- result = self.compiler.has_func_attribute(args[0], self.environment)
+ result, cached = self.compiler.has_func_attribute(args[0], self.environment)
+ cached = '(cached)' if cached else ''
h = mlog.green('YES') if result else mlog.red('NO')
- mlog.log('Compiler for {} supports function attribute {}:'.format(self.compiler.get_display_language(), args[0]), h)
+ mlog.log('Compiler for {} supports function attribute {}:'.format(self.compiler.get_display_language(), args[0]), h, cached)
return result
@FeatureNew('compiler.get_supported_function_attributes', '0.48.0')
@@ -2193,7 +2206,7 @@ class Interpreter(InterpreterBase):
def check_cross_stdlibs(self):
if self.build.environment.is_cross_build():
props = self.build.environment.properties.host
- for l, c in self.build.cross_compilers.items():
+ for l in self.build.cross_compilers.keys():
try:
di = mesonlib.stringlistify(props.get_stdlib(l))
if len(di) != 2:
@@ -2454,7 +2467,7 @@ external dependencies (including libraries) must go to "dependencies".''')
with mlog.nested():
# Suppress the 'ERROR:' prefix because this exception is not
# fatal and VS CI treat any logs with "ERROR:" as fatal.
- mlog.exception(e, prefix=None)
+ mlog.exception(e, prefix=mlog.yellow('Exception:'))
mlog.log('\nSubproject', mlog.bold(dirname), 'is buildable:', mlog.red('NO'), '(disabling)')
return self.disabled_subproject(dirname)
raise e
diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py
index c148cbd..71a4ef3 100644
--- a/mesonbuild/interpreterbase.py
+++ b/mesonbuild/interpreterbase.py
@@ -144,7 +144,7 @@ def stringArgs(f):
return wrapped
def noArgsFlattening(f):
- setattr(f, 'no-args-flattening', True)
+ setattr(f, 'no-args-flattening', True) # noqa: B010
return f
def disablerIfNotFound(f):
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index 1e776e4..f78fa35 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -720,11 +720,11 @@ def has_path_sep(name, sep='/\\'):
return True
return False
-def do_replacement(regex, line, format, confdata):
+def do_replacement(regex, line, variable_format, confdata):
missing_variables = set()
start_tag = '@'
backslash_tag = '\\@'
- if format == 'cmake':
+ if variable_format == 'cmake':
start_tag = '${'
backslash_tag = '\\${'
@@ -777,7 +777,7 @@ def do_mesondefine(line, confdata):
raise MesonException('#mesondefine argument "%s" is of unknown type.' % varname)
-def do_conf_file(src, dst, confdata, format, encoding='utf-8'):
+def do_conf_file(src, dst, confdata, variable_format, encoding='utf-8'):
try:
with open(src, encoding=encoding, newline='') as f:
data = f.readlines()
@@ -785,15 +785,15 @@ def do_conf_file(src, dst, confdata, format, encoding='utf-8'):
raise MesonException('Could not read input file %s: %s' % (src, str(e)))
# Only allow (a-z, A-Z, 0-9, _, -) as valid characters for a define
# Also allow escaping '@' with '\@'
- if format in ['meson', 'cmake@']:
+ if variable_format in ['meson', 'cmake@']:
regex = re.compile(r'(?:\\\\)+(?=\\?@)|\\@|@([-a-zA-Z0-9_]+)@')
- elif format == 'cmake':
+ elif variable_format == 'cmake':
regex = re.compile(r'(?:\\\\)+(?=\\?\$)|\\\${|\${([-a-zA-Z0-9_]+)}')
else:
- raise MesonException('Format "{}" not handled'.format(format))
+ raise MesonException('Format "{}" not handled'.format(variable_format))
search_token = '#mesondefine'
- if format != 'meson':
+ if variable_format != 'meson':
search_token = '#cmakedefine'
result = []
@@ -806,7 +806,7 @@ def do_conf_file(src, dst, confdata, format, encoding='utf-8'):
confdata_useless = False
line = do_mesondefine(line, confdata)
else:
- line, missing = do_replacement(regex, line, format, confdata)
+ line, missing = do_replacement(regex, line, variable_format, confdata)
missing_variables.update(missing)
if missing:
confdata_useless = False
@@ -920,7 +920,8 @@ def extract_as_list(dict_object, *keys, pop=False, **kwargs):
result.append(listify(fetch(key, []), **kwargs))
return result
-def typeslistify(item: typing.Union[_T, typing.List[_T]], types: typing.Union[typing.Type[_T], typing.Tuple[typing.Type[_T]]]) -> typing.List[_T]:
+def typeslistify(item: 'typing.Union[_T, typing.List[_T]]',
+ types: 'typing.Union[typing.Type[_T], typing.Tuple[typing.Type[_T]]]') -> typing.List[_T]:
'''
Ensure that type(@item) is one of @types or a
list of items all of which are of type @types
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index 4326c20..c94f1bf 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -41,41 +41,41 @@ class CommandLineParser:
self.subparsers = self.parser.add_subparsers(title='Commands',
description='If no command is specified it defaults to setup command.')
self.add_command('setup', msetup.add_arguments, msetup.run,
- help='Configure the project')
+ help_msg='Configure the project')
self.add_command('configure', mconf.add_arguments, mconf.run,
- help='Change project options',)
+ help_msg='Change project options',)
self.add_command('install', minstall.add_arguments, minstall.run,
- help='Install the project')
+ help_msg='Install the project')
self.add_command('introspect', mintro.add_arguments, mintro.run,
- help='Introspect project')
+ help_msg='Introspect project')
self.add_command('init', minit.add_arguments, minit.run,
- help='Create a new project')
+ help_msg='Create a new project')
self.add_command('test', mtest.add_arguments, mtest.run,
- help='Run tests')
+ help_msg='Run tests')
self.add_command('wrap', wraptool.add_arguments, wraptool.run,
- help='Wrap tools')
+ help_msg='Wrap tools')
self.add_command('subprojects', msubprojects.add_arguments, msubprojects.run,
- help='Manage subprojects')
+ help_msg='Manage subprojects')
self.add_command('help', self.add_help_arguments, self.run_help_command,
- help='Print help of a subcommand')
+ help_msg='Print help of a subcommand')
self.add_command('rewrite', lambda parser: rewriter.add_arguments(parser, self.formater), rewriter.run,
- help='Modify the project definition')
+ help_msg='Modify the project definition')
# Hidden commands
self.add_command('runpython', self.add_runpython_arguments, self.run_runpython_command,
- help=argparse.SUPPRESS)
+ help_msg=argparse.SUPPRESS)
self.add_command('unstable-coredata', munstable_coredata.add_arguments, munstable_coredata.run,
- help=argparse.SUPPRESS)
+ help_msg=argparse.SUPPRESS)
- def add_command(self, name, add_arguments_func, run_func, help, aliases=None):
+ def add_command(self, name, add_arguments_func, run_func, help_msg, aliases=None):
aliases = aliases or []
# FIXME: Cannot have hidden subparser:
# https://bugs.python.org/issue22848
- if help == argparse.SUPPRESS:
+ if help_msg == argparse.SUPPRESS:
p = argparse.ArgumentParser(prog='meson ' + name, formatter_class=self.formater)
self.hidden_commands.append(name)
else:
- p = self.subparsers.add_parser(name, help=help, aliases=aliases, formatter_class=self.formater)
+ p = self.subparsers.add_parser(name, help=help_msg, aliases=aliases, formatter_class=self.formater)
add_arguments_func(p)
p.set_defaults(run_func=run_func)
for i in [name] + aliases:
diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py
index c6b6bbf..ed82c37 100644
--- a/mesonbuild/minstall.py
+++ b/mesonbuild/minstall.py
@@ -65,7 +65,7 @@ class DirMaker:
def __enter__(self):
return self
- def __exit__(self, type, value, traceback):
+ def __exit__(self, exception_type, value, traceback):
self.dirs.reverse()
for d in self.dirs:
append_to_log(self.lf, d)
@@ -93,7 +93,7 @@ def set_chown(path, user=None, group=None, dir_fd=None, follow_symlinks=True):
dir_fd=dir_fd,
follow_symlinks=follow_symlinks)
shutil.chown(path, user, group)
- except:
+ except Exception:
raise
finally:
os.chown = real_os_chown
diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py
index c47fffd..8c8aa15 100644
--- a/mesonbuild/mintro.py
+++ b/mesonbuild/mintro.py
@@ -117,11 +117,11 @@ def list_installed(installdata):
for t in installdata.targets:
res[os.path.join(installdata.build_dir, t.fname)] = \
os.path.join(installdata.prefix, t.outdir, os.path.basename(t.fname))
- for path, installpath, unused_prefix in installdata.data:
+ for path, installpath, _ in installdata.data:
res[path] = os.path.join(installdata.prefix, installpath)
- for path, installdir, unused_custom_install_mode in installdata.headers:
+ for path, installdir, _ in installdata.headers:
res[path] = os.path.join(installdata.prefix, installdir, os.path.basename(path))
- for path, installpath, unused_custom_install_mode in installdata.man:
+ for path, installpath, _ in installdata.man:
res[path] = os.path.join(installdata.prefix, installpath)
return res
diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py
index e8ee6c8..79dee47 100644
--- a/mesonbuild/mlog.py
+++ b/mesonbuild/mlog.py
@@ -19,6 +19,7 @@ import time
import platform
from contextlib import contextmanager
import typing
+from typing import Any, Generator, List, Optional, Sequence, TextIO, Union
"""This is (mostly) a standalone module used to write logging
information about Meson runs. Some output goes to screen,
@@ -43,11 +44,11 @@ if platform.system().lower() == 'windows':
colorize_console = os.isatty(sys.stdout.fileno()) and _windows_ansi() # type: bool
else:
colorize_console = os.isatty(sys.stdout.fileno()) and os.environ.get('TERM') != 'dumb'
-log_dir = None # type: typing.Optional[str]
-log_file = None # type: typing.Optional[typing.TextIO]
+log_dir = None # type: Optional[str]
+log_file = None # type: Optional[TextIO]
log_fname = 'meson-log.txt' # type: str
log_depth = 0 # type: int
-log_timestamp_start = None # type: typing.Optional[float]
+log_timestamp_start = None # type: Optional[float]
log_fatal_warnings = False # type: bool
log_disable_stdout = False # type: bool
log_errors_only = False # type: bool
@@ -78,7 +79,7 @@ def set_timestamp_start(start: float) -> None:
global log_timestamp_start
log_timestamp_start = start
-def shutdown() -> typing.Optional[str]:
+def shutdown() -> Optional[str]:
global log_file
if log_file is not None:
path = log_file.name
@@ -124,8 +125,8 @@ def cyan(text: str) -> AnsiDecorator:
# This really should be AnsiDecorator or anything that implements
# __str__(), but that requires protocols from typing_extensions
-def process_markup(args: typing.Sequence[typing.Union[AnsiDecorator, str]], keep: bool) -> typing.List[str]:
- arr = [] # type: typing.List[str]
+def process_markup(args: Sequence[Union[AnsiDecorator, str]], keep: bool) -> List[str]:
+ arr = [] # type: List[str]
if log_timestamp_start is not None:
arr = ['[{:.3f}]'.format(time.monotonic() - log_timestamp_start)]
for arg in args:
@@ -139,7 +140,7 @@ def process_markup(args: typing.Sequence[typing.Union[AnsiDecorator, str]], keep
arr.append(str(arg))
return arr
-def force_print(*args: str, **kwargs: typing.Any) -> None:
+def force_print(*args: str, **kwargs: Any) -> None:
global log_disable_stdout
if log_disable_stdout:
return
@@ -160,14 +161,14 @@ def force_print(*args: str, **kwargs: typing.Any) -> None:
print(cleaned, end='')
# We really want a heterogenous dict for this, but that's in typing_extensions
-def debug(*args: typing.Union[str, AnsiDecorator], **kwargs: typing.Any) -> None:
+def debug(*args: Union[str, AnsiDecorator], **kwargs: Any) -> None:
arr = process_markup(args, False)
if log_file is not None:
print(*arr, file=log_file, **kwargs)
log_file.flush()
-def log(*args: typing.Union[str, AnsiDecorator], is_error: bool = False,
- **kwargs: typing.Any) -> None:
+def log(*args: Union[str, AnsiDecorator], is_error: bool = False,
+ **kwargs: Any) -> None:
global log_errors_only
arr = process_markup(args, False)
if log_file is not None:
@@ -178,7 +179,7 @@ def log(*args: typing.Union[str, AnsiDecorator], is_error: bool = False,
if not log_errors_only or is_error:
force_print(*arr, **kwargs)
-def _log_error(severity: str, *rargs: typing.Union[str, AnsiDecorator], **kwargs: typing.Any) -> None:
+def _log_error(severity: str, *rargs: Union[str, AnsiDecorator], **kwargs: Any) -> None:
from .mesonlib import get_error_location_string
from .environment import build_filename
from .mesonlib import MesonException
@@ -186,7 +187,7 @@ def _log_error(severity: str, *rargs: typing.Union[str, AnsiDecorator], **kwargs
# The tping requirements here are non-obvious. Lists are invariant,
# therefore List[A] and List[Union[A, B]] are not able to be joined
if severity == 'warning':
- label = [yellow('WARNING:')] # type: typing.List[typing.Union[str, AnsiDecorator]]
+ label = [yellow('WARNING:')] # type: List[Union[str, AnsiDecorator]]
elif severity == 'error':
label = [red('ERROR:')]
elif severity == 'deprecation':
@@ -202,7 +203,7 @@ def _log_error(severity: str, *rargs: typing.Union[str, AnsiDecorator], **kwargs
location_str = get_error_location_string(location_file, location.lineno)
# Unions are frankly awful, and we have to cast here to get mypy
# to understand that the list concatenation is safe
- location_list = typing.cast(typing.List[typing.Union[str, AnsiDecorator]], [location_str])
+ location_list = typing.cast(List[Union[str, AnsiDecorator]], [location_str])
args = location_list + args
log(*args, **kwargs)
@@ -211,18 +212,20 @@ def _log_error(severity: str, *rargs: typing.Union[str, AnsiDecorator], **kwargs
if log_fatal_warnings:
raise MesonException("Fatal warnings enabled, aborting")
-def error(*args: typing.Union[str, AnsiDecorator], **kwargs: typing.Any) -> None:
+def error(*args: Union[str, AnsiDecorator], **kwargs: Any) -> None:
return _log_error('error', *args, **kwargs, is_error=True)
-def warning(*args: typing.Union[str, AnsiDecorator], **kwargs: typing.Any) -> None:
+def warning(*args: Union[str, AnsiDecorator], **kwargs: Any) -> None:
return _log_error('warning', *args, **kwargs, is_error=True)
-def deprecation(*args: typing.Union[str, AnsiDecorator], **kwargs: typing.Any) -> None:
+def deprecation(*args: Union[str, AnsiDecorator], **kwargs: Any) -> None:
return _log_error('deprecation', *args, **kwargs, is_error=True)
-def exception(e: Exception, prefix: AnsiDecorator = red('ERROR:')) -> None:
+def exception(e: Exception, prefix: Optional[AnsiDecorator] = None) -> None:
+ if prefix is None:
+ prefix = red('ERROR:')
log()
- args = [] # type: typing.List[typing.Union[AnsiDecorator, str]]
+ args = [] # type: List[Union[AnsiDecorator, str]]
if hasattr(e, 'file') and hasattr(e, 'lineno') and hasattr(e, 'colno'):
# Mypy can't figure this out, and it's pretty easy to vidual inspect
# that this is correct, so we'll just ignore it.
@@ -234,19 +237,19 @@ def exception(e: Exception, prefix: AnsiDecorator = red('ERROR:')) -> None:
# Format a list for logging purposes as a string. It separates
# all but the last item with commas, and the last with 'and'.
-def format_list(list_: typing.List[str]) -> str:
- l = len(list_)
+def format_list(input_list: List[str]) -> str:
+ l = len(input_list)
if l > 2:
- return ' and '.join([', '.join(list_[:-1]), list_[-1]])
+ return ' and '.join([', '.join(input_list[:-1]), input_list[-1]])
elif l == 2:
- return ' and '.join(list_)
+ return ' and '.join(input_list)
elif l == 1:
- return list_[0]
+ return input_list[0]
else:
return ''
@contextmanager
-def nested() -> typing.Generator[None, None, None]:
+def nested() -> Generator[None, None, None]:
global log_depth
log_depth += 1
try:
diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py
index a0ebe0e..04941ea 100644
--- a/mesonbuild/modules/python.py
+++ b/mesonbuild/modules/python.py
@@ -477,9 +477,9 @@ class PythonModule(ExtensionModule):
ver = {'python2': '-2', 'python3': '-3'}[name_or_path]
cmd = ['py', ver, '-c', "import sysconfig; print(sysconfig.get_config_var('BINDIR'))"]
_, stdout, _ = mesonlib.Popen_safe(cmd)
- dir = stdout.strip()
- if os.path.exists(dir):
- return os.path.join(dir, 'python')
+ directory = stdout.strip()
+ if os.path.exists(directory):
+ return os.path.join(directory, 'python')
else:
return None
diff --git a/mesonbuild/modules/unstable_simd.py b/mesonbuild/modules/unstable_simd.py
index 18a1099..2f2f67f 100644
--- a/mesonbuild/modules/unstable_simd.py
+++ b/mesonbuild/modules/unstable_simd.py
@@ -66,7 +66,7 @@ class SimdModule(ExtensionModule):
mlog.log('Compiler supports %s:' % iset, mlog.red('NO'))
continue
if args:
- if not compiler.has_multi_arguments(args, state.environment):
+ if not compiler.has_multi_arguments(args, state.environment)[0]:
mlog.log('Compiler supports %s:' % iset, mlog.red('NO'))
continue
mlog.log('Compiler supports %s:' % iset, mlog.green('YES'))
diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py
index e8d266e..87a83fe 100644
--- a/mesonbuild/modules/windows.py
+++ b/mesonbuild/modules/windows.py
@@ -59,7 +59,7 @@ class WindowsModule(ExtensionModule):
if not rescomp.found():
raise MesonException('Could not find Windows resource compiler')
- for (arg, match, type) in [
+ for (arg, match, rc_type) in [
('/?', '^.*Microsoft.*Resource Compiler.*$', ResourceCompilerType.rc),
('--version', '^.*GNU windres.*$', ResourceCompilerType.windres),
]:
@@ -67,7 +67,7 @@ class WindowsModule(ExtensionModule):
m = re.search(match, o, re.MULTILINE)
if m:
mlog.log('Windows resource compiler: %s' % m.group())
- self._rescomp = (rescomp, type)
+ self._rescomp = (rescomp, rc_type)
break
else:
raise MesonException('Could not determine type of Windows resource compiler')
diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py
index 4305a7c..b4fb032 100644
--- a/mesonbuild/mparser.py
+++ b/mesonbuild/mparser.py
@@ -217,7 +217,7 @@ class BaseNode:
fname = 'visit_{}'.format(type(self).__name__)
if hasattr(visitor, fname):
func = getattr(visitor, fname)
- if hasattr(func, '__call__'):
+ if callable(func):
func(self)
class ElementaryNode(BaseNode):
diff --git a/mesonbuild/munstable_coredata.py b/mesonbuild/munstable_coredata.py
index aaf6523..f16468c 100644
--- a/mesonbuild/munstable_coredata.py
+++ b/mesonbuild/munstable_coredata.py
@@ -31,9 +31,12 @@ def dump_compilers(compilers):
print(' ' + lang + ':')
print(' Id: ' + compiler.id)
print(' Command: ' + ' '.join(compiler.exelist))
- print(' Full version: ' + compiler.full_version)
- print(' Detected version: ' + compiler.version)
- print(' Detected type: ' + repr(compiler.compiler_type))
+ if compiler.full_version:
+ print(' Full version: ' + compiler.full_version)
+ if compiler.version:
+ print(' Detected version: ' + compiler.version)
+ if hasattr(compiler, 'compiler_type'):
+ print(' Detected type: ' + repr(compiler.compiler_type))
#pprint.pprint(compiler.__dict__)
@@ -51,7 +54,7 @@ def run(options):
'change the working directory to it.')
return 1
- all = options.all
+ all_backends = options.all
print('This is a dump of the internal unstable cache of meson. This is for debugging only.')
print('Do NOT parse, this will change from version to version in incompatible ways')
@@ -64,18 +67,18 @@ def run(options):
# use `meson configure` to view these
pass
elif k in ['install_guid', 'test_guid', 'regen_guid']:
- if all or backend.startswith('vs'):
+ if all_backends or backend.startswith('vs'):
print(k + ': ' + v)
elif k == 'target_guids':
- if all or backend.startswith('vs'):
+ if all_backends or backend.startswith('vs'):
print(k + ':')
dump_guids(v)
elif k in ['lang_guids']:
- if all or backend.startswith('vs') or backend == 'xcode':
+ if all_backends or backend.startswith('vs') or backend == 'xcode':
print(k + ':')
dump_guids(v)
elif k == 'meson_command':
- if all or backend.startswith('vs'):
+ if all_backends or backend.startswith('vs'):
print('Meson command used in build file regeneration: ' + ' '.join(v))
elif k == 'pkgconf_envvar':
print('Last seen PKGCONFIG enviroment variable value: ' + v)
@@ -97,7 +100,7 @@ def run(options):
native = []
cross = []
for dep_key, dep in sorted(v.items()):
- if dep_key[2]:
+ if dep_key[1]:
cross.append((dep_key, dep))
else:
native.append((dep_key, dep))
diff --git a/mesonbuild/scripts/depfixer.py b/mesonbuild/scripts/depfixer.py
index 7294186..cc4669c 100644
--- a/mesonbuild/scripts/depfixer.py
+++ b/mesonbuild/scripts/depfixer.py
@@ -123,7 +123,7 @@ class Elf(DataSizes):
self.parse_header()
self.parse_sections()
self.parse_dynamic()
- except:
+ except (struct.error, RuntimeError):
self.bf.close()
raise
@@ -180,7 +180,7 @@ class Elf(DataSizes):
def parse_sections(self):
self.bf.seek(self.e_shoff)
self.sections = []
- for i in range(self.e_shnum):
+ for _ in range(self.e_shnum):
self.sections.append(SectionHeader(self.bf, self.ptrsize, self.is_le))
def read_str(self):
diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py
index 4d9d032..3eb68a7 100644
--- a/mesonbuild/wrap/wrap.py
+++ b/mesonbuild/wrap/wrap.py
@@ -84,7 +84,7 @@ class PackageDefinition:
try:
self.config = configparser.ConfigParser(interpolation=None)
self.config.read(fname)
- except:
+ except configparser.Error:
raise WrapException('Failed to parse {}'.format(self.basename))
if len(self.config.sections()) < 1:
raise WrapException('Missing sections in {}'.format(self.basename))
@@ -338,7 +338,7 @@ class Resolver:
"""
Copy directory tree. Overwrites also read only files.
"""
- for src_dir, dirs, files in os.walk(root_src_dir):
+ for src_dir, _, files in os.walk(root_src_dir):
dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
if not os.path.exists(dst_dir):
os.makedirs(dst_dir)
diff --git a/mesonbuild/wrap/wraptool.py b/mesonbuild/wrap/wraptool.py
index 132decf..80cc027 100644
--- a/mesonbuild/wrap/wraptool.py
+++ b/mesonbuild/wrap/wraptool.py
@@ -177,7 +177,7 @@ def promote(options):
# check if the argument is a full path to a subproject directory or wrap file
system_native_path_argument = argument.replace('/', os.sep)
- for _, matches in sprojs.items():
+ for matches in sprojs.values():
if system_native_path_argument in matches:
do_promotion(system_native_path_argument, spdir_name)
return
diff --git a/run_project_tests.py b/run_project_tests.py
index c1d42fc..324d824 100755
--- a/run_project_tests.py
+++ b/run_project_tests.py
@@ -505,6 +505,10 @@ def skippable(suite, test):
if test.endswith('netcdf'):
return True
+ # MSVC doesn't link with GFortran
+ if test.endswith('14 fortran links c'):
+ return True
+
# No frameworks test should be skipped on linux CI, as we expect all
# prerequisites to be installed
if mesonlib.is_linux():
@@ -774,7 +778,7 @@ def detect_system_compiler():
try:
comp = env.compiler_from_language(lang, env.is_cross_build())
details = '%s %s' % (' '.join(comp.get_exelist()), comp.get_version_string())
- except:
+ except mesonlib.MesonException:
comp = None
details = 'not found'
print('%-7s: %s' % (lang, details))
@@ -819,7 +823,7 @@ if __name__ == '__main__':
print(l, '\n')
except UnicodeError:
print(l.encode('ascii', errors='replace').decode(), '\n')
- for name, dirs, skip in all_tests:
+ for name, dirs, _ in all_tests:
dirs = (x.name for x in dirs)
for k, g in itertools.groupby(dirs, key=lambda x: x.split()[0]):
tests = list(g)
diff --git a/run_tests.py b/run_tests.py
index fb3bc28..a4b0fa2 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -136,7 +136,7 @@ def find_vcxproj_with_target(builddir, target):
p = r'<TargetName>{}</TargetName>\s*<TargetExt>\{}</TargetExt>'.format(t, ext)
else:
p = r'<TargetName>{}</TargetName>'.format(t)
- for root, dirs, files in os.walk(builddir):
+ for _, _, files in os.walk(builddir):
for f in fnmatch.filter(files, '*.vcxproj'):
f = os.path.join(builddir, f)
with open(f, 'r', encoding='utf-8') as o:
diff --git a/run_unittests.py b/run_unittests.py
index 110782b..3a473ea 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -1244,7 +1244,7 @@ class BasePlatformTests(unittest.TestCase):
print('Stderr:\n')
print(err)
raise RuntimeError('Configure failed')
- except:
+ except Exception:
self._print_meson_log()
raise
finally:
@@ -1257,7 +1257,7 @@ class BasePlatformTests(unittest.TestCase):
out = self._run(self.setup_command + args + extra_args)
except unittest.SkipTest:
raise unittest.SkipTest('Project requested skipping: ' + srcdir)
- except:
+ except Exception:
self._print_meson_log()
raise
return out
@@ -2681,9 +2681,9 @@ int main(int argc, char **argv) {
if ninja is None:
raise unittest.SkipTest('This test currently requires ninja. Fix this once "meson build" works.')
for lang in ('c', 'cpp'):
- for type in ('executable', 'library'):
+ for target_type in ('executable', 'library'):
with tempfile.TemporaryDirectory() as tmpdir:
- self._run(self.meson_command + ['init', '--language', lang, '--type', type],
+ self._run(self.meson_command + ['init', '--language', lang, '--type', target_type],
workdir=tmpdir)
self._run(self.setup_command + ['--backend=ninja', 'builddir'],
workdir=tmpdir)
@@ -3642,6 +3642,12 @@ recommended as it is not supported on some platforms''')
self.maxDiff = None
self.assertListEqual(res_nb, expected)
+ def test_unstable_coredata(self):
+ testdir = os.path.join(self.common_test_dir, '1 trivial')
+ self.init(testdir)
+ # just test that the command does not fail (e.g. because it throws an exception)
+ self._run([*self.meson_command, 'unstable-coredata', self.builddir])
+
class FailureTests(BasePlatformTests):
'''
Tests that test failure conditions. Build files here should be dynamically
@@ -4443,7 +4449,7 @@ class LinuxlikeTests(BasePlatformTests):
self.assertIn(cmd_std, cmd)
try:
self.build()
- except:
+ except Exception:
print('{} was {!r}'.format(lang_std, v))
raise
self.wipe()
@@ -5527,7 +5533,7 @@ class RewriterTests(BasePlatformTests):
out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
expected = {'name': 'myExe', 'sources': ['main.cpp']}
self.assertEqual(len(out['target']), 2)
- for _, val in out['target'].items():
+ for val in out['target'].values():
self.assertDictEqual(expected, val)
def test_kwargs_info(self):
diff --git a/setup.cfg b/setup.cfg
index 7a94d85..d818786 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -28,4 +28,6 @@ ignore =
E722
# W504: line break after binary operator
W504
+ # A003: builtin class attribute
+ A003
max-line-length = 120
diff --git a/sideci.yml b/sideci.yml
index 2e95afd..5c56196 100644
--- a/sideci.yml
+++ b/sideci.yml
@@ -1,3 +1,7 @@
linter:
flake8:
version: 3
+ plugins:
+ - flake8-blind-except
+ - flake8-builtins
+ - flake8-bugbear
diff --git a/test cases/fortran/14 fortran links c/clib.c b/test cases/fortran/14 fortran links c/clib.c
new file mode 100644
index 0000000..81b2e0c
--- /dev/null
+++ b/test cases/fortran/14 fortran links c/clib.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void hello(void){
+
+ printf("hello from C\n");
+
+}
diff --git a/test cases/fortran/14 fortran links c/f_call_c.f90 b/test cases/fortran/14 fortran links c/f_call_c.f90
new file mode 100644
index 0000000..af1e79c
--- /dev/null
+++ b/test cases/fortran/14 fortran links c/f_call_c.f90
@@ -0,0 +1,10 @@
+implicit none
+
+interface
+subroutine hello() bind (c)
+end subroutine hello
+end interface
+
+call hello()
+
+end program
diff --git a/test cases/fortran/14 fortran links c/meson.build b/test cases/fortran/14 fortran links c/meson.build
new file mode 100644
index 0000000..163aec6
--- /dev/null
+++ b/test cases/fortran/14 fortran links c/meson.build
@@ -0,0 +1,13 @@
+project('Fortran calling C', 'fortran', 'c')
+
+ccid = meson.get_compiler('c').get_id()
+if ccid == 'msvc' or ccid == 'clang-cl'
+ error('MESON_SKIP_TEST: MSVC and GCC do not interoperate like this.')
+endif
+
+c_lib = library('clib', 'clib.c')
+
+f_call_c = executable('f_call_c', 'f_call_c.f90',
+ link_with: c_lib,
+ link_language: 'fortran')
+test('Fortran calling C', f_call_c)
diff --git a/tools/boost_names.py b/tools/boost_names.py
index d381162..d0e5444 100755
--- a/tools/boost_names.py
+++ b/tools/boost_names.py
@@ -132,7 +132,7 @@ def get_modules_2():
# The python module uses an older build system format and is not easily parseable.
# We add the python module libraries manually.
modules.append(Module('python', 'Python', ['boost_python', 'boost_python3', 'boost_numpy', 'boost_numpy3']))
- for (root, dirs, files) in os.walk(LIBS):
+ for (root, _, files) in os.walk(LIBS):
for f in files:
if f == "libraries.json":
projectdir = os.path.dirname(root)