1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
|
# SPDX-License-Identifier: Apache-2.0
# Copyright 2012-2020 The Meson development team
# Copyright © 2023-2025 Intel Corporation
from __future__ import annotations
import itertools
import os, re
import typing as T
import collections
from . import cmdline
from . import coredata
from . import mesonlib
from . import machinefile
from . import options
from .mesonlib import (
MesonException, MachineChoice, Popen_safe, PerMachine,
PerMachineDefaultable, PerThreeMachineDefaultable, split_args,
MesonBugException
)
from .options import OptionKey
from . import mlog
from .programs import ExternalProgram
from .envconfig import (
BinaryTable, MachineInfo, Properties, CMakeVariables,
detect_machine_info, machine_info_can_run
)
from . import compilers
from mesonbuild import envconfig
if T.TYPE_CHECKING:
from .compilers import Compiler
from .options import OptionDict, ElementaryOptionValues
from .wrap.wrap import Resolver
NON_LANG_ENV_OPTIONS = [
('PKG_CONFIG_PATH', 'pkg_config_path'),
('CMAKE_PREFIX_PATH', 'cmake_prefix_path'),
('LDFLAGS', 'ldflags'),
('CPPFLAGS', 'cppflags'),
]
build_filename = 'meson.build'
def _as_str(val: object) -> str:
assert isinstance(val, str), 'for mypy'
return val
def _get_env_var(for_machine: MachineChoice, is_cross: bool, var_name: str) -> T.Optional[str]:
"""
Returns the exact env var and the value.
"""
candidates = PerMachine(
# The prefixed build version takes priority, but if we are native
# compiling we fall back on the unprefixed host version. This
# allows native builds to never need to worry about the 'BUILD_*'
# ones.
([var_name + '_FOR_BUILD'] if is_cross else [var_name]),
# Always just the unprefixed host versions
[var_name]
)[for_machine]
for var in candidates:
value = os.environ.get(var)
if value is not None:
break
else:
formatted = ', '.join([f'{var!r}' for var in candidates])
mlog.debug(f'None of {formatted} are defined in the environment, not changing global flags.')
return None
mlog.debug(f'Using {var!r} from environment with value: {value!r}')
return value
class Environment:
private_dir = 'meson-private'
log_dir = 'meson-logs'
info_dir = 'meson-info'
def __init__(self, source_dir: str, build_dir: T.Optional[str], cmd_options: cmdline.SharedCMDOptions) -> None:
self.source_dir = source_dir
# Do not try to create build directories when build_dir is none.
# This reduced mode is used by the --buildoptions introspector
if build_dir is not None:
self.build_dir = build_dir
self.scratch_dir = os.path.join(build_dir, Environment.private_dir)
self.log_dir = os.path.join(build_dir, Environment.log_dir)
self.info_dir = os.path.join(build_dir, Environment.info_dir)
os.makedirs(self.scratch_dir, exist_ok=True)
os.makedirs(self.log_dir, exist_ok=True)
os.makedirs(self.info_dir, exist_ok=True)
try:
self.coredata: coredata.CoreData = coredata.load(self.get_build_dir(), suggest_reconfigure=False)
self.first_invocation = False
except FileNotFoundError:
self.create_new_coredata(cmd_options)
except coredata.MesonVersionMismatchException as e:
# This is routine, but tell the user the update happened
mlog.log('Regenerating configuration from scratch:', str(e))
cmdline.read_cmd_line_file(self.build_dir, cmd_options)
self.create_new_coredata(cmd_options)
except MesonException as e:
# If we stored previous command line options, we can recover from
# a broken/outdated coredata.
if os.path.isfile(cmdline.get_cmd_line_file(self.build_dir)):
mlog.warning('Regenerating configuration from scratch.', fatal=False)
mlog.log('Reason:', mlog.red(str(e)))
cmdline.read_cmd_line_file(self.build_dir, cmd_options)
self.create_new_coredata(cmd_options)
else:
raise MesonException(f'{str(e)} Try regenerating using "meson setup --wipe".')
else:
# Just create a fresh coredata in this case
self.build_dir = ''
self.scratch_dir = ''
self.create_new_coredata(cmd_options)
## locally bind some unfrozen configuration
# Stores machine infos, the only *three* machine one because we have a
# target machine info on for the user (Meson never cares about the
# target machine.)
machines: PerThreeMachineDefaultable[MachineInfo] = PerThreeMachineDefaultable()
# Similar to coredata.compilers, but lower level in that there is no
# meta data, only names/paths.
binaries: PerMachineDefaultable[BinaryTable] = PerMachineDefaultable()
# Misc other properties about each machine.
properties: PerMachineDefaultable[Properties] = PerMachineDefaultable()
# CMake toolchain variables
cmakevars: PerMachineDefaultable[CMakeVariables] = PerMachineDefaultable()
## Setup build machine defaults
# Will be fully initialized later using compilers later.
machines.build = detect_machine_info()
# Just uses hard-coded defaults and environment variables. Might be
# overwritten by a native file.
binaries.build = BinaryTable()
properties.build = Properties()
# Options with the key parsed into an OptionKey type.
#
# Note that order matters because of 'buildtype', if it is after
# 'optimization' and 'debug' keys, it override them.
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)
## Read in native file(s) to override build machine configuration
if self.coredata.config_files is not None:
config = machinefile.parse_machine_files(self.coredata.config_files, self.source_dir)
binaries.build = BinaryTable(config.get('binaries', {}))
properties.build = Properties(config.get('properties', {}))
cmakevars.build = CMakeVariables(config.get('cmake', {}))
self._load_machine_file_options(
config, properties.build,
MachineChoice.BUILD if self.coredata.cross_files else MachineChoice.HOST)
## Read in cross file(s) to override host machine configuration
if self.coredata.cross_files:
config = machinefile.parse_machine_files(self.coredata.cross_files, self.source_dir)
properties.host = Properties(config.get('properties', {}))
binaries.host = BinaryTable(config.get('binaries', {}))
cmakevars.host = CMakeVariables(config.get('cmake', {}))
if 'host_machine' in config:
machines.host = MachineInfo.from_literal(config['host_machine'])
if 'target_machine' in config:
machines.target = MachineInfo.from_literal(config['target_machine'])
# Keep only per machine options from the native file. The cross
# file takes precedence over all other options.
for key, value in list(self.options.items()):
if self.coredata.optstore.is_per_machine_option(key):
self.options[key.as_build()] = value
self._load_machine_file_options(config, properties.host, MachineChoice.HOST)
## "freeze" now initialized configuration, and "save" to the class.
self.machines = machines.default_missing()
self.binaries = binaries.default_missing()
self.properties = properties.default_missing()
self.cmakevars = cmakevars.default_missing()
# Take default value from env if not set in cross/native files or command line.
self._set_default_options_from_env()
self._set_default_binaries_from_env()
self._set_default_properties_from_env()
# Warn if the user is using two different ways of setting build-type
# options that override each other
bt = OptionKey('buildtype')
db = OptionKey('debug')
op = OptionKey('optimization')
if bt in self.options and (db in self.options or op in self.options):
mlog.warning('Recommend using either -Dbuildtype or -Doptimization + -Ddebug. '
'Using both is redundant since they override each other. '
'See: https://mesonbuild.com/Builtin-options.html#build-type-options',
fatal=False)
# Filter out build machine options that are not valid per-project.
# We allow this in the file because it makes the machine files more
# useful (ie, the same file can be used for host == build configuration
# a host != build configuration)
self.options = {k: v for k, v in self.options.items()
if k.machine is MachineChoice.HOST or self.coredata.optstore.is_per_machine_option(k)}
exe_wrapper = self.lookup_binary_entry(MachineChoice.HOST, 'exe_wrapper')
if exe_wrapper is not None:
self.exe_wrapper = ExternalProgram.from_bin_list(self, MachineChoice.HOST, 'exe_wrapper')
else:
self.exe_wrapper = None
self.default_cmake = ['cmake']
self.default_pkgconfig = ['pkg-config']
self.wrap_resolver: T.Optional['Resolver'] = None
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)
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
def _load_machine_file_options(self, config: T.Mapping[str, T.Mapping[str, ElementaryOptionValues]],
properties: Properties, machine: MachineChoice) -> None:
"""Read the contents of a Machine file and put it in the options store."""
# Look for any options in the deprecated paths section, warn about
# those, then assign them. They will be overwritten by the ones in the
# "built-in options" section if they're in both sections.
paths = config.get('paths')
if paths:
mlog.deprecation('The [paths] section is deprecated, use the [built-in options] section instead.')
for strk, v in paths.items():
k = self.mfilestr2key(strk, 'paths', None, machine)
self.options[k] = v
# Next look for compiler options in the "properties" section, this is
# also deprecated, and these will also be overwritten by the "built-in
# options" section. We need to remove these from this section, as well.
deprecated_properties: T.Set[str] = set()
for lang in compilers.all_languages:
deprecated_properties.add(lang + '_args')
deprecated_properties.add(lang + '_link_args')
for strk, v in properties.properties.copy().items():
if strk in deprecated_properties:
mlog.deprecation(f'{strk} in the [properties] section of the machine file is deprecated, use the [built-in options] section.')
k = self.mfilestr2key(strk, 'properties', None, machine)
self.options[k] = v
del properties.properties[strk]
for section, values in config.items():
if ':' in section:
section_subproject, section = section.split(':', 1)
else:
section_subproject = ''
if section == 'built-in options':
for strk, v in values.items():
key = self.mfilestr2key(strk, section, section_subproject, machine)
# If we're in the cross file, and there is a `build.foo` warn about that. Later we'll remove it.
if machine is MachineChoice.HOST and key.machine is not machine:
mlog.deprecation('Setting build machine options in cross files, please use a native file instead, this will be removed in meson 2.0', once=True)
self.options[key] = v
elif section == 'project options' and machine is MachineChoice.HOST:
# Project options are only for the host machine, we don't want
# to read these from the native file
for strk, v in values.items():
# Project options are always for the host machine
key = self.mfilestr2key(strk, section, section_subproject, machine)
self.options[key] = v
elif ':' in section:
correct_subproject, correct_section = section.split(':')[-2:]
raise MesonException(
'Subproject options should always be set as '
'`[subproject:section]`, even if the options are from a '
'nested subproject. '
f'Replace `[{section_subproject}:{section}]` with `[{correct_subproject}:{correct_section}]`')
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()] +
NON_LANG_ENV_OPTIONS
)
env_opts: T.DefaultDict[OptionKey, T.List[str]] = collections.defaultdict(list)
for (evar, keyname), for_machine in itertools.product(opts, MachineChoice):
p_env = _get_env_var(for_machine, self.is_cross_build(), evar)
if p_env is not None:
# these may contain duplicates, which must be removed, else
# a duplicates-in-array-option warning arises.
if keyname == 'cmake_prefix_path':
if self.machines[for_machine].is_windows():
# Cannot split on ':' on Windows because its in the drive letter
_p_env = p_env.split(os.pathsep)
else:
# https://github.com/mesonbuild/meson/issues/7294
_p_env = re.split(r':|;', p_env)
p_list = list(mesonlib.OrderedSet(_p_env))
elif keyname == 'pkg_config_path':
p_list = list(mesonlib.OrderedSet(p_env.split(os.pathsep)))
else:
p_list = split_args(p_env)
p_list = [e for e in p_list if e] # filter out any empty elements
# Take env vars only on first invocation, if the env changes when
# reconfiguring it gets ignored.
# FIXME: We should remember if we took the value from env to warn
# if it changes on future invocations.
if self.first_invocation:
if keyname == 'ldflags':
for lang in compilers.compilers.LANGUAGES_USING_LDFLAGS:
key = OptionKey(name=f'{lang}_link_args', machine=for_machine)
env_opts[key].extend(p_list)
elif keyname == 'cppflags':
for lang in compilers.compilers.LANGUAGES_USING_CPPFLAGS:
key = OptionKey(f'{lang}_args', machine=for_machine)
env_opts[key].extend(p_list)
else:
key = OptionKey.from_string(keyname).evolve(machine=for_machine)
env_opts[key].extend(p_list)
# 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.
For example, pkg-config can be set via PKG_CONFIG, or in the machine
file. We want to set the default to the env variable.
"""
opts = itertools.chain(envconfig.DEPRECATED_ENV_PROG_MAP.items(),
envconfig.ENV_VAR_PROG_MAP.items())
for (name, evar), for_machine in itertools.product(opts, MachineChoice):
p_env = _get_env_var(for_machine, self.is_cross_build(), evar)
if p_env is not None:
if os.path.exists(p_env):
self.binaries[for_machine].binaries.setdefault(name, [p_env])
else:
self.binaries[for_machine].binaries.setdefault(name, mesonlib.split_args(p_env))
def _set_default_properties_from_env(self) -> None:
"""Properties which can also be set from the environment."""
# name, evar, split
opts: T.List[T.Tuple[str, T.List[str], bool]] = [
('boost_includedir', ['BOOST_INCLUDEDIR'], False),
('boost_librarydir', ['BOOST_LIBRARYDIR'], False),
('boost_root', ['BOOST_ROOT', 'BOOSTROOT'], True),
('java_home', ['JAVA_HOME'], False),
]
for (name, evars, split), for_machine in itertools.product(opts, MachineChoice):
for evar in evars:
p_env = _get_env_var(for_machine, self.is_cross_build(), evar)
if p_env is not None:
if split:
self.properties[for_machine].properties.setdefault(name, p_env.split(os.pathsep))
else:
self.properties[for_machine].properties.setdefault(name, p_env)
break
def create_new_coredata(self, options: cmdline.SharedCMDOptions) -> None:
# WARNING: Don't use any values from coredata in __init__. It gets
# re-initialized with project options by the interpreter during
# build file parsing.
# meson_command is used by the regenchecker script, which runs meson
meson_command = mesonlib.get_meson_command()
if meson_command is None:
meson_command = []
else:
meson_command = meson_command.copy()
self.coredata = coredata.CoreData(options, self.scratch_dir, meson_command)
self.first_invocation = True
def init_backend_options(self, backend_name: str) -> None:
# Only init backend options on first invocation otherwise it would
# override values previously set from command line.
if not self.first_invocation:
return
self.coredata.init_backend_options(backend_name)
for k, v in self.options.items():
if self.coredata.optstore.is_backend_option(k):
self.coredata.optstore.set_option(k, v)
def is_cross_build(self, when_building_for: MachineChoice = MachineChoice.HOST) -> bool:
return self.coredata.is_cross_build(when_building_for)
def dump_coredata(self) -> str:
return coredata.save(self.coredata, self.get_build_dir())
def get_log_dir(self) -> str:
return self.log_dir
def get_coredata(self) -> coredata.CoreData:
return self.coredata
@staticmethod
def get_build_command(unbuffered: bool = False) -> T.List[str]:
cmd = mesonlib.get_meson_command()
if cmd is None:
raise MesonBugException('No command?')
cmd = cmd.copy()
if unbuffered and 'python' in os.path.basename(cmd[0]):
cmd.insert(1, '-u')
return cmd
def lookup_binary_entry(self, for_machine: MachineChoice, name: str) -> T.Optional[T.List[str]]:
return self.binaries[for_machine].lookup_entry(name)
def get_scratch_dir(self) -> str:
return self.scratch_dir
def get_source_dir(self) -> str:
return self.source_dir
def get_build_dir(self) -> str:
return self.build_dir
def get_import_lib_dir(self) -> str:
"Install dir for the import library (library used for linking)"
return self.get_libdir()
def get_shared_module_dir(self) -> str:
"Install dir for shared modules that are loaded at runtime"
return self.get_libdir()
def get_shared_lib_dir(self) -> str:
"Install dir for the shared library"
m = self.machines.host
# Windows has no RPATH or similar, so DLLs must be next to EXEs.
if m.is_windows() or m.is_cygwin():
return self.get_bindir()
return self.get_libdir()
def get_jar_dir(self) -> str:
"""Install dir for JAR files"""
return f"{self.get_datadir()}/java"
def get_static_lib_dir(self) -> str:
"Install dir for the static library"
return self.get_libdir()
def get_prefix(self) -> str:
return _as_str(self.coredata.optstore.get_value_for(OptionKey('prefix')))
def get_libdir(self) -> str:
return _as_str(self.coredata.optstore.get_value_for(OptionKey('libdir')))
def get_libexecdir(self) -> str:
return _as_str(self.coredata.optstore.get_value_for(OptionKey('libexecdir')))
def get_bindir(self) -> str:
return _as_str(self.coredata.optstore.get_value_for(OptionKey('bindir')))
def get_includedir(self) -> str:
return _as_str(self.coredata.optstore.get_value_for(OptionKey('includedir')))
def get_mandir(self) -> str:
return _as_str(self.coredata.optstore.get_value_for(OptionKey('mandir')))
def get_datadir(self) -> str:
return _as_str(self.coredata.optstore.get_value_for(OptionKey('datadir')))
def get_compiler_system_lib_dirs(self, for_machine: MachineChoice) -> T.List[str]:
for comp in self.coredata.compilers[for_machine].values():
if comp.id == 'clang':
index = 1
break
elif comp.id == 'gcc':
index = 2
break
else:
# This option is only supported by gcc and clang. If we don't get a
# GCC or Clang compiler return and empty list.
return []
p, out, _ = Popen_safe(comp.get_exelist() + ['-print-search-dirs'])
if p.returncode != 0:
raise mesonlib.MesonException('Could not calculate system search dirs')
split = out.split('\n')[index].lstrip('libraries: =').split(':')
return [os.path.normpath(p) for p in split]
def get_compiler_system_include_dirs(self, for_machine: MachineChoice) -> T.List[str]:
for comp in self.coredata.compilers[for_machine].values():
if comp.id == 'clang':
break
elif comp.id == 'gcc':
break
else:
# This option is only supported by gcc and clang. If we don't get a
# GCC or Clang compiler return and empty list.
return []
return comp.get_default_include_dirs()
def need_exe_wrapper(self, for_machine: MachineChoice = MachineChoice.HOST) -> bool:
value = self.properties[for_machine].get('needs_exe_wrapper', None)
if value is not None:
assert isinstance(value, bool), 'for mypy'
return value
if not self.is_cross_build():
return False
return not machine_info_can_run(self.machines[for_machine])
def get_exe_wrapper(self) -> T.Optional[ExternalProgram]:
if not self.need_exe_wrapper():
return None
return self.exe_wrapper
def has_exe_wrapper(self) -> bool:
return self.exe_wrapper is not None and self.exe_wrapper.found()
def get_env_for_paths(self, library_paths: T.Set[str], extra_paths: T.Set[str]) -> mesonlib.EnvironmentVariables:
env = mesonlib.EnvironmentVariables()
need_wine = not self.machines.build.is_windows() and self.machines.host.is_windows()
if need_wine:
# Executable paths should be in both PATH and WINEPATH.
# - Having them in PATH makes bash completion find it,
# and make running "foo.exe" find it when wine-binfmt is installed.
# - Having them in WINEPATH makes "wine foo.exe" find it.
library_paths.update(extra_paths)
if library_paths:
if need_wine:
env.prepend('WINEPATH', list(library_paths), separator=';')
elif self.machines.host.is_windows() or self.machines.host.is_cygwin():
extra_paths.update(library_paths)
elif self.machines.host.is_darwin():
env.prepend('DYLD_LIBRARY_PATH', list(library_paths))
else:
env.prepend('LD_LIBRARY_PATH', list(library_paths))
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)
|