diff options
Diffstat (limited to 'mesonbuild/environment.py')
-rw-r--r-- | mesonbuild/environment.py | 116 |
1 files changed, 85 insertions, 31 deletions
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index f322cda..489ef50 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -12,6 +12,7 @@ import collections from . import coredata from . import mesonlib from . import machinefile +from . import options CmdLineFileParser = machinefile.CmdLineFileParser @@ -34,6 +35,7 @@ from .compilers import ( is_library, is_llvm_ir, is_object, + is_separate_compile, is_source, ) @@ -43,13 +45,20 @@ from mesonbuild import envconfig if T.TYPE_CHECKING: from .compilers import Compiler from .compilers.mixins.visualstudio import VisualStudioLikeCompiler - from .options import ElementaryOptionValues + from .options import OptionDict, ElementaryOptionValues from .wrap.wrap import Resolver from . import cargo CompilersDict = T.Dict[str, Compiler] +NON_LANG_ENV_OPTIONS = [ + ('PKG_CONFIG_PATH', 'pkg_config_path'), + ('CMAKE_PREFIX_PATH', 'cmake_prefix_path'), + ('LDFLAGS', 'ldflags'), + ('CPPFLAGS', 'cppflags'), +] + build_filename = 'meson.build' @@ -639,7 +648,12 @@ class Environment: # # Note that order matters because of 'buildtype', if it is after # 'optimization' and 'debug' keys, it override them. - self.options: T.MutableMapping[OptionKey, ElementaryOptionValues] = collections.OrderedDict() + self.options: OptionDict = collections.OrderedDict() + + # Environment variables with the name converted into an OptionKey type. + # These have subtly different behavior compared to machine files, so do + # not store them in self.options. See _set_default_options_from_env. + self.env_opts: OptionDict = {} self.machinestore = machinefile.MachineFileStore(self.coredata.config_files, self.coredata.cross_files, self.source_dir) @@ -716,13 +730,14 @@ class Environment: def mfilestr2key(self, machine_file_string: str, section: T.Optional[str], section_subproject: T.Optional[str], machine: MachineChoice) -> OptionKey: key = OptionKey.from_string(machine_file_string) - assert key.machine == MachineChoice.HOST if key.subproject: suggestion = section if section == 'project options' else 'built-in options' raise MesonException(f'Do not set subproject options in [{section}] section, use [subproject:{suggestion}] instead.') if section_subproject: key = key.evolve(subproject=section_subproject) if machine == MachineChoice.BUILD: + if key.machine == MachineChoice.BUILD: + mlog.deprecation('Setting build machine options in the native file does not need the "build." prefix', once=True) return key.evolve(machine=machine) return key @@ -777,12 +792,7 @@ class Environment: def _set_default_options_from_env(self) -> None: opts: T.List[T.Tuple[str, str]] = ( [(v, f'{k}_args') for k, v in compilers.compilers.CFLAGS_MAPPING.items()] + - [ - ('PKG_CONFIG_PATH', 'pkg_config_path'), - ('CMAKE_PREFIX_PATH', 'cmake_prefix_path'), - ('LDFLAGS', 'ldflags'), - ('CPPFLAGS', 'cppflags'), - ] + NON_LANG_ENV_OPTIONS ) env_opts: T.DefaultDict[OptionKey, T.List[str]] = collections.defaultdict(list) @@ -817,35 +827,35 @@ class Environment: env_opts[key].extend(p_list) elif keyname == 'cppflags': for lang in compilers.compilers.LANGUAGES_USING_CPPFLAGS: - key = OptionKey(f'{lang}_env_args', machine=for_machine) + key = OptionKey(f'{lang}_args', machine=for_machine) env_opts[key].extend(p_list) else: key = OptionKey.from_string(keyname).evolve(machine=for_machine) if evar in compilers.compilers.CFLAGS_MAPPING.values(): - # If this is an environment variable, we have to - # store it separately until the compiler is - # instantiated, as we don't know whether the - # compiler will want to use these arguments at link - # time and compile time (instead of just at compile - # time) until we're instantiating that `Compiler` - # object. This is required so that passing - # `-Dc_args=` on the command line and `$CFLAGS` - # have subtly different behavior. `$CFLAGS` will be - # added to the linker command line if the compiler - # acts as a linker driver, `-Dc_args` will not. - # - # We still use the original key as the base here, as - # we want to inherit the machine and the compiler - # language lang = key.name.split('_', 1)[0] - key = key.evolve(f'{lang}_env_args') + key = key.evolve(f'{lang}_args') env_opts[key].extend(p_list) - # Only store options that are not already in self.options, - # otherwise we'd override the machine files - for k, v in env_opts.items(): - if k not in self.options: - self.options[k] = v + # If this is an environment variable, we have to + # store it separately until the compiler is + # instantiated, as we don't know whether the + # compiler will want to use these arguments at link + # time and compile time (instead of just at compile + # time) until we're instantiating that `Compiler` + # object. This is required so that passing + # `-Dc_args=` on the command line and `$CFLAGS` + # have subtly different behavior. `$CFLAGS` will be + # added to the linker command line if the compiler + # acts as a linker driver, `-Dc_args` will not. + for (_, keyname), for_machine in itertools.product(NON_LANG_ENV_OPTIONS, MachineChoice): + key = OptionKey.from_string(keyname).evolve(machine=for_machine) + # Only store options that are not already in self.options, + # otherwise we'd override the machine files + if key in env_opts and key not in self.options: + self.options[key] = env_opts[key] + del env_opts[key] + + self.env_opts.update(env_opts) def _set_default_binaries_from_env(self) -> None: """Set default binaries from the environment. @@ -928,6 +938,9 @@ class Environment: def is_assembly(self, fname: 'mesonlib.FileOrString') -> bool: return is_assembly(fname) + def is_separate_compile(self, fname: 'mesonlib.FileOrString') -> bool: + return is_separate_compile(fname) + def is_llvm_ir(self, fname: 'mesonlib.FileOrString') -> bool: return is_llvm_ir(fname) @@ -1064,3 +1077,44 @@ class Environment: if extra_paths: env.prepend('PATH', list(extra_paths)) return env + + def add_lang_args(self, lang: str, comp: T.Type['Compiler'], + for_machine: MachineChoice) -> None: + """Add global language arguments that are needed before compiler/linker detection.""" + description = f'Extra arguments passed to the {lang}' + argkey = OptionKey(f'{lang}_args', machine=for_machine) + largkey = OptionKey(f'{lang}_link_args', machine=for_machine) + + comp_args_from_envvar = False + comp_options = self.coredata.optstore.get_pending_value(argkey) + if comp_options is None: + comp_args_from_envvar = True + comp_options = self.env_opts.get(argkey, []) + + link_options = self.coredata.optstore.get_pending_value(largkey) + if link_options is None: + link_options = self.env_opts.get(largkey, []) + + assert isinstance(comp_options, (str, list)), 'for mypy' + assert isinstance(link_options, (str, list)), 'for mypy' + + cargs = options.UserStringArrayOption( + argkey.name, + description + ' compiler', + comp_options, split_args=True, allow_dups=True) + + largs = options.UserStringArrayOption( + largkey.name, + description + ' linker', + link_options, split_args=True, allow_dups=True) + + self.coredata.optstore.add_compiler_option(lang, argkey, cargs) + self.coredata.optstore.add_compiler_option(lang, largkey, largs) + + if comp.INVOKES_LINKER and comp_args_from_envvar: + # If the compiler acts as a linker driver, and we're using the + # environment variable flags for both the compiler and linker + # arguments, then put the compiler flags in the linker flags as well. + # This is how autotools works, and the env vars feature is for + # autotools compatibility. + largs.extend_value(comp_options) |