diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2024-04-14 12:58:30 +0300 |
---|---|---|
committer | Jussi Pakkanen <jpakkane@gmail.com> | 2025-02-13 15:26:44 +0200 |
commit | 518c732ea9b0f1975f6f28accff3286be4106538 (patch) | |
tree | 2be9544828545a2f9f0676efc6eb82ac197ec4bd /mesonbuild/compilers | |
parent | ea678ed82938ceac00682b2695b57193d36b71b4 (diff) | |
download | meson-optionrefactor3.zip meson-optionrefactor3.tar.gz meson-optionrefactor3.tar.bz2 |
Make all Meson level options overridable per subproject.optionrefactor3
Diffstat (limited to 'mesonbuild/compilers')
-rw-r--r-- | mesonbuild/compilers/c.py | 120 | ||||
-rw-r--r-- | mesonbuild/compilers/compilers.py | 179 | ||||
-rw-r--r-- | mesonbuild/compilers/cpp.py | 216 | ||||
-rw-r--r-- | mesonbuild/compilers/cuda.py | 49 | ||||
-rw-r--r-- | mesonbuild/compilers/cython.py | 14 | ||||
-rw-r--r-- | mesonbuild/compilers/fortran.py | 21 | ||||
-rw-r--r-- | mesonbuild/compilers/mixins/clike.py | 2 | ||||
-rw-r--r-- | mesonbuild/compilers/mixins/elbrus.py | 11 | ||||
-rw-r--r-- | mesonbuild/compilers/mixins/emscripten.py | 3 | ||||
-rw-r--r-- | mesonbuild/compilers/mixins/islinker.py | 3 | ||||
-rw-r--r-- | mesonbuild/compilers/objc.py | 19 | ||||
-rw-r--r-- | mesonbuild/compilers/objcpp.py | 19 | ||||
-rw-r--r-- | mesonbuild/compilers/rust.py | 9 | ||||
-rw-r--r-- | mesonbuild/compilers/vala.py | 4 |
14 files changed, 395 insertions, 274 deletions
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 4f93ea1..4f2bd2f 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -8,6 +8,7 @@ import os.path import typing as T from .. import options +from ..options import OptionKey from .. import mlog from ..mesonlib import MesonException, version_compare from .c_function_attributes import C_FUNC_ATTRIBUTES @@ -36,13 +37,14 @@ from .compilers import ( ) if T.TYPE_CHECKING: - from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType + from ..coredata import MutableKeyedOptionDictType from ..dependencies import Dependency from ..envconfig import MachineInfo from ..environment import Environment from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice from .compilers import CompileCheckMode + from ..build import BuildTarget CompilerMixinBase = Compiler else: @@ -130,20 +132,19 @@ class ClangCCompiler(ClangCStds, ClangCompiler, CCompiler): gnu_winlibs) return opts - 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]: args = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('-std=' + std) return args - def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): - # without a typedict mypy can't understand this. - key = self.form_compileropt_key('winlibs') - libs = options.get_value(key).copy() - assert isinstance(libs, list) + retval = self.get_compileropt_value('winlibs', env, target, subproject) + assert isinstance(retval, list) + libs: T.List[str] = retval.copy() for l in libs: assert isinstance(l, str) return libs @@ -219,15 +220,15 @@ class ArmclangCCompiler(ArmclangCompiler, CCompiler): std_opt.set_versions(['c90', 'c99', 'c11'], gnu=True) return opts - 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]: args = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('-std=' + std) return args - def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: return [] @@ -263,20 +264,22 @@ class GnuCCompiler(GnuCStds, GnuCompiler, CCompiler): gnu_winlibs) return opts - 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]: args = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + key = OptionKey('c_std', machine=self.for_machine) + std = self.get_compileropt_value(key, env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('-std=' + std) return args - def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): # without a typeddict mypy can't figure this out - key = self.form_compileropt_key('winlibs') - libs: T.List[str] = options.get_value(key).copy() - assert isinstance(libs, list) + retval = self.get_compileropt_value('winlibs', env, target, subproject) + + assert isinstance(retval, list) + libs: T.List[str] = retval.copy() for l in libs: assert isinstance(l, str) return libs @@ -385,10 +388,10 @@ class IntelCCompiler(IntelGnuLikeCompiler, CCompiler): std_opt.set_versions(stds, gnu=True) return opts - def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: - args = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + def get_option_compile_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: + args: T.List[str] = [] + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('-std=' + std) return args @@ -412,11 +415,10 @@ class VisualStudioLikeCCompilerMixin(CompilerMixinBase): msvc_winlibs) return opts - def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: - # need a TypeDict to make this work - key = self.form_compileropt_key('winlibs') - libs = options.get_value(key).copy() - assert isinstance(libs, list) + def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: + retval = self.get_compileropt_value('winlibs', env, target, subproject) + assert isinstance(retval, list) + libs: T.List[str] = retval.copy() for l in libs: assert isinstance(l, str) return libs @@ -449,12 +451,12 @@ class VisualStudioCCompiler(MSVCCompiler, VisualStudioLikeCCompilerMixin, CCompi std_opt.set_versions(stds, gnu=True, gnu_deprecated=True) return opts - 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]: args = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + # As of MVSC 16.8, /std:c11 and /std:c17 are the only valid C standard options. - if std == 'c11': + if std in {'c11'}: args.append('/std:c11') elif std in {'c17', 'c18'}: args.append('/std:c17') @@ -471,9 +473,9 @@ class ClangClCCompiler(ClangCStds, ClangClCompiler, VisualStudioLikeCCompilerMix full_version=full_version) ClangClCompiler.__init__(self, target) - def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: - key = self.form_compileropt_key('std') - std = options.get_value(key) + def get_option_compile_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != "none": return [f'/clang:-std={std}'] return [] @@ -503,10 +505,10 @@ class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerM std_opt.set_versions(['c89', 'c99', 'c11']) return opts - def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: - args = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + def get_option_compile_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: + args: T.List[str] = [] + std = self.get_compileropt_value('winlibs', env, target, subproject) + assert isinstance(std, str) if std == 'c89': mlog.log("ICL doesn't explicitly implement c89, setting the standard to 'none', which is close.", once=True) elif std != 'none': @@ -537,10 +539,10 @@ class ArmCCompiler(ArmCompiler, CCompiler): std_opt.set_versions(['c89', 'c99', 'c11']) return opts - 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]: args = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('--' + std) return args @@ -570,10 +572,10 @@ class CcrxCCompiler(CcrxCompiler, CCompiler): def get_no_stdinc_args(self) -> T.List[str]: 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]: args = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std == 'c89': args.append('-lang=c') elif std == 'c99': @@ -618,10 +620,10 @@ class Xc16CCompiler(Xc16Compiler, CCompiler): def get_no_stdinc_args(self) -> T.List[str]: 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]: args = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('-ansi') args.append('-std=' + std) @@ -661,7 +663,7 @@ class CompCertCCompiler(CompCertCompiler, CCompiler): std_opt.set_versions(['c89', 'c99']) return opts - 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_no_optimization_args(self) -> T.List[str]: @@ -702,10 +704,10 @@ class TICCompiler(TICompiler, CCompiler): def get_no_stdinc_args(self) -> T.List[str]: 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]: args = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('--' + std) return args @@ -736,10 +738,10 @@ class MetrowerksCCompilerARM(MetrowerksCompiler, CCompiler): self._update_language_stds(opts, ['c99']) return opts - 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]: args = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('-lang') args.append(std) @@ -764,10 +766,10 @@ class MetrowerksCCompilerEmbeddedPowerPC(MetrowerksCompiler, CCompiler): self._update_language_stds(opts, ['c99']) return opts - 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]: args = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('-lang ' + std) return args 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 diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 80f84b3..b21a62e 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -3,7 +3,6 @@ from __future__ import annotations -import copy import functools import os.path import typing as T @@ -35,12 +34,13 @@ from .mixins.metrowerks import MetrowerksCompiler from .mixins.metrowerks import mwccarm_instruction_set_args, mwcceppc_instruction_set_args if T.TYPE_CHECKING: - from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType + from ..coredata import MutableKeyedOptionDictType from ..dependencies import Dependency from ..envconfig import MachineInfo from ..environment import Environment from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice + from ..build import BuildTarget CompilerMixinBase = CLikeCompiler else: CompilerMixinBase = object @@ -265,18 +265,24 @@ class ClangCPPCompiler(_StdCPPLibMixin, ClangCPPStds, ClangCompiler, CPPCompiler gnu_winlibs) return opts - 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]: args: T.List[str] = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + + std = self.get_compileropt_value('std', env, target, subproject) + rtti = self.get_compileropt_value('rtti', env, target, subproject) + debugstl = self.get_compileropt_value('debugstl', env, target, subproject) + eh = self.get_compileropt_value('eh', env, target, subproject) + + assert isinstance(std, str) + assert isinstance(rtti, bool) + assert isinstance(eh, str) + assert isinstance(debugstl, bool) if std != 'none': args.append(self._find_best_cpp_std(std)) - key = self.form_compileropt_key('eh') - non_msvc_eh_options(options.get_value(key), args) + non_msvc_eh_options(eh, args) - key = self.form_compileropt_key('debugstl') - if options.get_value(key): + if debugstl: args.append('-D_GLIBCXX_DEBUG=1') # We can't do _LIBCPP_DEBUG because it's unreliable unless libc++ was built with it too: @@ -285,18 +291,17 @@ class ClangCPPCompiler(_StdCPPLibMixin, ClangCPPStds, ClangCompiler, CPPCompiler if version_compare(self.version, '>=18'): args.append('-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG') - key = self.form_compileropt_key('rtti') - if not options.get_value(key): + if not rtti: args.append('-fno-rtti') return args - def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): # without a typedict mypy can't understand this. - key = self.form_compileropt_key('winlibs') - libs = options.get_value(key).copy() - assert isinstance(libs, list) + retval = self.get_compileropt_value('winlibs', env, target, subproject) + assert isinstance(retval, list) + libs = retval[:] for l in libs: assert isinstance(l, str) return libs @@ -363,10 +368,10 @@ class EmscriptenCPPCompiler(EmscriptenMixin, ClangCPPCompiler): info, linker=linker, defines=defines, full_version=full_version) - 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]: args: T.List[str] = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append(self._find_best_cpp_std(std)) return args @@ -407,19 +412,20 @@ class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): std_opt.set_versions(['c++98', 'c++03', 'c++11', 'c++14', 'c++17'], gnu=True) return opts - 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]: args: T.List[str] = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('-std=' + std) - key = self.form_compileropt_key('eh') - non_msvc_eh_options(options.get_value(key), args) + eh = self.get_compileropt_value('eh', env, target, subproject) + assert isinstance(eh, str) + non_msvc_eh_options(eh, args) return args - def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: return [] @@ -472,32 +478,37 @@ class GnuCPPCompiler(_StdCPPLibMixin, GnuCPPStds, GnuCompiler, CPPCompiler): return opts - 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]: args: T.List[str] = [] - stdkey = self.form_compileropt_key('std') - ehkey = self.form_compileropt_key('eh') - rttikey = self.form_compileropt_key('rtti') - debugstlkey = self.form_compileropt_key('debugstl') - std = options.get_value(stdkey) + std = self.get_compileropt_value('std', env, target, subproject) + rtti = self.get_compileropt_value('rtti', env, target, subproject) + debugstl = self.get_compileropt_value('debugstl', env, target, subproject) + eh = self.get_compileropt_value('eh', env, target, subproject) + + assert isinstance(std, str) + assert isinstance(rtti, bool) + assert isinstance(eh, str) + assert isinstance(debugstl, bool) + if std != 'none': args.append(self._find_best_cpp_std(std)) - non_msvc_eh_options(options.get_value(ehkey), args) + non_msvc_eh_options(eh, args) - if not options.get_value(rttikey): + if not rtti: args.append('-fno-rtti') - if options.get_value(debugstlkey): + if debugstl: args.append('-D_GLIBCXX_DEBUG=1') return args - def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): # without a typedict mypy can't understand this. - key = self.form_compileropt_key('winlibs') - libs = options.get_value(key).copy() - assert isinstance(libs, list) + retval = self.get_compileropt_value('winlibs', env, target, subproject) + assert isinstance(retval, list) + libs: T.List[str] = retval[:] for l in libs: assert isinstance(l, str) return libs @@ -621,18 +632,21 @@ class ElbrusCPPCompiler(ElbrusCompiler, CPPCompiler): dependencies=dependencies) # Elbrus C++ compiler does not support RTTI, so don't check for it. - 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]: args: T.List[str] = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append(self._find_best_cpp_std(std)) - key = self.form_compileropt_key('eh') - non_msvc_eh_options(options.get_value(key), args) + eh = self.get_compileropt_value('eh', env, target, subproject) + assert isinstance(eh, str) - key = self.form_compileropt_key('debugstl') - if options.get_value(key): + non_msvc_eh_options(eh, args) + + debugstl = self.get_compileropt_value('debugstl', env, target, subproject) + assert isinstance(debugstl, str) + if debugstl: args.append('-D_GLIBCXX_DEBUG=1') return args @@ -694,25 +708,34 @@ class IntelCPPCompiler(IntelGnuLikeCompiler, CPPCompiler): self._update_language_stds(opts, c_stds + g_stds) return opts - 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]: args: T.List[str] = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + + std = self.get_compileropt_value('std', env, target, subproject) + rtti = self.get_compileropt_value('rtti', env, target, subproject) + debugstl = self.get_compileropt_value('debugstl', env, target, subproject) + eh = self.get_compileropt_value('eh', env, target, subproject) + + assert isinstance(std, str) + assert isinstance(rtti, bool) + assert isinstance(eh, str) + assert isinstance(debugstl, bool) + if std != 'none': remap_cpp03 = { 'c++03': 'c++98', 'gnu++03': 'gnu++98' } args.append('-std=' + remap_cpp03.get(std, std)) - if options.get_value(key.evolve('eh')) == 'none': + if eh == 'none': args.append('-fno-exceptions') - if not options.get_value(key.evolve('rtti')): + if rtti: args.append('-fno-rtti') - if options.get_value(key.evolve('debugstl')): + if debugstl: args.append('-D_GLIBCXX_DEBUG=1') return args - def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: return [] @@ -739,10 +762,14 @@ class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase): 'c++latest': (False, "latest"), } - def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: # need a typeddict for this key = self.form_compileropt_key('winlibs') - return T.cast('T.List[str]', options.get_value(key)[:]) + if target: + value = env.coredata.get_option_for_target(target, key) + else: + value = env.coredata.get_option_for_subproject(key, subproject) + return T.cast('T.List[str]', value)[:] def _get_options_impl(self, opts: 'MutableKeyedOptionDictType', cpp_stds: T.List[str]) -> 'MutableKeyedOptionDictType': opts = super().get_options() @@ -771,11 +798,17 @@ class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase): std_opt.set_versions(cpp_stds) return opts - 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]: args: T.List[str] = [] - key = self.form_compileropt_key('std') - eh = options.get_value(self.form_compileropt_key('eh')) + std = self.get_compileropt_value('std', env, target, subproject) + eh = self.get_compileropt_value('eh', env, target, subproject) + rtti = self.get_compileropt_value('rtti', env, target, subproject) + + assert isinstance(std, str) + assert isinstance(rtti, bool) + assert isinstance(eh, str) + if eh == 'default': args.append('/EHsc') elif eh == 'none': @@ -783,10 +816,10 @@ class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase): else: args.append('/EH' + eh) - if not options.get_value(self.form_compileropt_key('rtti')): + if not rtti: args.append('/GR-') - permissive, ver = self.VC_VERSION_MAP[options.get_value(key)] + permissive, ver = self.VC_VERSION_MAP[std] if ver is not None: args.append(f'/std:c++{ver}') @@ -800,7 +833,6 @@ class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase): # XXX: this is a hack because so much GnuLike stuff is in the base CPPCompiler class. return Compiler.get_compiler_check_args(self, mode) - class CPP11AsCPP14Mixin(CompilerMixinBase): """Mixin class for VisualStudio and ClangCl to replace C++11 std with C++14. @@ -808,25 +840,25 @@ class CPP11AsCPP14Mixin(CompilerMixinBase): This is a limitation of Clang and MSVC that ICL doesn't share. """ - 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]: # Note: there is no explicit flag for supporting C++11; we attempt to do the best we can # which means setting the C++ standard version to C++14, in compilers that support it # (i.e., after VS2015U3) # if one is using anything before that point, one cannot set the standard. - key = self.form_compileropt_key('std') - if options.get_value(key) in {'vc++11', 'c++11'}: + stdkey = self.form_compileropt_key('std') + if target is not None: + std = env.coredata.get_option_for_target(target, stdkey) + else: + std = env.coredata.get_option_for_subproject(stdkey, subproject) + if std in {'vc++11', 'c++11'}: mlog.warning(self.id, 'does not support C++11;', 'attempting best effort; setting the standard to C++14', once=True, fatal=False) - # Don't mutate anything we're going to change, we need to use - # deepcopy since we're messing with members, and we can't simply - # copy the members because the option proxy doesn't support it. - options = copy.deepcopy(options) - if options.get_value(key) == 'vc++11': - options.set_value(key, 'vc++14') - else: - options.set_value(key, 'c++14') - return super().get_option_compile_args(options) + original_args = super().get_option_compile_args(target, env, subproject) + std_mapping = {'/std:c++11': '/std:c++14', + '/std:c++14': '/std:vc++14'} + processed_args = [std_mapping.get(x, x) for x in original_args] + return processed_args class VisualStudioCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixin, MSVCCompiler, CPPCompiler): @@ -859,14 +891,12 @@ class VisualStudioCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixi cpp_stds.extend(['c++20', 'vc++20']) return self._get_options_impl(super().get_options(), cpp_stds) - def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: - key = self.form_compileropt_key('std') - if options.get_value(key) != 'none' and version_compare(self.version, '<19.00.24210'): + def get_option_compile_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: + std = self.get_compileropt_value('std', env, target, subproject) + if std != 'none' and version_compare(self.version, '<19.00.24210'): mlog.warning('This version of MSVC does not support cpp_std arguments', fatal=False) - options = copy.copy(options) - options.set_value(key, 'none') - args = super().get_option_compile_args(options) + args = super().get_option_compile_args(target, env, subproject) if version_compare(self.version, '<19.11'): try: @@ -939,17 +969,17 @@ class ArmCPPCompiler(ArmCompiler, CPPCompiler): std_opt.set_versions(['c++03', 'c++11']) return opts - 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]: args: T.List[str] = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std == 'c++11': args.append('--cpp11') elif std == 'c++03': args.append('--cpp') return args - def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: return [] def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: @@ -969,7 +999,7 @@ class CcrxCPPCompiler(CcrxCompiler, CPPCompiler): def get_always_args(self) -> T.List[str]: return ['-nologo', '-lang=cpp'] - 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_compile_only_args(self) -> T.List[str]: @@ -978,7 +1008,7 @@ class CcrxCPPCompiler(CcrxCompiler, CPPCompiler): def get_output_args(self, outputname: str) -> T.List[str]: return [f'-output=obj={outputname}'] - def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: return [] def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: @@ -1001,10 +1031,10 @@ class TICPPCompiler(TICompiler, CPPCompiler): std_opt.set_versions(['c++03']) return opts - 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]: args: T.List[str] = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('--' + std) return args @@ -1012,7 +1042,7 @@ class TICPPCompiler(TICompiler, CPPCompiler): def get_always_args(self) -> T.List[str]: return [] - def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: return [] class C2000CPPCompiler(TICPPCompiler): @@ -1041,10 +1071,10 @@ class MetrowerksCPPCompilerARM(MetrowerksCompiler, CPPCompiler): self._update_language_stds(opts, []) return opts - 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]: args: T.List[str] = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('-lang') args.append(std) @@ -1069,10 +1099,10 @@ class MetrowerksCPPCompilerEmbeddedPowerPC(MetrowerksCompiler, CPPCompiler): self._update_language_stds(opts, []) return opts - 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]: args: T.List[str] = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('-lang ' + std) return args diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index 6a49d95..284f284 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -8,20 +8,18 @@ import os.path import string import typing as T -from .. import coredata from .. import options from .. import mlog from ..mesonlib import ( EnvironmentException, Popen_safe, is_windows, LibType, version_compare ) -from ..options import OptionKey from .compilers import Compiler if T.TYPE_CHECKING: from .compilers import CompileCheckMode from ..build import BuildTarget - from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType + from ..coredata import MutableKeyedOptionDictType from ..dependencies import Dependency from ..environment import Environment # noqa: F401 from ..envconfig import MachineInfo @@ -553,7 +551,7 @@ class CudaCompiler(Compiler): # Use the -ccbin option, if available, even during sanity checking. # Otherwise, on systems where CUDA does not support the default compiler, # NVCC becomes unusable. - flags += self.get_ccbin_args(env.coredata.optstore) + flags += self.get_ccbin_args(None, env, '') # If cross-compiling, we can't run the sanity check, only compile it. if self.is_cross and not env.has_exe_wrapper(): @@ -663,35 +661,26 @@ class CudaCompiler(Compiler): return opts - def _to_host_compiler_options(self, master_options: 'KeyedOptionDictType') -> 'KeyedOptionDictType': - """ - Convert an NVCC Option set to a host compiler's option set. - """ - - # We must strip the -std option from the host compiler option set, as NVCC has - # its own -std flag that may not agree with the host compiler's. - host_options = {key: master_options.get(key, opt) for key, opt in self.host_compiler.get_options().items()} - std_key = OptionKey(f'{self.host_compiler.language}_std', machine=self.for_machine) - overrides = {std_key: 'none'} - # To shut up mypy. - return coredata.OptionsView(host_options, overrides=overrides) - - def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: - args = self.get_ccbin_args(options) + def get_option_compile_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: + args = self.get_ccbin_args(target, env, subproject) # On Windows, the version of the C++ standard used by nvcc is dictated by # the combination of CUDA version and MSVC version; the --std= is thus ignored # and attempting to use it will result in a warning: https://stackoverflow.com/a/51272091/741027 if not is_windows(): - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('--std=' + std) - return args + self._to_host_flags(self.host_compiler.get_option_compile_args(self._to_host_compiler_options(options))) + try: + host_compiler_args = self.host_compiler.get_option_compile_args(target, env, subproject) + except KeyError: + host_compiler_args = [] + return args + self._to_host_flags(host_compiler_args) - def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: - args = self.get_ccbin_args(options) - return args + self._to_host_flags(self.host_compiler.get_option_link_args(self._to_host_compiler_options(options)), Phase.LINKER) + def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: + args = self.get_ccbin_args(target, env, subproject) + return args + self._to_host_flags(self.host_compiler.get_option_link_args(target, env, subproject), Phase.LINKER) def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, suffix: str, soversion: str, @@ -801,9 +790,15 @@ class CudaCompiler(Compiler): def get_dependency_link_args(self, dep: 'Dependency') -> T.List[str]: return self._to_host_flags(super().get_dependency_link_args(dep), Phase.LINKER) - def get_ccbin_args(self, ccoptions: 'KeyedOptionDictType') -> T.List[str]: + def get_ccbin_args(self, + target: 'T.Optional[BuildTarget]', + env: 'Environment', + subproject: T.Optional[str] = None) -> T.List[str]: key = self.form_compileropt_key('ccbindir') - ccbindir = ccoptions.get_value(key) + if target: + ccbindir = env.coredata.get_option_for_target(target, key) + else: + ccbindir = env.coredata.get_option_for_subproject(key, subproject) if isinstance(ccbindir, str) and ccbindir != '': return [self._shield_nvcc_list_arg('-ccbin='+ccbindir, False)] else: diff --git a/mesonbuild/compilers/cython.py b/mesonbuild/compilers/cython.py index ed0ab31..27cad55 100644 --- a/mesonbuild/compilers/cython.py +++ b/mesonbuild/compilers/cython.py @@ -11,8 +11,9 @@ from ..mesonlib import EnvironmentException, version_compare from .compilers import Compiler if T.TYPE_CHECKING: - from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType + from ..coredata import MutableKeyedOptionDictType from ..environment import Environment + from ..build import BuildTarget class CythonCompiler(Compiler): @@ -85,13 +86,14 @@ class CythonCompiler(Compiler): return opts - 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]: args: T.List[str] = [] - key = self.form_compileropt_key('version') - version = options.get_value(key) + version = self.get_compileropt_value('version', env, target, subproject) + assert isinstance(version, str) args.append(f'-{version}') - key = self.form_compileropt_key('language') - lang = options.get_value(key) + + lang = self.get_compileropt_value('language', env, target, subproject) + assert isinstance(lang, str) if lang == 'cpp': args.append('--cplus') return args diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 72c9a5a..0885518 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -27,12 +27,13 @@ from mesonbuild.mesonlib import ( ) if T.TYPE_CHECKING: - from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType + from ..coredata import MutableKeyedOptionDictType from ..dependencies import Dependency from ..envconfig import MachineInfo from ..environment import Environment from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice + from ..build import BuildTarget class FortranCompiler(CLikeCompiler, Compiler): @@ -284,10 +285,10 @@ class GnuFortranCompiler(GnuCompiler, FortranCompiler): self._update_language_stds(opts, fortran_stds) return opts - 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]: args: T.List[str] = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('-std=' + std) return args @@ -418,11 +419,11 @@ class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): self._update_language_stds(opts, ['none', 'legacy', 'f95', 'f2003', 'f2008', 'f2018']) return opts - 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]: args: T.List[str] = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} + assert isinstance(std, str) if std != 'none': args.append('-stand=' + stds[std]) return args @@ -472,11 +473,11 @@ class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): self._update_language_stds(opts, ['none', 'legacy', 'f95', 'f2003', 'f2008', 'f2018']) return opts - 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]: args: T.List[str] = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} + assert isinstance(std, str) if std != 'none': args.append('/stand:' + stds[std]) return args diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 19a6bb4..4792a8a 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -378,7 +378,7 @@ class CLikeCompiler(Compiler): try: crt_val = env.coredata.optstore.get_value('b_vscrt') buildtype = env.coredata.optstore.get_value('buildtype') - cargs += self.get_crt_compile_args(crt_val, buildtype) + cargs += self.get_crt_compile_args(crt_val, buildtype) # type: ignore[arg-type] except (KeyError, AttributeError): pass diff --git a/mesonbuild/compilers/mixins/elbrus.py b/mesonbuild/compilers/mixins/elbrus.py index 5818d8d..4bf0826 100644 --- a/mesonbuild/compilers/mixins/elbrus.py +++ b/mesonbuild/compilers/mixins/elbrus.py @@ -18,7 +18,7 @@ from ...options import OptionKey if T.TYPE_CHECKING: from ...environment import Environment - from ...coredata import KeyedOptionDictType + from ...build import BuildTarget class ElbrusCompiler(GnuLikeCompiler): @@ -83,9 +83,14 @@ class ElbrusCompiler(GnuLikeCompiler): # Actually it's not supported for now, but probably will be supported in future return 'pch' - 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]: args: T.List[str] = [] - std = options.get_value(OptionKey(f'{self.language}_std', machine=self.for_machine)) + key = OptionKey(f'{self.language}_std', machine=self.for_machine) + if target: + std = env.coredata.get_option_for_target(target, key) + else: + std = env.coredata.get_option_for_subproject(key, subproject) + assert isinstance(std, str) if std != 'none': args.append('-std=' + std) return args diff --git a/mesonbuild/compilers/mixins/emscripten.py b/mesonbuild/compilers/mixins/emscripten.py index 24ffced..c5b2e6d 100644 --- a/mesonbuild/compilers/mixins/emscripten.py +++ b/mesonbuild/compilers/mixins/emscripten.py @@ -51,7 +51,8 @@ class EmscriptenMixin(Compiler): def thread_link_flags(self, env: 'Environment') -> T.List[str]: args = ['-pthread'] - count: int = env.coredata.optstore.get_value(OptionKey(f'{self.language}_thread_count', machine=self.for_machine)) + count = env.coredata.optstore.get_value(OptionKey(f'{self.language}_thread_count', machine=self.for_machine)) + assert isinstance(count, int) if count: args.append(f'-sPTHREAD_POOL_SIZE={count}') return args diff --git a/mesonbuild/compilers/mixins/islinker.py b/mesonbuild/compilers/mixins/islinker.py index 8d17a94..6c9daf3 100644 --- a/mesonbuild/compilers/mixins/islinker.py +++ b/mesonbuild/compilers/mixins/islinker.py @@ -19,6 +19,7 @@ if T.TYPE_CHECKING: from ...coredata import KeyedOptionDictType from ...environment import Environment from ...compilers.compilers import Compiler + from ...build import BuildTarget else: # This is a bit clever, for mypy we pretend that these mixins descend from # Compiler, so we get all of the methods and attributes defined for us, but @@ -58,7 +59,7 @@ class BasicLinkerIsCompilerMixin(Compiler): def get_linker_lib_prefix(self) -> str: return '' - def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + def get_option_link_args(self, target: BuildTarget, env: Environment, subproject: T.Optional[str] = None) -> T.List[str]: return [] def has_multi_link_args(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: diff --git a/mesonbuild/compilers/objc.py b/mesonbuild/compilers/objc.py index 262a4c4..b133d47 100644 --- a/mesonbuild/compilers/objc.py +++ b/mesonbuild/compilers/objc.py @@ -20,6 +20,7 @@ if T.TYPE_CHECKING: from ..environment import Environment from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice + from ..build import BuildTarget class ObjCCompiler(CLikeCompiler, Compiler): @@ -75,14 +76,18 @@ class GnuObjCCompiler(GnuCStds, GnuCompiler, ObjCCompiler): self.supported_warn_args(gnu_common_warning_args) + self.supported_warn_args(gnu_objc_warning_args))} - def get_option_compile_args(self, options: 'coredata.KeyedOptionDictType') -> T.List[str]: - args = [] - std = options.get_value(self.form_compileropt_key('std')) + def get_option_compile_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: + args: T.List[str] = [] + key = OptionKey('c_std', machine=self.for_machine) + if target: + std = env.coredata.get_option_for_target(target, key) + else: + std = env.coredata.get_option_for_subproject(key, subproject) + assert isinstance(std, str) if std != 'none': args.append('-std=' + std) return args - class ClangObjCCompiler(ClangCStds, ClangCompiler, ObjCCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', @@ -109,9 +114,11 @@ class ClangObjCCompiler(ClangCStds, ClangCompiler, ObjCCompiler): return 'c_std' return super().make_option_name(key) - def get_option_compile_args(self, options: 'coredata.KeyedOptionDictType') -> T.List[str]: + def get_option_compile_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: args = [] - std = options.get_value(self.form_compileropt_key('std')) + key = OptionKey('c_std', machine=self.for_machine) + std = self.get_compileropt_value(key, env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('-std=' + std) return args diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py index 104d0cb..743bbb9 100644 --- a/mesonbuild/compilers/objcpp.py +++ b/mesonbuild/compilers/objcpp.py @@ -20,6 +20,7 @@ if T.TYPE_CHECKING: from ..environment import Environment from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice + from ..build import BuildTarget class ObjCPPCompiler(CLikeCompiler, Compiler): @@ -80,14 +81,18 @@ class GnuObjCPPCompiler(GnuCPPStds, GnuCompiler, ObjCPPCompiler): self.supported_warn_args(gnu_common_warning_args) + self.supported_warn_args(gnu_objc_warning_args))} - def get_option_compile_args(self, options: 'coredata.KeyedOptionDictType') -> T.List[str]: - args = [] - std = options.get_value(self.form_compileropt_key('std')) + def get_option_compile_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: + args: T.List[str] = [] + key = OptionKey('cpp_std', machine=self.for_machine) + if target: + std = env.coredata.get_option_for_target(target, key) + else: + std = env.coredata.get_option_for_subproject(key, subproject) + assert isinstance(std, str) if std != 'none': args.append('-std=' + std) return args - class ClangObjCPPCompiler(ClangCPPStds, ClangCompiler, ObjCPPCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, @@ -105,9 +110,11 @@ class ClangObjCPPCompiler(ClangCPPStds, ClangCompiler, ObjCPPCompiler): '3': default_warn_args + ['-Wextra', '-Wpedantic'], 'everything': ['-Weverything']} - def get_option_compile_args(self, options: 'coredata.KeyedOptionDictType') -> T.List[str]: + def get_option_compile_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: args = [] - std = options.get_value(self.form_compileropt_key('std')) + key = OptionKey('cpp_std', machine=self.for_machine) + std = self.get_compileropt_value(key, env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('-std=' + std) return args diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index aacdc07..3acc30e 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -15,12 +15,13 @@ from ..options import OptionKey from .compilers import Compiler, clike_debug_args if T.TYPE_CHECKING: - from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType + from ..coredata import MutableKeyedOptionDictType from ..envconfig import MachineInfo from ..environment import Environment # noqa: F401 from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice from ..dependencies import Dependency + from ..build import BuildTarget rust_optimization_args: T.Dict[str, T.List[str]] = { @@ -251,10 +252,10 @@ class RustCompiler(Compiler): # provided by the linker flags. 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]: args = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + std = self.get_compileropt_value('std', env, target, subproject) + assert isinstance(std, str) if std != 'none': args.append('--edition=' + std) return args diff --git a/mesonbuild/compilers/vala.py b/mesonbuild/compilers/vala.py index 35c7a68..28861a6 100644 --- a/mesonbuild/compilers/vala.py +++ b/mesonbuild/compilers/vala.py @@ -14,11 +14,11 @@ from .compilers import CompileCheckMode, Compiler if T.TYPE_CHECKING: from ..arglist import CompilerArgs - from ..coredata import KeyedOptionDictType from ..envconfig import MachineInfo from ..environment import Environment from ..mesonlib import MachineChoice from ..dependencies import Dependency + from ..build import BuildTarget class ValaCompiler(Compiler): @@ -141,7 +141,7 @@ class ValaCompiler(Compiler): def thread_link_flags(self, env: 'Environment') -> T.List[str]: return [] - def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: return [] def build_wrapper_args(self, env: 'Environment', |