diff options
Diffstat (limited to 'meson/mesonbuild/interpreter/compiler.py')
-rw-r--r-- | meson/mesonbuild/interpreter/compiler.py | 785 |
1 files changed, 785 insertions, 0 deletions
diff --git a/meson/mesonbuild/interpreter/compiler.py b/meson/mesonbuild/interpreter/compiler.py new file mode 100644 index 000000000..b1eef2fe5 --- /dev/null +++ b/meson/mesonbuild/interpreter/compiler.py @@ -0,0 +1,785 @@ +import functools + +from ..interpreterbase.decorators import typed_kwargs, KwargInfo + +from .interpreterobjects import (extract_required_kwarg, extract_search_dirs) + +from .. import mesonlib +from .. import mlog +from .. import dependencies +from ..interpreterbase import (ObjectHolder, noPosargs, noKwargs, permittedKwargs, + FeatureNew, FeatureNewKwargs, disablerIfNotFound, + check_stringlist, InterpreterException, InvalidArguments) + +import typing as T +import os + +if T.TYPE_CHECKING: + from ..interpreter import Interpreter + from ..compilers import Compiler, RunResult + +class TryRunResultHolder(ObjectHolder['RunResult']): + def __init__(self, res: 'RunResult', interpreter: 'Interpreter'): + super().__init__(res, interpreter) + self.methods.update({'returncode': self.returncode_method, + 'compiled': self.compiled_method, + 'stdout': self.stdout_method, + 'stderr': self.stderr_method, + }) + + @noPosargs + @permittedKwargs({}) + def returncode_method(self, args, kwargs): + return self.held_object.returncode + + @noPosargs + @permittedKwargs({}) + def compiled_method(self, args, kwargs): + return self.held_object.compiled + + @noPosargs + @permittedKwargs({}) + def stdout_method(self, args, kwargs): + return self.held_object.stdout + + @noPosargs + @permittedKwargs({}) + def stderr_method(self, args, kwargs): + return self.held_object.stderr + +header_permitted_kwargs = { + 'required', + 'prefix', + 'no_builtin_args', + 'include_directories', + 'args', + 'dependencies', +} + +find_library_permitted_kwargs = { + 'has_headers', + 'required', + 'dirs', + 'static', +} + +find_library_permitted_kwargs |= {'header_' + k for k in header_permitted_kwargs} + +class CompilerHolder(ObjectHolder['Compiler']): + def __init__(self, compiler: 'Compiler', interpreter: 'Interpreter'): + super().__init__(compiler, interpreter) + self.environment = self.env + self.methods.update({'compiles': self.compiles_method, + 'links': self.links_method, + 'get_id': self.get_id_method, + 'get_linker_id': self.get_linker_id_method, + 'compute_int': self.compute_int_method, + 'sizeof': self.sizeof_method, + 'get_define': self.get_define_method, + 'check_header': self.check_header_method, + 'has_header': self.has_header_method, + 'has_header_symbol': self.has_header_symbol_method, + 'run': self.run_method, + 'has_function': self.has_function_method, + 'has_member': self.has_member_method, + 'has_members': self.has_members_method, + 'has_type': self.has_type_method, + 'alignment': self.alignment_method, + 'version': self.version_method, + 'cmd_array': self.cmd_array_method, + 'find_library': self.find_library_method, + 'has_argument': self.has_argument_method, + 'has_function_attribute': self.has_func_attribute_method, + 'get_supported_function_attributes': self.get_supported_function_attributes_method, + 'has_multi_arguments': self.has_multi_arguments_method, + 'get_supported_arguments': self.get_supported_arguments_method, + 'first_supported_argument': self.first_supported_argument_method, + 'has_link_argument': self.has_link_argument_method, + 'has_multi_link_arguments': self.has_multi_link_arguments_method, + 'get_supported_link_arguments': self.get_supported_link_arguments_method, + 'first_supported_link_argument': self.first_supported_link_argument_method, + 'unittest_args': self.unittest_args_method, + 'symbols_have_underscore_prefix': self.symbols_have_underscore_prefix_method, + 'get_argument_syntax': self.get_argument_syntax_method, + }) + + @property + def compiler(self) -> 'Compiler': + return self.held_object + + def _dep_msg(self, deps, endl): + msg_single = 'with dependency {}' + msg_many = 'with dependencies {}' + if not deps: + return endl + if endl is None: + endl = '' + names = [] + for d in deps: + if isinstance(d, dependencies.InternalDependency): + continue + if isinstance(d, dependencies.ExternalLibrary): + name = '-l' + d.name + else: + name = d.name + names.append(name) + if not names: + return None + tpl = msg_many if len(names) > 1 else msg_single + return tpl.format(', '.join(names)) + endl + + @noPosargs + @permittedKwargs({}) + def version_method(self, args, kwargs): + return self.compiler.version + + @noPosargs + @permittedKwargs({}) + def cmd_array_method(self, args, kwargs): + return self.compiler.exelist + + def determine_args(self, kwargs, mode='link'): + nobuiltins = kwargs.get('no_builtin_args', False) + if not isinstance(nobuiltins, bool): + raise InterpreterException('Type of no_builtin_args not a boolean.') + args = [] + incdirs = mesonlib.extract_as_list(kwargs, 'include_directories') + for i in incdirs: + from ..build import IncludeDirs + if not isinstance(i, IncludeDirs): + raise InterpreterException('Include directories argument must be an include_directories object.') + for idir in i.to_string_list(self.environment.get_source_dir()): + args += self.compiler.get_include_args(idir, False) + if not nobuiltins: + opts = self.environment.coredata.options + args += self.compiler.get_option_compile_args(opts) + if mode == 'link': + args += self.compiler.get_option_link_args(opts) + args += mesonlib.stringlistify(kwargs.get('args', [])) + return args + + def determine_dependencies(self, kwargs, endl=':'): + deps = kwargs.get('dependencies', None) + if deps is not None: + final_deps = [] + while deps: + next_deps = [] + for d in mesonlib.listify(deps): + if not isinstance(d, dependencies.Dependency) or d.is_built(): + raise InterpreterException('Dependencies must be external dependencies') + final_deps.append(d) + next_deps.extend(d.ext_deps) + deps = next_deps + deps = final_deps + return deps, self._dep_msg(deps, endl) + + @permittedKwargs({ + 'prefix', + 'args', + 'dependencies', + }) + def alignment_method(self, args, kwargs): + if len(args) != 1: + raise InterpreterException('Alignment method takes exactly one positional argument.') + check_stringlist(args) + typename = args[0] + prefix = kwargs.get('prefix', '') + if not isinstance(prefix, str): + raise InterpreterException('Prefix argument of alignment must be a string.') + extra_args = mesonlib.stringlistify(kwargs.get('args', [])) + deps, msg = self.determine_dependencies(kwargs) + result = self.compiler.alignment(typename, prefix, self.environment, + extra_args=extra_args, + dependencies=deps) + mlog.log('Checking for alignment of', mlog.bold(typename, True), msg, result) + return result + + @permittedKwargs({ + 'name', + 'no_builtin_args', + 'include_directories', + 'args', + 'dependencies', + }) + def run_method(self, args, kwargs): + if len(args) != 1: + raise InterpreterException('Run method takes exactly one positional argument.') + code = args[0] + if isinstance(code, mesonlib.File): + code = mesonlib.File.from_absolute_file( + code.rel_to_builddir(self.environment.source_dir)) + elif not isinstance(code, str): + raise InvalidArguments('Argument must be string or file.') + testname = kwargs.get('name', '') + if not isinstance(testname, str): + 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.run(code, self.environment, extra_args=extra_args, + dependencies=deps) + if len(testname) > 0: + if not result.compiled: + h = mlog.red('DID NOT COMPILE') + elif result.returncode == 0: + h = mlog.green('YES') + else: + h = mlog.red('NO (%d)' % result.returncode) + mlog.log('Checking if', mlog.bold(testname, True), msg, 'runs:', h) + return result + + @noPosargs + @permittedKwargs({}) + def get_id_method(self, args, kwargs): + return self.compiler.get_id() + + @noPosargs + @permittedKwargs({}) + @FeatureNew('compiler.get_linker_id', '0.53.0') + def get_linker_id_method(self, args, kwargs): + return self.compiler.get_linker_id() + + @noPosargs + @permittedKwargs({}) + def symbols_have_underscore_prefix_method(self, args, kwargs): + ''' + Check if the compiler prefixes _ (underscore) to global C symbols + See: https://en.wikipedia.org/wiki/Name_mangling#C + ''' + return self.compiler.symbols_have_underscore_prefix(self.environment) + + @noPosargs + @permittedKwargs({}) + def unittest_args_method(self, args, kwargs): + ''' + This function is deprecated and should not be used. + It can be removed in a future version of Meson. + ''' + if not hasattr(self.compiler, 'get_feature_args'): + raise InterpreterException(f'This {self.compiler.get_display_language()} compiler has no feature arguments.') + build_to_src = os.path.relpath(self.environment.get_source_dir(), self.environment.get_build_dir()) + return self.compiler.get_feature_args({'unittest': 'true'}, build_to_src) + + @permittedKwargs({ + 'prefix', + 'no_builtin_args', + 'include_directories', + 'args', + 'dependencies', + }) + def has_member_method(self, args, kwargs): + if len(args) != 2: + raise InterpreterException('Has_member takes exactly two arguments.') + check_stringlist(args) + typename, membername = args + prefix = kwargs.get('prefix', '') + if not isinstance(prefix, str): + 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, cached = self.compiler.has_members(typename, [membername], prefix, + self.environment, + extra_args=extra_args, + dependencies=deps) + cached = mlog.blue('(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, cached) + return had + + @permittedKwargs({ + 'prefix', + 'no_builtin_args', + 'include_directories', + 'args', + 'dependencies', + }) + def has_members_method(self, args, kwargs): + if len(args) < 2: + raise InterpreterException('Has_members needs at least two arguments.') + check_stringlist(args) + typename, *membernames = args + prefix = kwargs.get('prefix', '') + if not isinstance(prefix, str): + 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, cached = self.compiler.has_members(typename, membernames, prefix, + self.environment, + extra_args=extra_args, + dependencies=deps) + cached = mlog.blue('(cached)') if cached else '' + if had: + hadtxt = mlog.green('YES') + else: + hadtxt = mlog.red('NO') + members = mlog.bold(', '.join([f'"{m}"' for m in membernames])) + mlog.log('Checking whether type', mlog.bold(typename, True), + 'has members', members, msg, hadtxt, cached) + return had + + @permittedKwargs({ + 'prefix', + 'no_builtin_args', + 'include_directories', + 'args', + 'dependencies', + }) + def has_function_method(self, args, kwargs): + if len(args) != 1: + raise InterpreterException('Has_function takes exactly one argument.') + check_stringlist(args) + funcname = args[0] + prefix = kwargs.get('prefix', '') + if not isinstance(prefix, str): + raise InterpreterException('Prefix argument of has_function must be a string.') + extra_args = self.determine_args(kwargs) + deps, msg = self.determine_dependencies(kwargs) + had, cached = self.compiler.has_function(funcname, prefix, self.environment, + extra_args=extra_args, + dependencies=deps) + cached = mlog.blue('(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, cached) + return had + + @permittedKwargs({ + 'prefix', + 'no_builtin_args', + 'include_directories', + 'args', + 'dependencies', + }) + def has_type_method(self, args, kwargs): + if len(args) != 1: + raise InterpreterException('Has_type takes exactly one argument.') + check_stringlist(args) + typename = args[0] + prefix = kwargs.get('prefix', '') + if not isinstance(prefix, str): + 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, cached = self.compiler.has_type(typename, prefix, self.environment, + extra_args=extra_args, dependencies=deps) + cached = mlog.blue('(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, cached) + return had + + @FeatureNew('compiler.compute_int', '0.40.0') + @permittedKwargs({ + 'prefix', + 'low', + 'high', + 'guess', + 'no_builtin_args', + 'include_directories', + 'args', + 'dependencies', + }) + def compute_int_method(self, args, kwargs): + if len(args) != 1: + raise InterpreterException('Compute_int takes exactly one argument.') + check_stringlist(args) + expression = args[0] + prefix = kwargs.get('prefix', '') + low = kwargs.get('low', None) + high = kwargs.get('high', None) + guess = kwargs.get('guess', None) + if not isinstance(prefix, str): + raise InterpreterException('Prefix argument of compute_int must be a string.') + if low is not None and not isinstance(low, int): + raise InterpreterException('Low argument of compute_int must be an int.') + if high is not None and not isinstance(high, int): + raise InterpreterException('High argument of compute_int must be an int.') + if guess is not None and not isinstance(guess, int): + raise InterpreterException('Guess argument of compute_int must be an int.') + extra_args = functools.partial(self.determine_args, kwargs) + deps, msg = self.determine_dependencies(kwargs) + res = self.compiler.compute_int(expression, low, high, guess, prefix, + self.environment, extra_args=extra_args, + dependencies=deps) + mlog.log('Computing int of', mlog.bold(expression, True), msg, res) + return res + + @permittedKwargs({ + 'prefix', + 'no_builtin_args', + 'include_directories', + 'args', + 'dependencies', + }) + def sizeof_method(self, args, kwargs): + if len(args) != 1: + raise InterpreterException('Sizeof takes exactly one argument.') + check_stringlist(args) + element = args[0] + prefix = kwargs.get('prefix', '') + if not isinstance(prefix, str): + raise InterpreterException('Prefix argument of sizeof must be a string.') + extra_args = functools.partial(self.determine_args, kwargs) + deps, msg = self.determine_dependencies(kwargs) + esize = self.compiler.sizeof(element, prefix, self.environment, + extra_args=extra_args, dependencies=deps) + mlog.log('Checking for size of', mlog.bold(element, True), msg, esize) + return esize + + @FeatureNew('compiler.get_define', '0.40.0') + @permittedKwargs({ + 'prefix', + 'no_builtin_args', + 'include_directories', + 'args', + 'dependencies', + }) + def get_define_method(self, args, kwargs): + if len(args) != 1: + raise InterpreterException('get_define() takes exactly one argument.') + check_stringlist(args) + element = args[0] + prefix = kwargs.get('prefix', '') + if not isinstance(prefix, str): + 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, cached = self.compiler.get_define(element, prefix, self.environment, + extra_args=extra_args, + dependencies=deps) + cached = mlog.blue('(cached)') if cached else '' + mlog.log('Fetching value of define', mlog.bold(element, True), msg, value, cached) + return value + + @permittedKwargs({ + 'name', + 'no_builtin_args', + 'include_directories', + 'args', + 'dependencies', + }) + def compiles_method(self, args, kwargs): + if len(args) != 1: + raise InterpreterException('compiles method takes exactly one argument.') + code = args[0] + if isinstance(code, mesonlib.File): + code = mesonlib.File.from_absolute_file( + code.rel_to_builddir(self.environment.source_dir)) + elif not isinstance(code, str): + raise InvalidArguments('Argument must be string or file.') + testname = kwargs.get('name', '') + if not isinstance(testname, str): + 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, 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') + cached = mlog.blue('(cached)') if cached else '' + mlog.log('Checking if', mlog.bold(testname, True), msg, 'compiles:', h, cached) + return result + + @permittedKwargs({ + 'name', + 'no_builtin_args', + 'include_directories', + 'args', + 'dependencies', + }) + def links_method(self, args, kwargs): + if len(args) != 1: + raise InterpreterException('links method takes exactly one argument.') + code = args[0] + if isinstance(code, mesonlib.File): + code = mesonlib.File.from_absolute_file( + code.rel_to_builddir(self.environment.source_dir)) + elif not isinstance(code, str): + raise InvalidArguments('Argument must be string or file.') + testname = kwargs.get('name', '') + if not isinstance(testname, str): + 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, cached = self.compiler.links(code, self.environment, + extra_args=extra_args, + dependencies=deps) + cached = mlog.blue('(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, cached) + return result + + @FeatureNew('compiler.check_header', '0.47.0') + @FeatureNewKwargs('compiler.check_header', '0.50.0', ['required']) + @permittedKwargs(header_permitted_kwargs) + def check_header_method(self, args, kwargs): + if len(args) != 1: + raise InterpreterException('check_header method takes exactly one argument.') + check_stringlist(args) + hname = args[0] + prefix = kwargs.get('prefix', '') + if not isinstance(prefix, str): + raise InterpreterException('Prefix argument of has_header must be a string.') + disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False) + if disabled: + mlog.log('Check usable header', mlog.bold(hname, True), 'skipped: feature', mlog.bold(feature), 'disabled') + return False + extra_args = functools.partial(self.determine_args, kwargs) + deps, msg = self.determine_dependencies(kwargs) + haz, cached = self.compiler.check_header(hname, prefix, self.environment, + extra_args=extra_args, + dependencies=deps) + cached = mlog.blue('(cached)') if cached else '' + if required and not haz: + raise InterpreterException(f'{self.compiler.get_display_language()} header {hname!r} not usable') + elif haz: + h = mlog.green('YES') + else: + h = mlog.red('NO') + mlog.log('Check usable header', mlog.bold(hname, True), msg, h, cached) + return haz + + @FeatureNewKwargs('compiler.has_header', '0.50.0', ['required']) + @permittedKwargs(header_permitted_kwargs) + def has_header_method(self, args, kwargs): + if len(args) != 1: + raise InterpreterException('has_header method takes exactly one argument.') + check_stringlist(args) + hname = args[0] + prefix = kwargs.get('prefix', '') + if not isinstance(prefix, str): + raise InterpreterException('Prefix argument of has_header must be a string.') + disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False) + if disabled: + mlog.log('Has header', mlog.bold(hname, True), 'skipped: feature', mlog.bold(feature), 'disabled') + return False + extra_args = functools.partial(self.determine_args, kwargs) + deps, msg = self.determine_dependencies(kwargs) + haz, cached = self.compiler.has_header(hname, prefix, self.environment, + extra_args=extra_args, dependencies=deps) + cached = mlog.blue('(cached)') if cached else '' + if required and not haz: + raise InterpreterException(f'{self.compiler.get_display_language()} header {hname!r} not found') + elif haz: + h = mlog.green('YES') + else: + h = mlog.red('NO') + mlog.log('Has header', mlog.bold(hname, True), msg, h, cached) + return haz + + @FeatureNewKwargs('compiler.has_header_symbol', '0.50.0', ['required']) + @permittedKwargs(header_permitted_kwargs) + def has_header_symbol_method(self, args, kwargs): + if len(args) != 2: + raise InterpreterException('has_header_symbol method takes exactly two arguments.') + check_stringlist(args) + hname, symbol = args + prefix = kwargs.get('prefix', '') + if not isinstance(prefix, str): + raise InterpreterException('Prefix argument of has_header_symbol must be a string.') + disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False) + if disabled: + mlog.log(f'Header <{hname}> has symbol', mlog.bold(symbol, True), 'skipped: feature', mlog.bold(feature), 'disabled') + return False + extra_args = functools.partial(self.determine_args, kwargs) + deps, msg = self.determine_dependencies(kwargs) + 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(f'{self.compiler.get_display_language()} symbol {symbol} not found in header {hname}') + elif haz: + h = mlog.green('YES') + else: + h = mlog.red('NO') + cached = mlog.blue('(cached)') if cached else '' + mlog.log(f'Header <{hname}> has symbol', mlog.bold(symbol, True), msg, h, cached) + return haz + + def notfound_library(self, libname): + lib = dependencies.ExternalLibrary(libname, None, + self.environment, + self.compiler.language, + silent=True) + return lib + + @FeatureNewKwargs('compiler.find_library', '0.51.0', ['static']) + @FeatureNewKwargs('compiler.find_library', '0.50.0', ['has_headers']) + @FeatureNewKwargs('compiler.find_library', '0.49.0', ['disabler']) + @disablerIfNotFound + @permittedKwargs(find_library_permitted_kwargs) + def find_library_method(self, args, kwargs): + # TODO add dependencies support? + if len(args) != 1: + raise InterpreterException('find_library method takes one argument.') + libname = args[0] + if not isinstance(libname, str): + raise InterpreterException('Library name not a string.') + + disabled, required, feature = extract_required_kwarg(kwargs, self.subproject) + if disabled: + mlog.log('Library', mlog.bold(libname), 'skipped: feature', mlog.bold(feature), 'disabled') + return self.notfound_library(libname) + + has_header_kwargs = {k[7:]: v for k, v in kwargs.items() if k.startswith('header_')} + has_header_kwargs['required'] = required + headers = mesonlib.stringlistify(kwargs.get('has_headers', [])) + for h in headers: + if not self.has_header_method([h], has_header_kwargs): + return self.notfound_library(libname) + + search_dirs = extract_search_dirs(kwargs) + + libtype = mesonlib.LibType.PREFER_SHARED + if 'static' in kwargs: + if not isinstance(kwargs['static'], bool): + raise InterpreterException('static must be a boolean') + libtype = mesonlib.LibType.STATIC if kwargs['static'] else mesonlib.LibType.SHARED + linkargs = self.compiler.find_library(libname, self.environment, search_dirs, libtype) + if required and not linkargs: + if libtype == mesonlib.LibType.PREFER_SHARED: + libtype = 'shared or static' + else: + libtype = libtype.name.lower() + raise InterpreterException('{} {} library {!r} not found' + .format(self.compiler.get_display_language(), + libtype, libname)) + lib = dependencies.ExternalLibrary(libname, linkargs, self.environment, + self.compiler.language) + return lib + + @permittedKwargs({}) + def has_argument_method(self, args: T.Sequence[str], kwargs) -> bool: + args = mesonlib.stringlistify(args) + if len(args) != 1: + raise InterpreterException('has_argument takes exactly one argument.') + return self.has_multi_arguments_method(args, kwargs) + + @permittedKwargs({}) + def has_multi_arguments_method(self, args: T.Sequence[str], kwargs: dict): + args = mesonlib.stringlistify(args) + result, cached = self.compiler.has_multi_arguments(args, self.environment) + if result: + h = mlog.green('YES') + else: + h = mlog.red('NO') + cached = mlog.blue('(cached)') if cached else '' + mlog.log( + 'Compiler for {} supports arguments {}:'.format( + self.compiler.get_display_language(), ' '.join(args)), + h, cached) + return result + + @FeatureNew('compiler.get_supported_arguments', '0.43.0') + @typed_kwargs( + 'compiler.get_supported_arguments', + KwargInfo('checked', str, default='off', since='0.59.0', + validator=lambda s: 'must be one of "warn", "require" or "off"' if s not in ['warn', 'require', 'off'] else None) + ) + def get_supported_arguments_method(self, args: T.Sequence[str], kwargs: T.Dict[str, T.Any]): + args = mesonlib.stringlistify(args) + supported_args = [] + checked = kwargs.pop('checked') + + for arg in args: + if not self.has_argument_method(arg, kwargs): + msg = f'Compiler for {self.compiler.get_display_language()} does not support "{arg}"' + if checked == 'warn': + mlog.warning(msg) + elif checked == 'require': + raise mesonlib.MesonException(msg) + else: + supported_args.append(arg) + return supported_args + + @permittedKwargs({}) + def first_supported_argument_method(self, args: T.Sequence[str], kwargs: dict) -> T.List[str]: + for arg in mesonlib.stringlistify(args): + if self.has_argument_method(arg, kwargs): + mlog.log('First supported argument:', mlog.bold(arg)) + return [arg] + mlog.log('First supported argument:', mlog.red('None')) + return [] + + @FeatureNew('compiler.has_link_argument', '0.46.0') + @permittedKwargs({}) + def has_link_argument_method(self, args, kwargs): + args = mesonlib.stringlistify(args) + if len(args) != 1: + raise InterpreterException('has_link_argument takes exactly one argument.') + return self.has_multi_link_arguments_method(args, kwargs) + + @FeatureNew('compiler.has_multi_link_argument', '0.46.0') + @permittedKwargs({}) + def has_multi_link_arguments_method(self, args, kwargs): + args = mesonlib.stringlistify(args) + result, cached = self.compiler.has_multi_link_arguments(args, self.environment) + cached = mlog.blue('(cached)') if cached else '' + if result: + h = mlog.green('YES') + else: + h = mlog.red('NO') + mlog.log( + 'Compiler for {} supports link arguments {}:'.format( + self.compiler.get_display_language(), ' '.join(args)), + h, cached) + return result + + @FeatureNew('compiler.get_supported_link_arguments_method', '0.46.0') + @permittedKwargs({}) + def get_supported_link_arguments_method(self, args, kwargs): + args = mesonlib.stringlistify(args) + supported_args = [] + for arg in args: + if self.has_link_argument_method(arg, kwargs): + supported_args.append(arg) + return supported_args + + @FeatureNew('compiler.first_supported_link_argument_method', '0.46.0') + @permittedKwargs({}) + def first_supported_link_argument_method(self, args, kwargs): + for i in mesonlib.stringlistify(args): + if self.has_link_argument_method(i, kwargs): + mlog.log('First supported link argument:', mlog.bold(i)) + return [i] + mlog.log('First supported link argument:', mlog.red('None')) + return [] + + @FeatureNew('compiler.has_function_attribute', '0.48.0') + @permittedKwargs({}) + def has_func_attribute_method(self, args, kwargs): + args = mesonlib.stringlistify(args) + if len(args) != 1: + raise InterpreterException('has_func_attribute takes exactly one argument.') + result, cached = self.compiler.has_func_attribute(args[0], self.environment) + cached = mlog.blue('(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, cached) + return result + + @FeatureNew('compiler.get_supported_function_attributes', '0.48.0') + @permittedKwargs({}) + def get_supported_function_attributes_method(self, args, kwargs): + args = mesonlib.stringlistify(args) + return [a for a in args if self.has_func_attribute_method(a, kwargs)] + + @FeatureNew('compiler.get_argument_syntax_method', '0.49.0') + @noPosargs + @noKwargs + def get_argument_syntax_method(self, args, kwargs): + return self.compiler.get_argument_syntax() |