diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index ad252a136..d0934fc73 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -1424,12 +1424,19 @@ def get_global_options(lang: str, 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) - envkey = OptionKey(f'{lang}_env_args', machine=for_machine) - comp_key = argkey if argkey in env.options else envkey + comp_args_from_envvar = False + comp_options = env.coredata.optstore.get_pending_value(argkey) + if comp_options is None: + comp_args_from_envvar = True + comp_options = env.env_opts.get(argkey, []) + + link_args_from_envvar = False + link_options = env.coredata.optstore.get_pending_value(largkey) + if link_options is None: + link_args_from_envvar = True + link_options = env.env_opts.get(largkey, []) - comp_options = env.options.get(comp_key, []) - link_options = env.options.get(largkey, []) assert isinstance(comp_options, (str, list)), 'for mypy' assert isinstance(link_options, (str, list)), 'for mypy' @@ -1443,7 +1450,7 @@ def get_global_options(lang: str, description + ' linker', link_options, split_args=True, allow_dups=True) - if comp.INVOKES_LINKER and comp_key == envkey: + if comp.INVOKES_LINKER and comp_args_from_envvar and link_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. diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index a3b8cd5f2..2a9cf165b 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -648,6 +648,11 @@ class Environment: # 'optimization' and 'debug' keys, it override them. self.options: T.MutableMapping[OptionKey, ElementaryOptionValues] = 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: T.MutableMapping[OptionKey, ElementaryOptionValues] = {} + self.machinestore = machinefile.MachineFileStore(self.coredata.config_files, self.coredata.cross_files, self.source_dir) ## Read in native file(s) to override build machine configuration @@ -819,35 +824,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) - for k, v in env_opts.items(): + # 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 k not in self.options: - self.options[k] = v + 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. diff --git a/mesonbuild/options.py b/mesonbuild/options.py index 3653f5062..7260fcc58 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -838,6 +838,12 @@ class OptionStore: key = key.as_host() return key + def get_pending_value(self, key: T.Union[OptionKey, str], default: T.Optional[ElementaryOptionValues] = None) -> ElementaryOptionValues: + key = self.ensure_and_validate_key(key) + if key in self.options: + return self.options[key].value + return self.pending_options.get(key, default) + def get_value(self, key: T.Union[OptionKey, str]) -> ElementaryOptionValues: return self.get_value_object(key).value