diff options
Diffstat (limited to 'mesonbuild/compilers/compilers.py')
-rw-r--r-- | mesonbuild/compilers/compilers.py | 179 |
1 files changed, 124 insertions, 55 deletions
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 0f7ef17..e4c7f77 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -256,12 +256,16 @@ BASE_OPTIONS: T.Mapping[OptionKey, BaseOption] = { base_options = {key: base_opt.init_option(key) for key, base_opt in BASE_OPTIONS.items()} -def option_enabled(boptions: T.Set[OptionKey], options: 'KeyedOptionDictType', - option: OptionKey) -> bool: +def option_enabled(boptions: T.Set[OptionKey], + target: 'BuildTarget', + env: 'Environment', + option: T.Union[str, OptionKey]) -> bool: + if isinstance(option, str): + option = OptionKey(option) try: if option not in boptions: return False - ret = options.get_value(option) + ret = env.coredata.get_option_for_target(target, option) assert isinstance(ret, bool), 'must return bool' # could also be str return ret except KeyError: @@ -271,7 +275,7 @@ def option_enabled(boptions: T.Set[OptionKey], options: 'KeyedOptionDictType', def get_option_value(options: 'KeyedOptionDictType', opt: OptionKey, fallback: '_T') -> '_T': """Get the value of an option, or the fallback value.""" try: - v: '_T' = options.get_value(opt) + v: '_T' = options.get_value(opt) # type: ignore [assignment] except (KeyError, AttributeError): return fallback @@ -279,37 +283,75 @@ def get_option_value(options: 'KeyedOptionDictType', opt: OptionKey, fallback: ' # Mypy doesn't understand that the above assert ensures that v is type _T return v +def get_option_value_for_target(env: 'Environment', target: 'BuildTarget', opt: OptionKey, fallback: '_T') -> '_T': + """Get the value of an option, or the fallback value.""" + try: + v = env.coredata.get_option_for_target(target, opt) + except (KeyError, AttributeError): + return fallback + + assert isinstance(v, type(fallback)), f'Should have {type(fallback)!r} but was {type(v)!r}' + # Mypy doesn't understand that the above assert ensures that v is type _T + return v + + +def get_target_option_value(target: 'BuildTarget', + env: 'Environment', + opt: T.Union[OptionKey, str], + fallback: '_T') -> '_T': + """Get the value of an option, or the fallback value.""" + try: + v = env.coredata.get_option_for_target(target, opt) + except KeyError: + return fallback + + assert isinstance(v, type(fallback)), f'Should have {type(fallback)!r} but was {type(v)!r}' + # Mypy doesn't understand that the above assert ensures that v is type _T + return v + -def are_asserts_disabled(options: KeyedOptionDictType) -> bool: +def are_asserts_disabled(target: 'BuildTarget', env: 'Environment') -> bool: """Should debug assertions be disabled - :param options: OptionDictionary + :param target: a target to check for + :param env: the environment :return: whether to disable assertions or not """ - return (options.get_value('b_ndebug') == 'true' or - (options.get_value('b_ndebug') == 'if-release' and - options.get_value('buildtype') in {'release', 'plain'})) + return (env.coredata.get_option_for_target(target, 'b_ndebug') == 'true' or + (env.coredata.get_option_for_target(target, 'b_ndebug') == 'if-release' and + env.coredata.get_option_for_target(target, 'buildtype') in {'release', 'plain'})) +def are_asserts_disabled_for_subproject(subproject: str, env: 'Environment') -> bool: + return (env.coredata.get_option_for_subproject('b_ndebug', subproject) == 'true' or + (env.coredata.get_option_for_subproject('b_ndebug', subproject) == 'if-release' and + env.coredata.get_option_for_subproject('buildtype', subproject) in {'release', 'plain'})) -def get_base_compile_args(options: 'KeyedOptionDictType', compiler: 'Compiler', env: 'Environment') -> T.List[str]: + +def get_base_compile_args(target: 'BuildTarget', compiler: 'Compiler', env: 'Environment') -> T.List[str]: args: T.List[str] = [] try: - if options.get_value(OptionKey('b_lto')): + if env.coredata.get_option_for_target(target, 'b_lto'): + num_threads = get_option_value_for_target(env, target, OptionKey('b_lto_threads'), 0) + ltomode = get_option_value_for_target(env, target, OptionKey('b_lto_mode'), 'default') args.extend(compiler.get_lto_compile_args( - threads=get_option_value(options, OptionKey('b_lto_threads'), 0), - mode=get_option_value(options, OptionKey('b_lto_mode'), 'default'))) + threads=num_threads, + mode=ltomode)) except (KeyError, AttributeError): pass try: - args += compiler.get_colorout_args(options.get_value(OptionKey('b_colorout'))) - except (KeyError, AttributeError): + clrout = env.coredata.get_option_for_target(target, 'b_colorout') + assert isinstance(clrout, str) + args += compiler.get_colorout_args(clrout) + except KeyError: pass try: - args += compiler.sanitizer_compile_args(options.get_value(OptionKey('b_sanitize'))) - except (KeyError, AttributeError): + sanitize = env.coredata.get_option_for_target(target, 'b_sanitize') + assert isinstance(sanitize, str) + args += compiler.sanitizer_compile_args(sanitize) + except KeyError: pass try: - pgo_val = options.get_value(OptionKey('b_pgo')) + pgo_val = env.coredata.get_option_for_target(target, 'b_pgo') if pgo_val == 'generate': args.extend(compiler.get_profile_generate_args()) elif pgo_val == 'use': @@ -317,21 +359,23 @@ def get_base_compile_args(options: 'KeyedOptionDictType', compiler: 'Compiler', except (KeyError, AttributeError): pass try: - if options.get_value(OptionKey('b_coverage')): + if env.coredata.get_option_for_target(target, 'b_coverage'): args += compiler.get_coverage_args() except (KeyError, AttributeError): pass try: - args += compiler.get_assert_args(are_asserts_disabled(options), env) - except (KeyError, AttributeError): + args += compiler.get_assert_args(are_asserts_disabled(target, env), env) + except KeyError: pass # This does not need a try...except - if option_enabled(compiler.base_options, options, OptionKey('b_bitcode')): + if option_enabled(compiler.base_options, target, env, 'b_bitcode'): args.append('-fembed-bitcode') try: + crt_val = env.coredata.get_option_for_target(target, 'b_vscrt') + assert isinstance(crt_val, str) + buildtype = env.coredata.get_option_for_target(target, 'buildtype') + assert isinstance(buildtype, str) try: - crt_val = options.get_value(OptionKey('b_vscrt')) - buildtype = options.get_value(OptionKey('buildtype')) args += compiler.get_crt_compile_args(crt_val, buildtype) except AttributeError: pass @@ -339,31 +383,38 @@ def get_base_compile_args(options: 'KeyedOptionDictType', compiler: 'Compiler', pass return args -def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler', - is_shared_module: bool, build_dir: str) -> T.List[str]: +def get_base_link_args(target: 'BuildTarget', + linker: 'Compiler', + env: 'Environment') -> T.List[str]: args: T.List[str] = [] + build_dir = env.get_build_dir() try: - if options.get_value('b_lto'): - if options.get_value('werror'): + if env.coredata.get_option_for_target(target, 'b_lto'): + if env.coredata.get_option_for_target(target, 'werror'): args.extend(linker.get_werror_args()) thinlto_cache_dir = None - if get_option_value(options, OptionKey('b_thinlto_cache'), False): - thinlto_cache_dir = get_option_value(options, OptionKey('b_thinlto_cache_dir'), '') + cachedir_key = OptionKey('b_thinlto_cache') + if get_option_value_for_target(env, target, cachedir_key, False): + thinlto_cache_dir = get_option_value_for_target(env, target, OptionKey('b_thinlto_cache_dir'), '') if thinlto_cache_dir == '': thinlto_cache_dir = os.path.join(build_dir, 'meson-private', 'thinlto-cache') + num_threads = get_option_value_for_target(env, target, OptionKey('b_lto_threads'), 0) + lto_mode = get_option_value_for_target(env, target, OptionKey('b_lto_mode'), 'default') args.extend(linker.get_lto_link_args( - threads=get_option_value(options, OptionKey('b_lto_threads'), 0), - mode=get_option_value(options, OptionKey('b_lto_mode'), 'default'), + threads=num_threads, + mode=lto_mode, thinlto_cache_dir=thinlto_cache_dir)) except (KeyError, AttributeError): pass try: - args += linker.sanitizer_link_args(options.get_value('b_sanitize')) - except (KeyError, AttributeError): + sanitizer = env.coredata.get_option_for_target(target, 'b_sanitize') + assert isinstance(sanitizer, str) + args += linker.sanitizer_link_args(sanitizer) + except KeyError: pass try: - pgo_val = options.get_value('b_pgo') + pgo_val = env.coredata.get_option_for_target(target, 'b_pgo') if pgo_val == 'generate': args.extend(linker.get_profile_generate_args()) elif pgo_val == 'use': @@ -371,16 +422,16 @@ def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler', except (KeyError, AttributeError): pass try: - if options.get_value('b_coverage'): + if env.coredata.get_option_for_target(target, 'b_coverage'): args += linker.get_coverage_link_args() except (KeyError, AttributeError): pass - as_needed = option_enabled(linker.base_options, options, OptionKey('b_asneeded')) - bitcode = option_enabled(linker.base_options, options, OptionKey('b_bitcode')) + as_needed = option_enabled(linker.base_options, target, env, 'b_asneeded') + bitcode = option_enabled(linker.base_options, target, env, 'b_bitcode') # Shared modules cannot be built with bitcode_bundle because # -bitcode_bundle is incompatible with -undefined and -bundle - if bitcode and not is_shared_module: + if bitcode and not target.typename == 'shared module': args.extend(linker.bitcode_args()) elif as_needed: # -Wl,-dead_strip_dylibs is incompatible with bitcode @@ -389,18 +440,23 @@ def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler', # Apple's ld (the only one that supports bitcode) does not like -undefined # arguments or -headerpad_max_install_names when bitcode is enabled if not bitcode: + from ..build import SharedModule args.extend(linker.headerpad_args()) - if (not is_shared_module and - option_enabled(linker.base_options, options, OptionKey('b_lundef'))): + if (not isinstance(target, SharedModule) and + option_enabled(linker.base_options, target, env, 'b_lundef')): args.extend(linker.no_undefined_link_args()) else: args.extend(linker.get_allow_undefined_link_args()) try: + crt_val = env.coredata.get_option_for_target(target, 'b_vscrt') + assert isinstance(crt_val, str) + buildtype = env.coredata.get_option_for_target(target, 'buildtype') + assert isinstance(buildtype, str) try: - crt_val = options.get_value(OptionKey('b_vscrt')) - buildtype = options.get_value(OptionKey('buildtype')) - args += linker.get_crt_link_args(crt_val, buildtype) + crtargs = linker.get_crt_link_args(crt_val, buildtype) + assert isinstance(crtargs, list) + args += crtargs except AttributeError: pass except KeyError: @@ -598,11 +654,11 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta): def get_options(self) -> 'MutableKeyedOptionDictType': return {} - def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + def get_option_compile_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: return [] - def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: - return self.linker.get_option_args(options) + def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: + return self.linker.get_option_link_args(target, env, subproject) def check_header(self, hname: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None, @@ -894,8 +950,8 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta): def get_std_shared_lib_link_args(self) -> T.List[str]: return self.linker.get_std_shared_lib_args() - def get_std_shared_module_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: - return self.linker.get_std_shared_module_args(options) + def get_std_shared_module_link_args(self, target: 'BuildTarget') -> T.List[str]: + return self.linker.get_std_shared_module_args(target) def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: return self.linker.get_link_whole_for(args) @@ -1358,6 +1414,19 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta): def form_compileropt_key(self, basename: str) -> OptionKey: return OptionKey(f'{self.language}_{basename}', machine=self.for_machine) + def get_compileropt_value(self, + key: T.Union[str, OptionKey], + env: Environment, + target: T.Optional[BuildTarget], + subproject: T.Optional[str] = None + ) -> T.Union[str, int, bool, T.List[str]]: + if isinstance(key, str): + key = self.form_compileropt_key(key) + if target: + return env.coredata.get_option_for_target(target, key) + else: + return env.coredata.get_option_for_subproject(key, subproject) + def _update_language_stds(self, opts: MutableKeyedOptionDictType, value: T.List[str]) -> None: key = self.form_compileropt_key('std') std = opts[key] @@ -1370,12 +1439,12 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta): def get_global_options(lang: str, comp: T.Type[Compiler], for_machine: MachineChoice, - env: 'Environment') -> dict[OptionKey, options.UserOption[T.Any]]: + env: 'Environment') -> dict[OptionKey, options.AnyOptionType]: """Retrieve options that apply to all compilers for a given language.""" description = f'Extra arguments passed to the {lang}' argkey = OptionKey(f'{lang}_args', machine=for_machine) - largkey = argkey.evolve(f'{lang}_link_args') - envkey = argkey.evolve(f'{lang}_env_args') + largkey = OptionKey(f'{lang}_link_args', machine=for_machine) + envkey = OptionKey(f'{lang}_env_args', machine=for_machine) comp_key = argkey if argkey in env.options else envkey @@ -1383,12 +1452,12 @@ def get_global_options(lang: str, link_options = env.options.get(largkey, []) cargs = options.UserStringArrayOption( - f'{lang}_{argkey.name}', + argkey.name, description + ' compiler', comp_options, split_args=True, allow_dups=True) largs = options.UserStringArrayOption( - f'{lang}_{largkey.name}', + largkey.name, description + ' linker', link_options, split_args=True, allow_dups=True) @@ -1400,6 +1469,6 @@ def get_global_options(lang: str, # autotools compatibility. largs.extend_value(comp_options) - opts: dict[OptionKey, options.UserOption[T.Any]] = {argkey: cargs, largkey: largs} + opts: dict[OptionKey, options.AnyOptionType] = {argkey: cargs, largkey: largs} return opts |