options: restore special behavior of CFLAGS vs. c_args
For compatibility with Autotools, CFLAGS is added to the linker command
line if the compiler acts as a linker driver. However, this behavior
was lost in commit d37d649b0
("Make all Meson level options overridable
per subproject.", 2025-02-13).
The issue is that (for example) c_link_args is stored in env.options, and
from that point on it is treated as a machine-file option. This includes
not being able to override it in compilers.get_global_options:
- initialize_from_top_level_project_call places it in pending_options
- add_lang_args passes the right value to add_compiler_option
- add_compiler_option calls add_system_option_internal
- add_system_option_internal fishes the value out of pending_options
and ignores what get_global_options provided.
Instead, store the putative values of the compiler options coming from
the environment in a separate dictionary, that is only accessed by
get_global_options. This way it never appears in pending_options, and
also there is no internal *_env_args variable anymore.
Fixes: #14533
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
d11fa36196
commit
2d1c67f095
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue