Merge pull request #8159 from dcbaker/submit/all-env-variables-up-front

Read and store all environment variables up front
pull/8166/head
Jussi Pakkanen 4 years ago committed by GitHub
commit 5ff1a3ab25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      mesonbuild/backend/backends.py
  2. 18
      mesonbuild/cmake/executor.py
  3. 2
      mesonbuild/compilers/__init__.py
  4. 3
      mesonbuild/compilers/c.py
  5. 89
      mesonbuild/compilers/compilers.py
  6. 3
      mesonbuild/compilers/cpp.py
  7. 2
      mesonbuild/coredata.py
  8. 12
      mesonbuild/dependencies/base.py
  9. 65
      mesonbuild/dependencies/boost.py
  10. 2
      mesonbuild/dependencies/hdf5.py
  11. 2
      mesonbuild/dependencies/mpi.py
  12. 175
      mesonbuild/envconfig.py
  13. 144
      mesonbuild/environment.py
  14. 19
      mesonbuild/linkers.py
  15. 8
      mesonbuild/modules/unstable_external_project.py
  16. 45
      run_unittests.py

@ -29,7 +29,7 @@ from .. import build
from .. import dependencies from .. import dependencies
from .. import mesonlib from .. import mesonlib
from .. import mlog from .. import mlog
from ..compilers import languages_using_ldflags from ..compilers import LANGUAGES_USING_LDFLAGS
from ..mesonlib import ( from ..mesonlib import (
File, MachineChoice, MesonException, OptionType, OrderedSet, OptionOverrideProxy, File, MachineChoice, MesonException, OptionType, OrderedSet, OptionOverrideProxy,
classify_unity_sources, unholder, OptionKey classify_unity_sources, unholder, OptionKey
@ -480,7 +480,7 @@ class Backend:
def get_external_rpath_dirs(self, target): def get_external_rpath_dirs(self, target):
dirs = set() dirs = set()
args = [] args = []
for lang in languages_using_ldflags: for lang in LANGUAGES_USING_LDFLAGS:
try: try:
args.extend(self.environment.coredata.get_external_link_args(target.for_machine, lang)) args.extend(self.environment.coredata.get_external_link_args(target.for_machine, lang))
except Exception: except Exception:

@ -24,7 +24,6 @@ import os
from .. import mlog from .. import mlog
from ..mesonlib import PerMachine, Popen_safe, version_compare, MachineChoice, is_windows, OptionKey from ..mesonlib import PerMachine, Popen_safe, version_compare, MachineChoice, is_windows, OptionKey
from ..envconfig import get_env_var
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
from ..environment import Environment from ..environment import Environment
@ -63,23 +62,6 @@ class CMakeExecutor:
return return
self.prefix_paths = self.environment.coredata.options[OptionKey('cmake_prefix_path', machine=self.for_machine)].value self.prefix_paths = self.environment.coredata.options[OptionKey('cmake_prefix_path', machine=self.for_machine)].value
env_pref_path_raw = get_env_var(
self.for_machine,
self.environment.is_cross_build(),
'CMAKE_PREFIX_PATH')
if env_pref_path_raw is not None:
env_pref_path = [] # type: T.List[str]
if is_windows():
# Cannot split on ':' on Windows because its in the drive letter
env_pref_path = env_pref_path_raw.split(os.pathsep)
else:
# https://github.com/mesonbuild/meson/issues/7294
env_pref_path = re.split(r':|;', env_pref_path_raw)
env_pref_path = [x for x in env_pref_path if x] # Filter out empty strings
if not self.prefix_paths:
self.prefix_paths = []
self.prefix_paths += env_pref_path
if self.prefix_paths: if self.prefix_paths:
self.extra_cmake_args += ['-DCMAKE_PREFIX_PATH={}'.format(';'.join(self.prefix_paths))] self.extra_cmake_args += ['-DCMAKE_PREFIX_PATH={}'.format(';'.join(self.prefix_paths))]

@ -127,7 +127,7 @@ from .compilers import (
is_library, is_library,
is_known_suffix, is_known_suffix,
lang_suffixes, lang_suffixes,
languages_using_ldflags, LANGUAGES_USING_LDFLAGS,
sort_clink, sort_clink,
) )
from .c import ( from .c import (

@ -17,7 +17,6 @@ import typing as T
from .. import coredata from .. import coredata
from ..mesonlib import MachineChoice, MesonException, mlog, version_compare, OptionKey from ..mesonlib import MachineChoice, MesonException, mlog, version_compare, OptionKey
from ..linkers import LinkerEnvVarsMixin
from .c_function_attributes import C_FUNC_ATTRIBUTES from .c_function_attributes import C_FUNC_ATTRIBUTES
from .mixins.clike import CLikeCompiler from .mixins.clike import CLikeCompiler
from .mixins.ccrx import CcrxCompiler from .mixins.ccrx import CcrxCompiler
@ -195,7 +194,7 @@ class AppleClangCCompiler(ClangCCompiler):
_C2X_VERSION = '>=11.0.0' _C2X_VERSION = '>=11.0.0'
class EmscriptenCCompiler(EmscriptenMixin, LinkerEnvVarsMixin, ClangCCompiler): class EmscriptenCCompiler(EmscriptenMixin, ClangCCompiler):
def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool,
info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None,
linker: T.Optional['DynamicLinker'] = None, linker: T.Optional['DynamicLinker'] = None,

@ -22,13 +22,9 @@ from functools import lru_cache
from .. import coredata from .. import coredata
from .. import mlog from .. import mlog
from .. import mesonlib from .. import mesonlib
from ..linkers import LinkerEnvVarsMixin
from ..mesonlib import ( from ..mesonlib import (
EnvironmentException, MachineChoice, MesonException, EnvironmentException, MachineChoice, MesonException,
Popen_safe, split_args, LibType, TemporaryDirectoryWinProof, OptionKey, Popen_safe, LibType, TemporaryDirectoryWinProof, OptionKey,
)
from ..envconfig import (
get_env_var
) )
from ..arglist import CompilerArgs from ..arglist import CompilerArgs
@ -85,13 +81,14 @@ clink_suffixes += ('h', 'll', 's')
all_suffixes = set(itertools.chain(*lang_suffixes.values(), clink_suffixes)) # type: T.Set[str] all_suffixes = set(itertools.chain(*lang_suffixes.values(), clink_suffixes)) # type: T.Set[str]
# Languages that should use LDFLAGS arguments when linking. # Languages that should use LDFLAGS arguments when linking.
languages_using_ldflags = {'objcpp', 'cpp', 'objc', 'c', 'fortran', 'd', 'cuda'} # type: T.Set[str] LANGUAGES_USING_LDFLAGS = {'objcpp', 'cpp', 'objc', 'c', 'fortran', 'd', 'cuda'} # type: T.Set[str]
# Languages that should use CPPFLAGS arguments when linking. # Languages that should use CPPFLAGS arguments when linking.
languages_using_cppflags = {'c', 'cpp', 'objc', 'objcpp'} # type: T.Set[str] LANGUAGES_USING_CPPFLAGS = {'c', 'cpp', 'objc', 'objcpp'} # type: T.Set[str]
soregex = re.compile(r'.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$') soregex = re.compile(r'.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$')
# Environment variables that each lang uses. # Environment variables that each lang uses.
cflags_mapping = {'c': 'CFLAGS', CFLAGS_MAPPING: T.Mapping[str, str] = {
'c': 'CFLAGS',
'cpp': 'CXXFLAGS', 'cpp': 'CXXFLAGS',
'cuda': 'CUFLAGS', 'cuda': 'CUFLAGS',
'objc': 'OBJCFLAGS', 'objc': 'OBJCFLAGS',
@ -99,10 +96,13 @@ cflags_mapping = {'c': 'CFLAGS',
'fortran': 'FFLAGS', 'fortran': 'FFLAGS',
'd': 'DFLAGS', 'd': 'DFLAGS',
'vala': 'VALAFLAGS', 'vala': 'VALAFLAGS',
'rust': 'RUSTFLAGS'} # type: T.Dict[str, str] 'rust': 'RUSTFLAGS',
}
cexe_mapping = {'c': 'CC', CEXE_MAPPING: T.Mapping = {
'cpp': 'CXX'} 'c': 'CC',
'cpp': 'CXX',
}
# All these are only for C-linkable languages; see `clink_langs` above. # All these are only for C-linkable languages; see `clink_langs` above.
@ -587,11 +587,6 @@ class Compiler(metaclass=abc.ABCMeta):
""" """
return [] return []
def get_linker_args_from_envvars(self,
for_machine: MachineChoice,
is_cross: bool) -> T.List[str]:
return self.linker.get_args_from_envvars(for_machine, is_cross)
def get_options(self) -> 'KeyedOptionDictType': def get_options(self) -> 'KeyedOptionDictType':
return {} return {}
@ -1199,68 +1194,32 @@ class Compiler(metaclass=abc.ABCMeta):
def get_prelink_args(self, prelink_name: str, obj_list: T.List[str]) -> T.List[str]: def get_prelink_args(self, prelink_name: str, obj_list: T.List[str]) -> T.List[str]:
raise EnvironmentException('{} does not know how to do prelinking.'.format(self.id)) raise EnvironmentException('{} does not know how to do prelinking.'.format(self.id))
def get_args_from_envvars(lang: str,
for_machine: MachineChoice,
is_cross: bool,
use_linker_args: bool) -> T.Tuple[T.List[str], T.List[str]]:
"""
Returns a tuple of (compile_flags, link_flags) for the specified language
from the inherited environment
"""
if lang not in cflags_mapping:
return [], []
compile_flags = [] # type: T.List[str]
link_flags = [] # type: T.List[str]
env_compile_flags = get_env_var(for_machine, is_cross, cflags_mapping[lang])
if env_compile_flags is not None:
compile_flags += split_args(env_compile_flags)
# Link flags (same for all languages)
if lang in languages_using_ldflags:
link_flags += LinkerEnvVarsMixin.get_args_from_envvars(for_machine, is_cross)
if use_linker_args:
# When the compiler is used as a wrapper around the linker (such as
# with GCC and Clang), the compile flags can be needed while linking
# too. This is also what Autotools does. However, we don't want to do
# this when the linker is stand-alone such as with MSVC C/C++, etc.
link_flags = compile_flags + link_flags
# Pre-processor flags for certain languages
if lang in languages_using_cppflags:
env_preproc_flags = get_env_var(for_machine, is_cross, 'CPPFLAGS')
if env_preproc_flags is not None:
compile_flags += split_args(env_preproc_flags)
return compile_flags, link_flags
def get_global_options(lang: str, def get_global_options(lang: str,
comp: T.Type[Compiler], comp: T.Type[Compiler],
for_machine: MachineChoice, for_machine: MachineChoice,
is_cross: bool) -> 'KeyedOptionDictType': env: 'Environment') -> 'KeyedOptionDictType':
"""Retreive options that apply to all compilers for a given language.""" """Retreive options that apply to all compilers for a given language."""
description = 'Extra arguments passed to the {}'.format(lang) description = 'Extra arguments passed to the {}'.format(lang)
argkey = OptionKey('args', lang=lang, machine=for_machine) argkey = OptionKey('args', lang=lang, machine=for_machine)
largkey = argkey.evolve('link_args') largkey = argkey.evolve('link_args')
# We shouldn't need listify here, but until we have a separate
# linker-driver representation and can have that do the combine we have to
# do it htis way.
compile_args = mesonlib.listify(env.options.get(argkey, []))
link_args = mesonlib.listify(env.options.get(largkey, []))
if comp.INVOKES_LINKER:
link_args = compile_args + link_args
opts: 'KeyedOptionDictType' = { opts: 'KeyedOptionDictType' = {
argkey: coredata.UserArrayOption( argkey: coredata.UserArrayOption(
description + ' compiler', description + ' compiler',
[], split_args=True, user_input=True, allow_dups=True), compile_args, split_args=True, user_input=True, allow_dups=True),
largkey: coredata.UserArrayOption( largkey: coredata.UserArrayOption(
description + ' linker', description + ' linker',
[], split_args=True, user_input=True, allow_dups=True), link_args, split_args=True, user_input=True, allow_dups=True),
} }
# Get from env vars.
compile_args, link_args = get_args_from_envvars(
lang,
for_machine,
is_cross,
comp.INVOKES_LINKER)
opts[argkey].set_value(compile_args)
opts[largkey].set_value(link_args)
return opts return opts

@ -21,7 +21,6 @@ from .. import coredata
from .. import mlog from .. import mlog
from ..mesonlib import MesonException, MachineChoice, version_compare, OptionKey from ..mesonlib import MesonException, MachineChoice, version_compare, OptionKey
from ..linkers import LinkerEnvVarsMixin
from .compilers import ( from .compilers import (
gnu_winlibs, gnu_winlibs,
msvc_winlibs, msvc_winlibs,
@ -256,7 +255,7 @@ class AppleClangCPPCompiler(ClangCPPCompiler):
return ['-lc++'] return ['-lc++']
class EmscriptenCPPCompiler(EmscriptenMixin, LinkerEnvVarsMixin, ClangCPPCompiler): class EmscriptenCPPCompiler(EmscriptenMixin, ClangCPPCompiler):
def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool,
info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None,
linker: T.Optional['DynamicLinker'] = None, linker: T.Optional['DynamicLinker'] = None,

@ -759,7 +759,7 @@ class CoreData:
for_machine: MachineChoice, env: 'Environment') -> None: for_machine: MachineChoice, env: 'Environment') -> None:
"""Add global language arguments that are needed before compiler/linker detection.""" """Add global language arguments that are needed before compiler/linker detection."""
from .compilers import compilers from .compilers import compilers
options = compilers.get_global_options(lang, comp, for_machine, env.is_cross_build()) options = compilers.get_global_options(lang, comp, for_machine, env)
self.add_compiler_options(options, lang, for_machine, env) self.add_compiler_options(options, lang, for_machine, env)
def process_new_compiler(self, lang: str, comp: 'Compiler', env: 'Environment') -> None: def process_new_compiler(self, lang: str, comp: 'Compiler', env: 'Environment') -> None:

@ -32,7 +32,6 @@ from pathlib import Path, PurePath
from .. import mlog from .. import mlog
from .. import mesonlib from .. import mesonlib
from ..compilers import clib_langs from ..compilers import clib_langs
from ..envconfig import get_env_var
from ..environment import Environment, MachineInfo from ..environment import Environment, MachineInfo
from ..cmake import CMakeExecutor, CMakeTraceParser, CMakeException, CMakeToolchain, CMakeExecScope, check_cmake_args from ..cmake import CMakeExecutor, CMakeTraceParser, CMakeException, CMakeToolchain, CMakeExecScope, check_cmake_args
from ..mesonlib import MachineChoice, MesonException, OrderedSet, PerMachine from ..mesonlib import MachineChoice, MesonException, OrderedSet, PerMachine
@ -317,7 +316,7 @@ class HasNativeKwarg:
return MachineChoice.BUILD if kwargs.get('native', False) else MachineChoice.HOST return MachineChoice.BUILD if kwargs.get('native', False) else MachineChoice.HOST
class ExternalDependency(Dependency, HasNativeKwarg): class ExternalDependency(Dependency, HasNativeKwarg):
def __init__(self, type_name, environment, kwargs, language: T.Optional[str] = None): def __init__(self, type_name, environment: Environment, kwargs, language: T.Optional[str] = None):
Dependency.__init__(self, type_name, kwargs) Dependency.__init__(self, type_name, kwargs)
self.env = environment self.env = environment
self.name = type_name # default self.name = type_name # default
@ -784,14 +783,7 @@ class PkgConfigDependency(ExternalDependency):
# #
# Only prefix_libpaths are reordered here because there should not be # Only prefix_libpaths are reordered here because there should not be
# too many system_libpaths to cause library version issues. # too many system_libpaths to cause library version issues.
pkg_config_path = get_env_var( pkg_config_path: T.List[str] = self.env.coredata.options[OptionKey('pkg_config_path', machine=self.for_machine)].value
self.for_machine,
self.env.is_cross_build(),
'PKG_CONFIG_PATH')
if pkg_config_path:
pkg_config_path = pkg_config_path.split(os.pathsep)
else:
pkg_config_path = []
pkg_config_path = self._convert_mingw_paths(pkg_config_path) pkg_config_path = self._convert_mingw_paths(pkg_config_path)
prefix_libpaths = sort_libpaths(prefix_libpaths, pkg_config_path) prefix_libpaths = sort_libpaths(prefix_libpaths, pkg_config_path)
system_libpaths = OrderedSet() system_libpaths = OrderedSet()

@ -20,12 +20,14 @@ from pathlib import Path
from .. import mlog from .. import mlog
from .. import mesonlib from .. import mesonlib
from ..envconfig import get_env_var
from ..environment import Environment from ..environment import Environment
from .base import DependencyException, ExternalDependency, PkgConfigDependency from .base import DependencyException, ExternalDependency, PkgConfigDependency
from .misc import threads_factory from .misc import threads_factory
if T.TYPE_CHECKING:
from ..environment import Properties
# On windows 3 directory layouts are supported: # On windows 3 directory layouts are supported:
# * The default layout (versioned) installed: # * The default layout (versioned) installed:
# - $BOOST_ROOT/include/boost-x_x/boost/*.hpp # - $BOOST_ROOT/include/boost-x_x/boost/*.hpp
@ -372,18 +374,11 @@ class BoostDependency(ExternalDependency):
# First, look for paths specified in a machine file # First, look for paths specified in a machine file
props = self.env.properties[self.for_machine] props = self.env.properties[self.for_machine]
boost_property_env = [props.get('boost_includedir'), props.get('boost_librarydir'), props.get('boost_root')] if any(x in self.env.properties[self.for_machine] for x in
if any(boost_property_env): ['boost_includedir', 'boost_librarydir', 'boost_root']):
self.detect_boost_machine_file(props) self.detect_boost_machine_file(props)
return return
# Next, look for paths in the environment
boost_manual_env_list = ['BOOST_INCLUDEDIR', 'BOOST_LIBRARYDIR', 'BOOST_ROOT', 'BOOSTROOT']
boost_manual_env = [get_env_var(self.for_machine, self.env.is_cross_build, x) for x in boost_manual_env_list]
if any(boost_manual_env):
self.detect_boost_env()
return
# Finally, look for paths from .pc files and from searching the filesystem # Finally, look for paths from .pc files and from searching the filesystem
self.detect_roots() self.detect_roots()
@ -405,13 +400,20 @@ class BoostDependency(ExternalDependency):
self.boost_root = j self.boost_root = j
break break
def detect_boost_machine_file(self, props: T.Dict[str, str]) -> None: def detect_boost_machine_file(self, props: 'Properties') -> None:
"""Detect boost with values in the machine file or environment.
The machine file values are defaulted to the environment values.
"""
# XXX: if we had a TypedDict we woudn't need this
incdir = props.get('boost_includedir') incdir = props.get('boost_includedir')
assert incdir is None or isinstance(incdir, str)
libdir = props.get('boost_librarydir') libdir = props.get('boost_librarydir')
assert libdir is None or isinstance(libdir, str)
if incdir and libdir: if incdir and libdir:
inc_dir = Path(props['boost_includedir']) inc_dir = Path(incdir)
lib_dir = Path(props['boost_librarydir']) lib_dir = Path(libdir)
if not inc_dir.is_absolute() or not lib_dir.is_absolute(): if not inc_dir.is_absolute() or not lib_dir.is_absolute():
raise DependencyException('Paths given for boost_includedir and boost_librarydir in machine file must be absolute') raise DependencyException('Paths given for boost_includedir and boost_librarydir in machine file must be absolute')
@ -436,43 +438,6 @@ class BoostDependency(ExternalDependency):
self.check_and_set_roots(paths) self.check_and_set_roots(paths)
def detect_boost_env(self) -> None:
boost_includedir = get_env_var(self.for_machine, self.env.is_cross_build, 'BOOST_INCLUDEDIR')
boost_librarydir = get_env_var(self.for_machine, self.env.is_cross_build, 'BOOST_LIBRARYDIR')
boost_manual_env = [boost_includedir, boost_librarydir]
if all(boost_manual_env):
inc_dir = Path(boost_includedir)
lib_dir = Path(boost_librarydir)
if not inc_dir.is_absolute() or not lib_dir.is_absolute():
raise DependencyException('Paths given in BOOST_INCLUDEDIR and BOOST_LIBRARYDIR must be absolute')
mlog.debug('Trying to find boost with:')
mlog.debug(' - BOOST_INCLUDEDIR = {}'.format(inc_dir))
mlog.debug(' - BOOST_LIBRARYDIR = {}'.format(lib_dir))
return self.detect_split_root(inc_dir, lib_dir)
elif any(boost_manual_env):
raise DependencyException('Both BOOST_INCLUDEDIR *and* BOOST_LIBRARYDIR have to be set (one is not enough). Ignoring.')
boost_root = get_env_var(self.for_machine, self.env.is_cross_build, 'BOOST_ROOT')
boostroot = get_env_var(self.for_machine, self.env.is_cross_build, 'BOOSTROOT')
# It shouldn't be possible to get here without something in BOOST_ROOT or BOOSTROOT
assert(boost_root or boostroot)
for path, name in [(boost_root, 'BOOST_ROOT'), (boostroot, 'BOOSTROOT')]:
if path:
raw_paths = path.split(os.pathsep)
paths = [Path(x) for x in raw_paths]
if paths and any([not x.is_absolute() for x in paths]):
raise DependencyException('Paths in {} must be absolute'.format(name))
break
self.check_and_set_roots(paths)
def run_check(self, inc_dirs: T.List[BoostIncludeDir], lib_dirs: T.List[Path]) -> bool: def run_check(self, inc_dirs: T.List[BoostIncludeDir], lib_dirs: T.List[Path]) -> bool:
mlog.debug(' - potential library dirs: {}'.format([x.as_posix() for x in lib_dirs])) mlog.debug(' - potential library dirs: {}'.format([x.as_posix() for x in lib_dirs]))
mlog.debug(' - potential include dirs: {}'.format([x.path.as_posix() for x in inc_dirs])) mlog.debug(' - potential include dirs: {}'.format([x.path.as_posix() for x in inc_dirs]))

@ -30,8 +30,8 @@ import typing as T
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
from .base import Dependency from .base import Dependency
from ..envconfig import MachineChoice
from ..environment import Environment from ..environment import Environment
from ..mesonlib import MachineChoice
class HDF5PkgConfigDependency(PkgConfigDependency): class HDF5PkgConfigDependency(PkgConfigDependency):

@ -106,7 +106,7 @@ class _MPIConfigToolDependency(ConfigToolDependency):
Drop -O2 and everything that is not needed. Drop -O2 and everything that is not needed.
""" """
result = [] result = []
multi_args = ('-I', ) multi_args: T.Tuple[str, ...] = ('-I', )
if self.language == 'fortran': if self.language == 'fortran':
fc = self.env.coredata.compilers[self.for_machine]['fortran'] fc = self.env.coredata.compilers[self.for_machine]['fortran']
multi_args += fc.get_module_incdir_args() multi_args += fc.get_module_incdir_args()

@ -12,17 +12,15 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import os, subprocess import subprocess
import typing as T import typing as T
from enum import Enum from enum import Enum
from . import mesonlib from . import mesonlib
from .mesonlib import EnvironmentException, MachineChoice, PerMachine, split_args from .mesonlib import EnvironmentException
from . import mlog from . import mlog
from pathlib import Path from pathlib import Path
_T = T.TypeVar('_T')
# These classes contains all the data pulled from configuration files (native # These classes contains all the data pulled from configuration files (native
# and cross file currently), and also assists with the reading environment # and cross file currently), and also assists with the reading environment
@ -85,46 +83,54 @@ CPU_FAMILES_64_BIT = [
'x86_64', 'x86_64',
] ]
# Map from language identifiers to environment variables.
ENV_VAR_PROG_MAP: T.Mapping[str, str] = {
# Compilers
'c': 'CC',
'cpp': 'CXX',
'cs': 'CSC',
'd': 'DC',
'fortran': 'FC',
'objc': 'OBJC',
'objcpp': 'OBJCXX',
'rust': 'RUSTC',
'vala': 'VALAC',
# Linkers
'c_ld': 'CC_LD',
'cpp_ld': 'CXX_LD',
'd_ld': 'DC_LD',
'fortran_ld': 'FC_LD',
'objc_ld': 'OBJC_LD',
'objcpp_ld': 'OBJCXX_LD',
'rust_ld': 'RUSTC_LD',
# Binutils
'strip': 'STRIP',
'ar': 'AR',
'windres': 'WINDRES',
# Other tools
'cmake': 'CMAKE',
'qmake': 'QMAKE',
'pkgconfig': 'PKG_CONFIG',
'make': 'MAKE',
}
# Deprecated environment variables mapped from the new variable to the old one
# Deprecated in 0.54.0
DEPRECATED_ENV_PROG_MAP: T.Mapping[str, str] = {
'd_ld': 'D_LD',
'fortran_ld': 'F_LD',
'rust_ld': 'RUST_LD',
'objcpp_ld': 'OBJCPP_LD',
}
class CMakeSkipCompilerTest(Enum): class CMakeSkipCompilerTest(Enum):
ALWAYS = 'always' ALWAYS = 'always'
NEVER = 'never' NEVER = 'never'
DEP_ONLY = 'dep_only' DEP_ONLY = 'dep_only'
def get_env_var_pair(for_machine: MachineChoice,
is_cross: bool,
var_name: str) -> T.Optional[T.Tuple[str, 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 verions
[var_name]
)[for_machine]
for var in candidates:
value = os.environ.get(var)
if value is not None:
break
else:
formatted = ', '.join(['{!r}'.format(var) for var in candidates])
mlog.debug('None of {} are defined in the environment, not changing global flags.'.format(formatted))
return None
mlog.debug('Using {!r} from environment with value: {!r}'.format(var, value))
return var, value
def get_env_var(for_machine: MachineChoice,
is_cross: bool,
var_name: str) -> T.Optional[str]:
ret = get_env_var_pair(for_machine, is_cross, var_name)
if ret is None:
return None
return ret[1]
class Properties: class Properties:
def __init__( def __init__(
self, self,
@ -351,60 +357,18 @@ class MachineInfo:
return self.is_windows() or self.is_cygwin() return self.is_windows() or self.is_cygwin()
class BinaryTable: class BinaryTable:
def __init__( def __init__(
self, self,
binaries: T.Optional[T.Dict[str, T.Union[str, T.List[str]]]] = None, binaries: T.Optional[T.Dict[str, T.Union[str, T.List[str]]]] = None,
): ):
self.binaries = binaries or {} # type: T.Dict[str, T.Union[str, T.List[str]]] self.binaries: T.Dict[str, T.List[str]] = {}
for name, command in self.binaries.items(): if binaries:
for name, command in binaries.items():
if not isinstance(command, (list, str)): if not isinstance(command, (list, str)):
# TODO generalize message
raise mesonlib.MesonException( raise mesonlib.MesonException(
'Invalid type {!r} for binary {!r} in cross file' f'Invalid type {command!r} for entry {name!r} in cross file')
''.format(command, name)) self.binaries[name] = mesonlib.listify(command)
# Map from language identifiers to environment variables.
evarMap = {
# Compilers
'c': 'CC',
'cpp': 'CXX',
'cs': 'CSC',
'd': 'DC',
'fortran': 'FC',
'objc': 'OBJC',
'objcpp': 'OBJCXX',
'rust': 'RUSTC',
'vala': 'VALAC',
# Linkers
'c_ld': 'CC_LD',
'cpp_ld': 'CXX_LD',
'd_ld': 'DC_LD',
'fortran_ld': 'FC_LD',
'objc_ld': 'OBJC_LD',
'objcpp_ld': 'OBJCXX_LD',
'rust_ld': 'RUSTC_LD',
# Binutils
'strip': 'STRIP',
'ar': 'AR',
'windres': 'WINDRES',
# Other tools
'cmake': 'CMAKE',
'qmake': 'QMAKE',
'pkgconfig': 'PKG_CONFIG',
'make': 'MAKE',
} # type: T.Dict[str, str]
# Deprecated environment variables mapped from the new variable to the old one
# Deprecated in 0.54.0
DEPRECATION_MAP = {
'DC_LD': 'D_LD',
'FC_LD': 'F_LD',
'RUSTC_LD': 'RUST_LD',
'OBJCXX_LD': 'OBJCPP_LD',
} # type: T.Dict[str, str]
@staticmethod @staticmethod
def detect_ccache() -> T.List[str]: def detect_ccache() -> T.List[str]:
@ -426,42 +390,17 @@ class BinaryTable:
# Return value has to be a list of compiler 'choices' # Return value has to be a list of compiler 'choices'
return compiler, ccache return compiler, ccache
def lookup_entry(self, def lookup_entry(self, name: str) -> T.Optional[T.List[str]]:
for_machine: MachineChoice,
is_cross: bool,
name: str) -> T.Optional[T.List[str]]:
"""Lookup binary in cross/native file and fallback to environment. """Lookup binary in cross/native file and fallback to environment.
Returns command with args as list if found, Returns `None` if nothing is Returns command with args as list if found, Returns `None` if nothing is
found. found.
""" """
# Try explicit map, don't fall back on env var command = self.binaries.get(name)
# Try explict map, then env vars if not command:
for _ in [()]: # a trick to get `break` return None
raw_command = self.binaries.get(name) elif not command[0].strip():
if raw_command is not None: return None
command = mesonlib.stringlistify(raw_command)
break # found
evar = self.evarMap.get(name)
if evar is not None:
raw_command = get_env_var(for_machine, is_cross, evar)
if raw_command is None:
deprecated = self.DEPRECATION_MAP.get(evar)
if deprecated is not None:
raw_command = get_env_var(for_machine, is_cross, deprecated)
if raw_command is not None:
mlog.deprecation(
'The', deprecated, 'environment variable is deprecated in favor of',
evar, once=True)
if raw_command is not None:
command = split_args(raw_command)
break # found
command = None
# Do not return empty or blank string entries
if command is not None and (len(command) == 0 or len(command[0].strip()) == 0):
command = None
return command return command
class CMakeVariables: class CMakeVariables:

@ -1,4 +1,4 @@
# Copyright 2012-2016 The Meson development team # Copyright 2012-2020 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import itertools
import os, platform, re, sys, shutil, subprocess import os, platform, re, sys, shutil, subprocess
import tempfile import tempfile
import shlex import shlex
@ -22,15 +23,13 @@ from . import coredata
from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, DLinker, CcrxLinker, Xc16Linker, CompCertLinker, C2000Linker, IntelVisualStudioLinker, AIXArLinker from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, DLinker, CcrxLinker, Xc16Linker, CompCertLinker, C2000Linker, IntelVisualStudioLinker, AIXArLinker
from . import mesonlib from . import mesonlib
from .mesonlib import ( from .mesonlib import (
MesonException, EnvironmentException, MachineChoice, Popen_safe, MesonException, EnvironmentException, MachineChoice, Popen_safe, PerMachine,
PerMachineDefaultable, PerThreeMachineDefaultable, split_args, quote_arg, OptionKey PerMachineDefaultable, PerThreeMachineDefaultable, split_args, quote_arg, OptionKey
) )
from . import mlog from . import mlog
from .envconfig import ( from .envconfig import (
BinaryTable, MachineInfo, BinaryTable, MachineInfo, Properties, known_cpu_families, CMakeVariables,
Properties, known_cpu_families, get_env_var_pair,
CMakeVariables,
) )
from . import compilers from . import compilers
from .compilers import ( from .compilers import (
@ -128,6 +127,7 @@ from .compilers import (
VisualStudioCCompiler, VisualStudioCCompiler,
VisualStudioCPPCompiler, VisualStudioCPPCompiler,
) )
from mesonbuild import envconfig
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
from configparser import ConfigParser from configparser import ConfigParser
@ -141,6 +141,32 @@ CompilersDict = T.Dict[str, Compiler]
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
import argparse import argparse
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 verions
[var_name]
)[for_machine]
for var in candidates:
value = os.environ.get(var)
if value is not None:
break
else:
formatted = ', '.join(['{!r}'.format(var) for var in candidates])
mlog.debug('None of {} are defined in the environment, not changing global flags.'.format(formatted))
return None
mlog.debug('Using {!r} from environment with value: {!r}'.format(var, value))
return value
def detect_gcovr(min_version='3.3', new_rootdir_version='4.2', log=False): def detect_gcovr(min_version='3.3', new_rootdir_version='4.2', log=False):
gcovr_exe = 'gcovr' gcovr_exe = 'gcovr'
try: try:
@ -579,7 +605,7 @@ class Environment:
# Stores machine infos, the only *three* machine one because we have a # 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 info on for the user (Meson never cares about the
# target machine.) # target machine.)
machines = PerThreeMachineDefaultable() # type: PerMachineDefaultable[MachineInfo] machines: PerThreeMachineDefaultable[MachineInfo] = PerThreeMachineDefaultable()
# Similar to coredata.compilers, but lower level in that there is no # Similar to coredata.compilers, but lower level in that there is no
# meta data, only names/paths. # meta data, only names/paths.
@ -605,7 +631,7 @@ class Environment:
# #
# Note that order matters because of 'buildtype', if it is after # Note that order matters because of 'buildtype', if it is after
# 'optimization' and 'debug' keys, it override them. # 'optimization' and 'debug' keys, it override them.
self.options: T.MutableMapping[OptionKey, str] = collections.OrderedDict() self.options: T.MutableMapping[OptionKey, T.Union[str, T.List[str]]] = collections.OrderedDict()
## Read in native file(s) to override build machine configuration ## Read in native file(s) to override build machine configuration
@ -614,7 +640,7 @@ class Environment:
binaries.build = BinaryTable(config.get('binaries', {})) binaries.build = BinaryTable(config.get('binaries', {}))
properties.build = Properties(config.get('properties', {})) properties.build = Properties(config.get('properties', {}))
cmakevars.build = CMakeVariables(config.get('cmake', {})) cmakevars.build = CMakeVariables(config.get('cmake', {}))
self.load_machine_file_options(config, properties.build, MachineChoice.BUILD) self._load_machine_file_options(config, properties.build, MachineChoice.BUILD)
## Read in cross file(s) to override host machine configuration ## Read in cross file(s) to override host machine configuration
@ -632,7 +658,7 @@ class Environment:
for key, value in list(self.options.items()): for key, value in list(self.options.items()):
if self.coredata.is_per_machine_option(key): if self.coredata.is_per_machine_option(key):
self.options[key.as_build()] = value self.options[key.as_build()] = value
self.load_machine_file_options(config, properties.host, MachineChoice.HOST) self._load_machine_file_options(config, properties.host, MachineChoice.HOST)
else: else:
# IF we aren't cross compiling, but we hav ea native file, the # IF we aren't cross compiling, but we hav ea native file, the
# native file is for the host. This is due to an mismatch between # native file is for the host. This is due to an mismatch between
@ -652,7 +678,9 @@ class Environment:
self.options.update(options.cmd_line_options) self.options.update(options.cmd_line_options)
# Take default value from env if not set in cross/native files or command line. # Take default value from env if not set in cross/native files or command line.
self.set_default_options_from_env() 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 # Warn if the user is using two different ways of setting build-type
# options that override each other # options that override each other
@ -718,7 +746,7 @@ class Environment:
self.default_pkgconfig = ['pkg-config'] self.default_pkgconfig = ['pkg-config']
self.wrap_resolver = None self.wrap_resolver = None
def load_machine_file_options(self, config: 'ConfigParser', properties: Properties, machine: MachineChoice) -> None: def _load_machine_file_options(self, config: 'ConfigParser', properties: Properties, machine: MachineChoice) -> None:
"""Read the contents of a Machine file and put it in the options store.""" """Read the contents of a Machine file and put it in the options store."""
paths = config.get('paths') paths = config.get('paths')
if paths: if paths:
@ -749,23 +777,90 @@ class Environment:
key = OptionKey.from_string(k).evolve(subproject=subproject) key = OptionKey.from_string(k).evolve(subproject=subproject)
self.options[key] = v self.options[key] = v
def set_default_options_from_env(self) -> None: def _set_default_options_from_env(self) -> None:
for for_machine in MachineChoice: opts: T.List[T.Tuple[str, str]] = (
for evar, keyname in [('PKG_CONFIG_PATH', 'pkg_config_path')]: [(v, f'{k}_args') for k, v in compilers.compilers.CFLAGS_MAPPING.items()] +
p_env_pair = get_env_var_pair(for_machine, self.is_cross_build(), evar) [
if p_env_pair is not None: ('PKG_CONFIG_PATH', 'pkg_config_path'),
_, p_env = p_env_pair ('CMAKE_PREFIX_PATH', 'cmake_prefix_path'),
('LDFLAGS', 'ldflags'),
('CPPFLAGS', 'cppflags'),
]
)
# PKG_CONFIG_PATH may contain duplicates, which must be for (evar, keyname), for_machine in itertools.product(opts, MachineChoice):
# removed, else a duplicates-in-array-option warning arises. 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(':'))) p_list = list(mesonlib.OrderedSet(p_env.split(':')))
else:
p_list = split_args(p_env)
p_list = [e for e in p_list if e] # filter out any empty eelemnts
# Take env vars only on first invocation, if the env changes when # Take env vars only on first invocation, if the env changes when
# reconfiguring it gets ignored. # reconfiguring it gets ignored.
# FIXME: We should remember if we took the value from env to warn # FIXME: We should remember if we took the value from env to warn
# if it changes on future invocations. # if it changes on future invocations.
if self.first_invocation: if self.first_invocation:
key = OptionKey(keyname, machine=for_machine) if keyname == 'ldflags':
self.options.setdefault(key, p_list) key = OptionKey('link_args', machine=for_machine, lang='c') # needs a language to initialize properly
for lang in compilers.compilers.LANGUAGES_USING_LDFLAGS:
key = key.evolve(lang=lang)
v = mesonlib.listify(self.options.get(key, []))
self.options.setdefault(key, v + p_list)
elif keyname == 'cppflags':
key = OptionKey('args', machine=for_machine, lang='c')
for lang in compilers.compilers.LANGUAGES_USING_CPPFLAGS:
key = key.evolve(lang=lang)
v = mesonlib.listify(self.options.get(key, []))
self.options.setdefault(key, v + p_list)
else:
key = OptionKey.from_string(keyname).evolve(machine=for_machine)
v = mesonlib.listify(self.options.get(key, []))
self.options.setdefault(key, v + p_list)
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:
self.binaries[for_machine].binaries.setdefault(name, mesonlib.split_args(p_env))
def _set_default_properties_from_env(self) -> None:
"""Properties which can alkso 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),
]
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: 'argparse.Namespace') -> None: def create_new_coredata(self, options: 'argparse.Namespace') -> None:
# WARNING: Don't use any values from coredata in __init__. It gets # WARNING: Don't use any values from coredata in __init__. It gets
@ -816,11 +911,8 @@ class Environment:
def is_library(self, fname): def is_library(self, fname):
return is_library(fname) return is_library(fname)
def lookup_binary_entry(self, for_machine: MachineChoice, name: str): def lookup_binary_entry(self, for_machine: MachineChoice, name: str) -> T.List[str]:
return self.binaries[for_machine].lookup_entry( return self.binaries[for_machine].lookup_entry(name)
for_machine,
self.is_cross_build(),
name)
@staticmethod @staticmethod
def get_gnu_compiler_defines(compiler): def get_gnu_compiler_defines(compiler):

@ -18,12 +18,11 @@ import typing as T
from . import mesonlib from . import mesonlib
from .arglist import CompilerArgs from .arglist import CompilerArgs
from .envconfig import get_env_var
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
from .coredata import KeyedOptionDictType from .coredata import KeyedOptionDictType
from .envconfig import MachineChoice
from .environment import Environment from .environment import Environment
from .mesonlib import MachineChoice
class StaticLinker: class StaticLinker:
@ -301,21 +300,7 @@ def evaluate_rpath(p: str, build_dir: str, from_dir: str) -> str:
else: else:
return os.path.relpath(os.path.join(build_dir, p), os.path.join(build_dir, from_dir)) return os.path.relpath(os.path.join(build_dir, p), os.path.join(build_dir, from_dir))
class DynamicLinker(metaclass=abc.ABCMeta):
class LinkerEnvVarsMixin(metaclass=abc.ABCMeta):
"""Mixin reading LDFLAGS from the environment."""
@staticmethod
def get_args_from_envvars(for_machine: mesonlib.MachineChoice,
is_cross: bool) -> T.List[str]:
raw_value = get_env_var(for_machine, is_cross, 'LDFLAGS')
if raw_value is not None:
return mesonlib.split_args(raw_value)
else:
return []
class DynamicLinker(LinkerEnvVarsMixin, metaclass=abc.ABCMeta):
"""Base class for dynamic linkers.""" """Base class for dynamic linkers."""

@ -23,7 +23,7 @@ from ..mesonlib import (MesonException, Popen_safe, MachineChoice,
from ..interpreterbase import InterpreterObject, InterpreterException, FeatureNew from ..interpreterbase import InterpreterObject, InterpreterException, FeatureNew
from ..interpreterbase import stringArgs, permittedKwargs from ..interpreterbase import stringArgs, permittedKwargs
from ..interpreter import Interpreter, DependencyHolder, InstallDir from ..interpreter import Interpreter, DependencyHolder, InstallDir
from ..compilers.compilers import cflags_mapping, cexe_mapping from ..compilers.compilers import CFLAGS_MAPPING, CEXE_MAPPING
from ..dependencies.base import InternalDependency, PkgConfigDependency from ..dependencies.base import InternalDependency, PkgConfigDependency
from ..environment import Environment from ..environment import Environment
from ..mesonlib import OptionKey from ..mesonlib import OptionKey
@ -110,11 +110,11 @@ class ExternalProject(InterpreterObject):
link_args = [] link_args = []
self.run_env = os.environ.copy() self.run_env = os.environ.copy()
for lang, compiler in self.env.coredata.compilers[MachineChoice.HOST].items(): for lang, compiler in self.env.coredata.compilers[MachineChoice.HOST].items():
if any(lang not in i for i in (cexe_mapping, cflags_mapping)): if any(lang not in i for i in (CEXE_MAPPING, CFLAGS_MAPPING)):
continue continue
cargs = self.env.coredata.get_external_args(MachineChoice.HOST, lang) cargs = self.env.coredata.get_external_args(MachineChoice.HOST, lang)
self.run_env[cexe_mapping[lang]] = self._quote_and_join(compiler.get_exelist()) self.run_env[CEXE_MAPPING[lang]] = self._quote_and_join(compiler.get_exelist())
self.run_env[cflags_mapping[lang]] = self._quote_and_join(cargs) self.run_env[CFLAGS_MAPPING[lang]] = self._quote_and_join(cargs)
if not link_exelist: if not link_exelist:
link_exelist = compiler.get_linker_exelist() link_exelist = compiler.get_linker_exelist()
link_args = self.env.coredata.get_external_link_args(MachineChoice.HOST, lang) link_args = self.env.coredata.get_external_link_args(MachineChoice.HOST, lang)

@ -2606,8 +2606,10 @@ class AllPlatformTests(BasePlatformTests):
if is_osx(): if is_osx():
self.assertIsInstance(cc.linker, mesonbuild.linkers.AppleDynamicLinker) self.assertIsInstance(cc.linker, mesonbuild.linkers.AppleDynamicLinker)
elif is_windows(): elif is_windows():
# This is clang, not clang-cl # This is clang, not clang-cl. This can be either an
self.assertIsInstance(cc.linker, mesonbuild.linkers.MSVCDynamicLinker) # ld-like linker of link.exe-like linker (usually the
# former for msys2, the latter otherwise)
self.assertIsInstance(cc.linker, (mesonbuild.linkers.MSVCDynamicLinker, mesonbuild.linkers.GnuLikeDynamicLinkerMixin))
else: else:
self.assertIsInstance(cc.linker, mesonbuild.linkers.GnuLikeDynamicLinkerMixin) self.assertIsInstance(cc.linker, mesonbuild.linkers.GnuLikeDynamicLinkerMixin)
if isinstance(cc, intel): if isinstance(cc, intel):
@ -2635,17 +2637,16 @@ class AllPlatformTests(BasePlatformTests):
# something like `ccache gcc -pipe` or `distcc ccache gcc` works. # something like `ccache gcc -pipe` or `distcc ccache gcc` works.
wrapper = os.path.join(testdir, 'compiler wrapper.py') wrapper = os.path.join(testdir, 'compiler wrapper.py')
wrappercc = python_command + [wrapper] + cc.get_exelist() + ['-DSOME_ARG'] wrappercc = python_command + [wrapper] + cc.get_exelist() + ['-DSOME_ARG']
wrappercc_s = '' os.environ[evar] = ' '.join(quote_arg(w) for w in wrappercc)
for w in wrappercc:
wrappercc_s += quote_arg(w) + ' '
os.environ[evar] = wrappercc_s
wcc = getattr(env, 'detect_{}_compiler'.format(lang))(MachineChoice.HOST)
# Check static linker too # Check static linker too
wrapperlinker = python_command + [wrapper] + linker.get_exelist() + linker.get_always_args() wrapperlinker = python_command + [wrapper] + linker.get_exelist() + linker.get_always_args()
wrapperlinker_s = '' os.environ['AR'] = ' '.join(quote_arg(w) for w in wrapperlinker)
for w in wrapperlinker:
wrapperlinker_s += quote_arg(w) + ' ' # Need a new env to re-run environment loading
os.environ['AR'] = wrapperlinker_s env = get_fake_env(testdir, self.builddir, self.prefix)
wcc = getattr(env, 'detect_{}_compiler'.format(lang))(MachineChoice.HOST)
wlinker = env.detect_static_linker(wcc) wlinker = env.detect_static_linker(wcc)
# Pop it so we don't use it for the next detection # Pop it so we don't use it for the next detection
evalue = os.environ.pop('AR') evalue = os.environ.pop('AR')
@ -5375,7 +5376,7 @@ class FailureTests(BasePlatformTests):
def test_boost_BOOST_ROOT_dependency(self): def test_boost_BOOST_ROOT_dependency(self):
# Test BOOST_ROOT; can be run even if Boost is found or not # Test BOOST_ROOT; can be run even if Boost is found or not
self.assertMesonRaises("dependency('boost')", self.assertMesonRaises("dependency('boost')",
"(BOOST_ROOT.*absolute|{})".format(self.dnf), "(boost_root.*absolute|{})".format(self.dnf),
override_envvars = {'BOOST_ROOT': 'relative/path'}) override_envvars = {'BOOST_ROOT': 'relative/path'})
def test_dependency_invalid_method(self): def test_dependency_invalid_method(self):
@ -5687,12 +5688,12 @@ class WindowsTests(BasePlatformTests):
def _check_ld(self, name: str, lang: str, expected: str) -> None: def _check_ld(self, name: str, lang: str, expected: str) -> None:
if not shutil.which(name): if not shutil.which(name):
raise unittest.SkipTest('Could not find {}.'.format(name)) raise unittest.SkipTest('Could not find {}.'.format(name))
envvars = [mesonbuild.envconfig.BinaryTable.evarMap['{}_ld'.format(lang)]] envvars = [mesonbuild.envconfig.ENV_VAR_PROG_MAP['{}_ld'.format(lang)]]
# Also test a deprecated variable if there is one. # Also test a deprecated variable if there is one.
if envvars[0] in mesonbuild.envconfig.BinaryTable.DEPRECATION_MAP: if f'{lang}_ld' in mesonbuild.envconfig.DEPRECATED_ENV_PROG_MAP:
envvars.append( envvars.append(
mesonbuild.envconfig.BinaryTable.DEPRECATION_MAP[envvars[0]]) mesonbuild.envconfig.DEPRECATED_ENV_PROG_MAP[f'{lang}_ld'])
for envvar in envvars: for envvar in envvars:
with mock.patch.dict(os.environ, {envvar: name}): with mock.patch.dict(os.environ, {envvar: name}):
@ -7291,12 +7292,12 @@ class LinuxlikeTests(BasePlatformTests):
raise unittest.SkipTest('Solaris currently cannot override the linker.') raise unittest.SkipTest('Solaris currently cannot override the linker.')
if not shutil.which(check): if not shutil.which(check):
raise unittest.SkipTest('Could not find {}.'.format(check)) raise unittest.SkipTest('Could not find {}.'.format(check))
envvars = [mesonbuild.envconfig.BinaryTable.evarMap['{}_ld'.format(lang)]] envvars = [mesonbuild.envconfig.ENV_VAR_PROG_MAP['{}_ld'.format(lang)]]
# Also test a deprecated variable if there is one. # Also test a deprecated variable if there is one.
if envvars[0] in mesonbuild.envconfig.BinaryTable.DEPRECATION_MAP: if f'{lang}_ld' in mesonbuild.envconfig.DEPRECATED_ENV_PROG_MAP:
envvars.append( envvars.append(
mesonbuild.envconfig.BinaryTable.DEPRECATION_MAP[envvars[0]]) mesonbuild.envconfig.DEPRECATED_ENV_PROG_MAP[f'{lang}_ld'])
for envvar in envvars: for envvar in envvars:
with mock.patch.dict(os.environ, {envvar: name}): with mock.patch.dict(os.environ, {envvar: name}):
@ -8272,7 +8273,7 @@ class NativeFileTests(BasePlatformTests):
return 'gfortran', 'gcc' return 'gfortran', 'gcc'
self.helper_for_compiler('fortran', cb) self.helper_for_compiler('fortran', cb)
def _single_implementation_compiler(self, lang, binary, version_str, version): def _single_implementation_compiler(self, lang: str, binary: str, version_str: str, version: str) -> None:
"""Helper for languages with a single (supported) implementation. """Helper for languages with a single (supported) implementation.
Builds a wrapper around the compiler to override the version. Builds a wrapper around the compiler to override the version.
@ -8281,7 +8282,7 @@ class NativeFileTests(BasePlatformTests):
env = get_fake_env() env = get_fake_env()
getter = getattr(env, 'detect_{}_compiler'.format(lang)) getter = getattr(env, 'detect_{}_compiler'.format(lang))
getter = functools.partial(getter, MachineChoice.HOST) getter = functools.partial(getter, MachineChoice.HOST)
env.binaries.host.binaries[lang] = wrapper env.binaries.host.binaries[lang] = [wrapper]
compiler = getter() compiler = getter()
self.assertEqual(compiler.version, version) self.assertEqual(compiler.version, version)
@ -8308,7 +8309,7 @@ class NativeFileTests(BasePlatformTests):
'swiftc', version='Swift 1.2345', outfile='stderr', 'swiftc', version='Swift 1.2345', outfile='stderr',
extra_args={'Xlinker': 'macosx_version. PROJECT:ld - 1.2.3'}) extra_args={'Xlinker': 'macosx_version. PROJECT:ld - 1.2.3'})
env = get_fake_env() env = get_fake_env()
env.binaries.host.binaries['swift'] = wrapper env.binaries.host.binaries['swift'] = [wrapper]
compiler = env.detect_swift_compiler(MachineChoice.HOST) compiler = env.detect_swift_compiler(MachineChoice.HOST)
self.assertEqual(compiler.version, '1.2345') self.assertEqual(compiler.version, '1.2345')
@ -9345,7 +9346,7 @@ def unset_envs():
# For unit tests we must fully control all command lines # For unit tests we must fully control all command lines
# so that there are no unexpected changes coming from the # so that there are no unexpected changes coming from the
# environment, for example when doing a package build. # environment, for example when doing a package build.
varnames = ['CPPFLAGS', 'LDFLAGS'] + list(mesonbuild.compilers.compilers.cflags_mapping.values()) varnames = ['CPPFLAGS', 'LDFLAGS'] + list(mesonbuild.compilers.compilers.CFLAGS_MAPPING.values())
for v in varnames: for v in varnames:
if v in os.environ: if v in os.environ:
del os.environ[v] del os.environ[v]

Loading…
Cancel
Save