Split compiler detection from Environment

This moves all the compiler detection logic into the new
compilers.detect module. This dramatically reduces the size
and complexity of Environment.
pull/8933/head
Daniel Mensinger 4 years ago
parent 0f237b8d1d
commit 3f889606c7
  1. 3
      mesonbuild/ast/introspection.py
  2. 4
      mesonbuild/backend/backends.py
  3. 4
      mesonbuild/build.py
  4. 33
      mesonbuild/compilers/__init__.py
  5. 1209
      mesonbuild/compilers/detect.py
  6. 5
      mesonbuild/compilers/mixins/intel.py
  7. 4
      mesonbuild/dependencies/dev.py
  8. 1368
      mesonbuild/environment.py
  9. 2
      mesonbuild/interpreter/interpreter.py
  10. 11
      mesonbuild/linkers/__init__.py
  11. 216
      mesonbuild/linkers/detect.py
  12. 44
      mesonbuild/mesonlib/universal.py
  13. 9
      run_project_tests.py
  14. 156
      run_unittests.py

@ -23,6 +23,7 @@ from ..mesonlib import MachineChoice, OptionKey
from ..interpreterbase import InvalidArguments, TYPE_nvar from ..interpreterbase import InvalidArguments, TYPE_nvar
from ..build import BuildTarget, Executable, Jar, SharedLibrary, SharedModule, StaticLibrary from ..build import BuildTarget, Executable, Jar, SharedLibrary, SharedModule, StaticLibrary
from ..mparser import BaseNode, ArithmeticNode, ArrayNode, ElementaryNode, IdNode, FunctionNode, StringNode from ..mparser import BaseNode, ArithmeticNode, ArrayNode, ElementaryNode, IdNode, FunctionNode, StringNode
from ..compilers import detect_compiler_for
import typing as T import typing as T
import os import os
import argparse import argparse
@ -162,7 +163,7 @@ class IntrospectionInterpreter(AstInterpreter):
for lang in sorted(langs, key=compilers.sort_clink): for lang in sorted(langs, key=compilers.sort_clink):
lang = lang.lower() lang = lang.lower()
if lang not in self.coredata.compilers[for_machine]: if lang not in self.coredata.compilers[for_machine]:
self.environment.detect_compiler_for(lang, for_machine) detect_compiler_for(self.environment, lang, for_machine)
def func_dependency(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> None: def func_dependency(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> None:
args = self.flatten_args(args) args = self.flatten_args(args)

@ -29,7 +29,7 @@ from .. import dependencies
from .. import programs from .. import programs
from .. import mesonlib from .. import mesonlib
from .. import mlog from .. import mlog
from ..compilers import LANGUAGES_USING_LDFLAGS from ..compilers import LANGUAGES_USING_LDFLAGS, detect
from ..mesonlib import ( from ..mesonlib import (
File, MachineChoice, MesonException, OptionType, OrderedSet, OptionOverrideProxy, File, MachineChoice, MesonException, OptionType, OrderedSet, OptionOverrideProxy,
classify_unity_sources, OptionKey, join_args classify_unity_sources, OptionKey, join_args
@ -1315,7 +1315,7 @@ class Backend:
mlog.warning('Cross file does not specify strip binary, result will not be stripped.') mlog.warning('Cross file does not specify strip binary, result will not be stripped.')
else: else:
# TODO go through all candidates, like others # TODO go through all candidates, like others
strip_bin = [self.environment.default_strip[0]] strip_bin = [detect.defaults['strip'][0]]
d = InstallData(self.environment.get_source_dir(), d = InstallData(self.environment.get_source_dir(),
self.environment.get_build_dir(), self.environment.get_build_dir(),
self.environment.get_prefix(), self.environment.get_prefix(),

@ -37,7 +37,7 @@ from .mesonlib import (
) )
from .compilers import ( from .compilers import (
Compiler, is_object, clink_langs, sort_clink, lang_suffixes, Compiler, is_object, clink_langs, sort_clink, lang_suffixes,
is_known_suffix is_known_suffix, detect_static_linker
) )
from .linkers import StaticLinker from .linkers import StaticLinker
from .interpreterbase import FeatureNew from .interpreterbase import FeatureNew
@ -275,7 +275,7 @@ class Build:
def ensure_static_linker(self, compiler): def ensure_static_linker(self, compiler):
if self.static_linker[compiler.for_machine] is None and compiler.needs_static_linker(): if self.static_linker[compiler.for_machine] is None and compiler.needs_static_linker():
self.static_linker[compiler.for_machine] = self.environment.detect_static_linker(compiler) self.static_linker[compiler.for_machine] = detect_static_linker(self.environment, compiler)
def get_project(self): def get_project(self):
return self.projects[''] return self.projects['']

@ -35,6 +35,22 @@ __all__ = [
'lang_suffixes', 'lang_suffixes',
'sort_clink', 'sort_clink',
'compiler_from_language',
'detect_compiler_for',
'detect_static_linker',
'detect_c_compiler',
'detect_cpp_compiler',
'detect_cuda_compiler',
'detect_fortran_compiler',
'detect_objc_compiler',
'detect_objcpp_compiler',
'detect_java_compiler',
'detect_cs_compiler',
'detect_vala_compiler',
'detect_rust_compiler',
'detect_d_compiler',
'detect_swift_compiler',
'AppleClangCCompiler', 'AppleClangCCompiler',
'AppleClangCPPCompiler', 'AppleClangCPPCompiler',
'AppleClangObjCCompiler', 'AppleClangObjCCompiler',
@ -133,6 +149,23 @@ from .compilers import (
LANGUAGES_USING_LDFLAGS, LANGUAGES_USING_LDFLAGS,
sort_clink, sort_clink,
) )
from .detect import (
compiler_from_language,
detect_compiler_for,
detect_static_linker,
detect_c_compiler,
detect_cpp_compiler,
detect_cuda_compiler,
detect_objc_compiler,
detect_objcpp_compiler,
detect_fortran_compiler,
detect_java_compiler,
detect_cs_compiler,
detect_vala_compiler,
detect_rust_compiler,
detect_d_compiler,
detect_swift_compiler,
)
from .c import ( from .c import (
CCompiler, CCompiler,
AppleClangCCompiler, AppleClangCCompiler,

File diff suppressed because it is too large Load Diff

@ -168,14 +168,11 @@ class IntelVisualStudioLikeCompiler(VisualStudioLikeCompiler):
return args return args
def get_toolset_version(self) -> T.Optional[str]: def get_toolset_version(self) -> T.Optional[str]:
# Avoid circular dependencies....
from ...environment import search_version
# ICL provides a cl.exe that returns the version of MSVC it tries to # ICL provides a cl.exe that returns the version of MSVC it tries to
# emulate, so we'll get the version from that and pass it to the same # emulate, so we'll get the version from that and pass it to the same
# function the real MSVC uses to calculate the toolset version. # function the real MSVC uses to calculate the toolset version.
_, _, err = mesonlib.Popen_safe(['cl.exe']) _, _, err = mesonlib.Popen_safe(['cl.exe'])
v1, v2, *_ = search_version(err).split('.') v1, v2, *_ = mesonlib.search_version(err).split('.')
version = int(v1 + v2) version = int(v1 + v2)
return self._calculate_toolset_version(version) return self._calculate_toolset_version(version)

@ -23,7 +23,7 @@ import shutil
import typing as T import typing as T
from .. import mesonlib, mlog from .. import mesonlib, mlog
from ..compilers import AppleClangCCompiler, AppleClangCPPCompiler from ..compilers import AppleClangCCompiler, AppleClangCPPCompiler, detect_compiler_for
from ..environment import get_llvm_tool_names from ..environment import get_llvm_tool_names
from ..mesonlib import version_compare, stringlistify, extract_as_list, MachineChoice from ..mesonlib import version_compare, stringlistify, extract_as_list, MachineChoice
from .base import DependencyException, DependencyMethods, strip_system_libdirs, SystemDependency from .base import DependencyException, DependencyMethods, strip_system_libdirs, SystemDependency
@ -520,7 +520,7 @@ class JDKSystemDependency(SystemDependency):
m = self.env.machines[self.for_machine] m = self.env.machines[self.for_machine]
if 'java' not in environment.coredata.compilers[self.for_machine]: if 'java' not in environment.coredata.compilers[self.for_machine]:
environment.detect_compiler_for('java', self.for_machine) detect_compiler_for(environment, 'java', self.for_machine)
self.javac = environment.coredata.compilers[self.for_machine]['java'] self.javac = environment.coredata.compilers[self.for_machine]['java']
self.version = self.javac.version self.version = self.javac.version

File diff suppressed because it is too large Load Diff

@ -1328,7 +1328,7 @@ external dependencies (including libraries) must go to "dependencies".''')
comp = clist[lang] comp = clist[lang]
else: else:
try: try:
comp = self.environment.detect_compiler_for(lang, for_machine) comp = compilers.detect_compiler_for(self.environment, lang, for_machine)
if comp is None: if comp is None:
raise InvalidArguments('Tried to use unknown language "%s".' % lang) raise InvalidArguments('Tried to use unknown language "%s".' % lang)
if self.should_skip_sanity_check(for_machine): if self.should_skip_sanity_check(for_machine):

@ -12,6 +12,11 @@
# 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.
from .detect import (
defaults,
guess_win_linker,
guess_nix_linker,
)
from .linkers import ( from .linkers import (
RSPFileSyntax, RSPFileSyntax,
@ -64,6 +69,12 @@ from .linkers import (
) )
__all__ = [ __all__ = [
# detect.py
'defaults',
'guess_win_linker',
'guess_nix_linker',
# linkers.py
'RSPFileSyntax', 'RSPFileSyntax',
'StaticLinker', 'StaticLinker',

@ -0,0 +1,216 @@
# Copyright 2012-2021 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ..mesonlib import (
EnvironmentException, MachineChoice, OptionKey,
Popen_safe, search_version
)
from .linkers import (
DynamicLinker,
AppleDynamicLinker,
GnuDynamicLinker,
GnuGoldDynamicLinker,
GnuBFDDynamicLinker,
LLVMDynamicLinker,
QualcommLLVMDynamicLinker,
MSVCDynamicLinker,
ClangClDynamicLinker,
SolarisDynamicLinker,
AIXDynamicLinker,
OptlinkDynamicLinker,
)
import re
import shlex
import typing as T
if T.TYPE_CHECKING:
from ..environment import Environment
from ..compilers import Compiler
defaults: T.Dict[str, T.List[str]] = {}
defaults['static_linker'] = ['ar', 'gar']
defaults['vs_static_linker'] = ['lib']
defaults['clang_cl_static_linker'] = ['llvm-lib']
defaults['cuda_static_linker'] = ['nvlink']
defaults['gcc_static_linker'] = ['gcc-ar']
defaults['clang_static_linker'] = ['llvm-ar']
def __failed_to_detect_linker(compiler: T.List[str], args: T.List[str], stdout: str, stderr: str) -> 'T.NoReturn':
msg = 'Unable to detect linker for compiler "{} {}"\nstdout: {}\nstderr: {}'.format(
' '.join(compiler), ' '.join(args), stdout, stderr)
raise EnvironmentException(msg)
def guess_win_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Type['Compiler'],
for_machine: MachineChoice, *,
use_linker_prefix: bool = True, invoked_directly: bool = True,
extra_args: T.Optional[T.List[str]] = None) -> 'DynamicLinker':
env.coredata.add_lang_args(comp_class.language, comp_class, for_machine, env)
# Explicitly pass logo here so that we can get the version of link.exe
if not use_linker_prefix or comp_class.LINKER_PREFIX is None:
check_args = ['/logo', '--version']
elif isinstance(comp_class.LINKER_PREFIX, str):
check_args = [comp_class.LINKER_PREFIX + '/logo', comp_class.LINKER_PREFIX + '--version']
elif isinstance(comp_class.LINKER_PREFIX, list):
check_args = comp_class.LINKER_PREFIX + ['/logo'] + comp_class.LINKER_PREFIX + ['--version']
check_args += env.coredata.options[OptionKey('args', lang=comp_class.language, machine=for_machine)].value
override = [] # type: T.List[str]
value = env.lookup_binary_entry(for_machine, comp_class.language + '_ld')
if value is not None:
override = comp_class.use_linker_args(value[0])
check_args += override
if extra_args is not None:
check_args.extend(extra_args)
p, o, _ = Popen_safe(compiler + check_args)
if o.startswith('LLD'):
if '(compatible with GNU linkers)' in o:
return LLVMDynamicLinker(
compiler, for_machine, comp_class.LINKER_PREFIX,
override, version=search_version(o))
elif not invoked_directly:
return ClangClDynamicLinker(
for_machine, override, exelist=compiler, prefix=comp_class.LINKER_PREFIX,
version=search_version(o), direct=False, machine=None)
if value is not None and invoked_directly:
compiler = value
# We've already hanedled the non-direct case above
p, o, e = Popen_safe(compiler + check_args)
if o.startswith('LLD'):
return ClangClDynamicLinker(
for_machine, [],
prefix=comp_class.LINKER_PREFIX if use_linker_prefix else [],
exelist=compiler, version=search_version(o), direct=invoked_directly)
elif 'OPTLINK' in o:
# Opltink's stdout *may* beging with a \r character.
return OptlinkDynamicLinker(compiler, for_machine, version=search_version(o))
elif o.startswith('Microsoft') or e.startswith('Microsoft'):
out = o or e
match = re.search(r'.*(X86|X64|ARM|ARM64).*', out)
if match:
target = str(match.group(1))
else:
target = 'x86'
return MSVCDynamicLinker(
for_machine, [], machine=target, exelist=compiler,
prefix=comp_class.LINKER_PREFIX if use_linker_prefix else [],
version=search_version(out), direct=invoked_directly)
elif 'GNU coreutils' in o:
raise EnvironmentException(
"Found GNU link.exe instead of MSVC link.exe. This link.exe "
"is not a linker. You may need to reorder entries to your "
"%PATH% variable to resolve this.")
__failed_to_detect_linker(compiler, check_args, o, e)
def guess_nix_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Type['Compiler'],
for_machine: MachineChoice, *,
extra_args: T.Optional[T.List[str]] = None) -> 'DynamicLinker':
"""Helper for guessing what linker to use on Unix-Like OSes.
:compiler: Invocation to use to get linker
:comp_class: The Compiler Type (uninstantiated)
:for_machine: which machine this linker targets
:extra_args: Any additional arguments required (such as a source file)
"""
env.coredata.add_lang_args(comp_class.language, comp_class, for_machine, env)
extra_args = extra_args or []
extra_args += env.coredata.options[OptionKey('args', lang=comp_class.language, machine=for_machine)].value
if isinstance(comp_class.LINKER_PREFIX, str):
check_args = [comp_class.LINKER_PREFIX + '--version'] + extra_args
else:
check_args = comp_class.LINKER_PREFIX + ['--version'] + extra_args
override = [] # type: T.List[str]
value = env.lookup_binary_entry(for_machine, comp_class.language + '_ld')
if value is not None:
override = comp_class.use_linker_args(value[0])
check_args += override
_, o, e = Popen_safe(compiler + check_args)
v = search_version(o + e)
linker: DynamicLinker
if o.startswith('LLD'):
linker = LLVMDynamicLinker(
compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v)
elif 'Snapdragon' in e and 'LLVM' in e:
linker = QualcommLLVMDynamicLinker(
compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v)
elif e.startswith('lld-link: '):
# The LLD MinGW frontend didn't respond to --version before version 9.0.0,
# and produced an error message about failing to link (when no object
# files were specified), instead of printing the version number.
# Let's try to extract the linker invocation command to grab the version.
_, o, e = Popen_safe(compiler + check_args + ['-v'])
try:
linker_cmd = re.match(r'.*\n(.*?)\nlld-link: ', e, re.DOTALL).group(1)
linker_cmd = shlex.split(linker_cmd)[0]
except (AttributeError, IndexError, ValueError):
pass
else:
_, o, e = Popen_safe([linker_cmd, '--version'])
v = search_version(o)
linker = LLVMDynamicLinker(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v)
# first is for apple clang, second is for real gcc, the third is icc
elif e.endswith('(use -v to see invocation)\n') or 'macosx_version' in e or 'ld: unknown option:' in e:
if isinstance(comp_class.LINKER_PREFIX, str):
_, _, e = Popen_safe(compiler + [comp_class.LINKER_PREFIX + '-v'] + extra_args)
else:
_, _, e = Popen_safe(compiler + comp_class.LINKER_PREFIX + ['-v'] + extra_args)
for line in e.split('\n'):
if 'PROJECT:ld' in line:
v = line.split('-')[1]
break
else:
v = 'unknown version'
linker = AppleDynamicLinker(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v)
elif 'GNU' in o or 'GNU' in e:
cls: T.Type[GnuDynamicLinker]
if 'gold' in o or 'gold' in e:
cls = GnuGoldDynamicLinker
else:
cls = GnuBFDDynamicLinker
linker = cls(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v)
elif 'Solaris' in e or 'Solaris' in o:
for line in (o+e).split('\n'):
if 'ld: Software Generation Utilities' in line:
v = line.split(':')[2].lstrip()
break
else:
v = 'unknown version'
linker = SolarisDynamicLinker(
compiler, for_machine, comp_class.LINKER_PREFIX, override,
version=v)
elif 'ld: 0706-012 The -- flag is not recognized' in e:
if isinstance(comp_class.LINKER_PREFIX, str):
_, _, e = Popen_safe(compiler + [comp_class.LINKER_PREFIX + '-V'] + extra_args)
else:
_, _, e = Popen_safe(compiler + comp_class.LINKER_PREFIX + ['-V'] + extra_args)
linker = AIXDynamicLinker(
compiler, for_machine, comp_class.LINKER_PREFIX, override,
version=search_version(e))
else:
__failed_to_detect_linker(compiler, check_args, o, e)
return linker

@ -135,6 +135,7 @@ __all__ = [
'version_compare', 'version_compare',
'version_compare_condition_with_min', 'version_compare_condition_with_min',
'version_compare_many', 'version_compare_many',
'search_version',
'windows_proof_rm', 'windows_proof_rm',
'windows_proof_rmtree', 'windows_proof_rmtree',
] ]
@ -883,6 +884,49 @@ def version_compare_condition_with_min(condition: str, minimum: str) -> bool:
return T.cast(bool, cmpop(Version(minimum), Version(condition))) return T.cast(bool, cmpop(Version(minimum), Version(condition)))
def search_version(text: str) -> str:
# Usually of the type 4.1.4 but compiler output may contain
# stuff like this:
# (Sourcery CodeBench Lite 2014.05-29) 4.8.3 20140320 (prerelease)
# Limiting major version number to two digits seems to work
# thus far. When we get to GCC 100, this will break, but
# if we are still relevant when that happens, it can be
# considered an achievement in itself.
#
# This regex is reaching magic levels. If it ever needs
# to be updated, do not complexify but convert to something
# saner instead.
# We'll demystify it a bit with a verbose definition.
version_regex = re.compile(r"""
(?<! # Zero-width negative lookbehind assertion
(
\d # One digit
| \. # Or one period
) # One occurrence
)
# Following pattern must not follow a digit or period
(
\d{1,2} # One or two digits
(
\.\d+ # Period and one or more digits
)+ # One or more occurrences
(
-[a-zA-Z0-9]+ # Hyphen and one or more alphanumeric
)? # Zero or one occurrence
) # One occurrence
""", re.VERBOSE)
match = version_regex.search(text)
if match:
return match.group(0)
# try a simpler regex that has like "blah 2020.01.100 foo" or "blah 2020.01 foo"
version_regex = re.compile(r"(\d{1,4}\.\d{1,4}\.?\d{0,4})")
match = version_regex.search(text)
if match:
return match.group(0)
return 'unknown version'
def default_libdir() -> str: def default_libdir() -> str:
if is_debianlike(): if is_debianlike():

@ -42,6 +42,7 @@ from mesonbuild import compilers
from mesonbuild import mesonlib from mesonbuild import mesonlib
from mesonbuild import mlog from mesonbuild import mlog
from mesonbuild import mtest from mesonbuild import mtest
from mesonbuild.compilers import compiler_from_language, detect_objc_compiler, detect_objcpp_compiler
from mesonbuild.build import ConfigurationData from mesonbuild.build import ConfigurationData
from mesonbuild.mesonlib import MachineChoice, Popen_safe, TemporaryDirectoryWinProof from mesonbuild.mesonlib import MachineChoice, Popen_safe, TemporaryDirectoryWinProof
from mesonbuild.mlog import blue, bold, cyan, green, red, yellow, normal_green from mesonbuild.mlog import blue, bold, cyan, green, red, yellow, normal_green
@ -884,7 +885,7 @@ def have_objc_compiler(use_tmp: bool) -> bool:
with TemporaryDirectoryWinProof(prefix='b ', dir=None if use_tmp else '.') as build_dir: with TemporaryDirectoryWinProof(prefix='b ', dir=None if use_tmp else '.') as build_dir:
env = environment.Environment(None, build_dir, get_fake_options('/')) env = environment.Environment(None, build_dir, get_fake_options('/'))
try: try:
objc_comp = env.detect_objc_compiler(MachineChoice.HOST) objc_comp = detect_objc_compiler(env, MachineChoice.HOST)
except mesonlib.MesonException: except mesonlib.MesonException:
return False return False
if not objc_comp: if not objc_comp:
@ -900,7 +901,7 @@ def have_objcpp_compiler(use_tmp: bool) -> bool:
with TemporaryDirectoryWinProof(prefix='b ', dir=None if use_tmp else '.') as build_dir: with TemporaryDirectoryWinProof(prefix='b ', dir=None if use_tmp else '.') as build_dir:
env = environment.Environment(None, build_dir, get_fake_options('/')) env = environment.Environment(None, build_dir, get_fake_options('/'))
try: try:
objcpp_comp = env.detect_objcpp_compiler(MachineChoice.HOST) objcpp_comp = detect_objcpp_compiler(env, MachineChoice.HOST)
except mesonlib.MesonException: except mesonlib.MesonException:
return False return False
if not objcpp_comp: if not objcpp_comp:
@ -1392,7 +1393,7 @@ def detect_system_compiler(options: 'CompilerArgumentType') -> None:
for lang in sorted(compilers.all_languages): for lang in sorted(compilers.all_languages):
try: try:
comp = env.compiler_from_language(lang, MachineChoice.HOST) comp = compiler_from_language(env, lang, MachineChoice.HOST)
# note compiler id for later use with test.json matrix # note compiler id for later use with test.json matrix
compiler_id_map[lang] = comp.get_id() compiler_id_map[lang] = comp.get_id()
except mesonlib.MesonException: except mesonlib.MesonException:
@ -1412,7 +1413,7 @@ def print_compilers(env: 'Environment', machine: MachineChoice) -> None:
print() print()
for lang in sorted(compilers.all_languages): for lang in sorted(compilers.all_languages):
try: try:
comp = env.compiler_from_language(lang, machine) comp = compiler_from_language(env, lang, machine)
details = '{:<10} {} {}'.format('[' + comp.get_id() + ']', ' '.join(comp.get_exelist()), comp.get_version_string()) details = '{:<10} {} {}'.format('[' + comp.get_id() + ']', ' '.join(comp.get_exelist()), comp.get_version_string())
except mesonlib.MesonException: except mesonlib.MesonException:
details = '[not found]' details = '[not found]'

@ -59,7 +59,13 @@ from mesonbuild.mesonlib import (
BuildDirLock, LibType, MachineChoice, PerMachine, Version, is_windows, BuildDirLock, LibType, MachineChoice, PerMachine, Version, is_windows,
is_osx, is_cygwin, is_dragonflybsd, is_openbsd, is_haiku, is_sunos, is_osx, is_cygwin, is_dragonflybsd, is_openbsd, is_haiku, is_sunos,
windows_proof_rmtree, windows_proof_rm, python_command, windows_proof_rmtree, windows_proof_rm, python_command,
version_compare, split_args, quote_arg, relpath, is_linux, git version_compare, split_args, quote_arg, relpath, is_linux, git,
search_version
)
from mesonbuild.compilers import (
detect_static_linker, detect_c_compiler, detect_cpp_compiler,
detect_objc_compiler, detect_objcpp_compiler, detect_d_compiler,
detect_swift_compiler, compiler_from_language
) )
from mesonbuild.environment import detect_ninja from mesonbuild.environment import detect_ninja
from mesonbuild.mesonlib import MesonException, EnvironmentException, OptionKey from mesonbuild.mesonlib import MesonException, EnvironmentException, OptionKey
@ -140,7 +146,7 @@ def _git_init(project_dir):
# If a user has git configuration init.defaultBranch set we want to override that # If a user has git configuration init.defaultBranch set we want to override that
with tempfile.TemporaryDirectory() as d: with tempfile.TemporaryDirectory() as d:
out = git(['--version'], str(d))[1] out = git(['--version'], str(d))[1]
if version_compare(mesonbuild.environment.search_version(out), '>= 2.28'): if version_compare(search_version(out), '>= 2.28'):
extra_cmd = ['--initial-branch', 'master'] extra_cmd = ['--initial-branch', 'master']
else: else:
extra_cmd = [] extra_cmd = []
@ -226,14 +232,12 @@ def skip_if_no_cmake(f):
return f(*args, **kwargs) return f(*args, **kwargs)
return wrapped return wrapped
def skip_if_not_language(lang): def skip_if_not_language(lang: str):
def wrapper(func): def wrapper(func):
@functools.wraps(func) @functools.wraps(func)
def wrapped(*args, **kwargs): def wrapped(*args, **kwargs):
try: try:
env = get_fake_env() compiler_from_language(get_fake_env(), lang, MachineChoice.HOST)
f = getattr(env, f'detect_{lang}_compiler')
f(MachineChoice.HOST)
except EnvironmentException: except EnvironmentException:
raise unittest.SkipTest(f'No {lang} compiler found.') raise unittest.SkipTest(f'No {lang} compiler found.')
return func(*args, **kwargs) return func(*args, **kwargs)
@ -269,7 +273,7 @@ def skip_if_not_base_option(feature):
@functools.wraps(f) @functools.wraps(f)
def wrapped(*args, **kwargs): def wrapped(*args, **kwargs):
env = get_fake_env() env = get_fake_env()
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
key = OptionKey(feature) key = OptionKey(feature)
if key not in cc.base_options: if key not in cc.base_options:
raise unittest.SkipTest( raise unittest.SkipTest(
@ -327,18 +331,17 @@ def no_pkgconfig():
class InternalTests(unittest.TestCase): class InternalTests(unittest.TestCase):
def test_version_number(self): def test_version_number(self):
searchfunc = mesonbuild.environment.search_version self.assertEqual(search_version('foobar 1.2.3'), '1.2.3')
self.assertEqual(searchfunc('foobar 1.2.3'), '1.2.3') self.assertEqual(search_version('1.2.3'), '1.2.3')
self.assertEqual(searchfunc('1.2.3'), '1.2.3') self.assertEqual(search_version('foobar 2016.10.28 1.2.3'), '1.2.3')
self.assertEqual(searchfunc('foobar 2016.10.28 1.2.3'), '1.2.3') self.assertEqual(search_version('2016.10.28 1.2.3'), '1.2.3')
self.assertEqual(searchfunc('2016.10.28 1.2.3'), '1.2.3') self.assertEqual(search_version('foobar 2016.10.128'), '2016.10.128')
self.assertEqual(searchfunc('foobar 2016.10.128'), '2016.10.128') self.assertEqual(search_version('2016.10.128'), '2016.10.128')
self.assertEqual(searchfunc('2016.10.128'), '2016.10.128') self.assertEqual(search_version('2016.10'), '2016.10')
self.assertEqual(searchfunc('2016.10'), '2016.10') self.assertEqual(search_version('2016.10 1.2.3'), '1.2.3')
self.assertEqual(searchfunc('2016.10 1.2.3'), '1.2.3') self.assertEqual(search_version('oops v1.2.3'), '1.2.3')
self.assertEqual(searchfunc('oops v1.2.3'), '1.2.3') self.assertEqual(search_version('2016.oops 1.2.3'), '1.2.3')
self.assertEqual(searchfunc('2016.oops 1.2.3'), '1.2.3') self.assertEqual(search_version('2016.x'), 'unknown version')
self.assertEqual(searchfunc('2016.x'), 'unknown version')
def test_mode_symbolic_to_bits(self): def test_mode_symbolic_to_bits(self):
modefunc = mesonbuild.mesonlib.FileMode.perms_s_to_bits modefunc = mesonbuild.mesonlib.FileMode.perms_s_to_bits
@ -837,7 +840,7 @@ class InternalTests(unittest.TestCase):
'{}.dll.a', '{}.lib', '{}.dll'), '{}.dll.a', '{}.lib', '{}.dll'),
'static': msvc_static}} 'static': msvc_static}}
env = get_fake_env() env = get_fake_env()
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
if is_osx(): if is_osx():
self._test_all_naming(cc, env, patterns, 'darwin') self._test_all_naming(cc, env, patterns, 'darwin')
elif is_cygwin(): elif is_cygwin():
@ -881,7 +884,7 @@ class InternalTests(unittest.TestCase):
with tempfile.TemporaryDirectory() as tmpdir: with tempfile.TemporaryDirectory() as tmpdir:
pkgbin = ExternalProgram('pkg-config', command=['pkg-config'], silent=True) pkgbin = ExternalProgram('pkg-config', command=['pkg-config'], silent=True)
env = get_fake_env() env = get_fake_env()
compiler = env.detect_c_compiler(MachineChoice.HOST) compiler = detect_c_compiler(env, MachineChoice.HOST)
env.coredata.compilers.host = {'c': compiler} env.coredata.compilers.host = {'c': compiler}
env.coredata.options[OptionKey('link_args', lang='c')] = FakeCompilerOptions() env.coredata.options[OptionKey('link_args', lang='c')] = FakeCompilerOptions()
p1 = Path(tmpdir) / '1' p1 = Path(tmpdir) / '1'
@ -1063,7 +1066,7 @@ class InternalTests(unittest.TestCase):
Ensure that the toolset version returns the correct value for this MSVC Ensure that the toolset version returns the correct value for this MSVC
''' '''
env = get_fake_env() env = get_fake_env()
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
if cc.get_argument_syntax() != 'msvc': if cc.get_argument_syntax() != 'msvc':
raise unittest.SkipTest('Test only applies to MSVC-like compilers') raise unittest.SkipTest('Test only applies to MSVC-like compilers')
toolset_ver = cc.get_toolset_version() toolset_ver = cc.get_toolset_version()
@ -1752,8 +1755,8 @@ class DataTests(unittest.TestCase):
self.assertIsNotNone(md) self.assertIsNotNone(md)
env = get_fake_env() env = get_fake_env()
# FIXME: Support other compilers # FIXME: Support other compilers
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
cpp = env.detect_cpp_compiler(MachineChoice.HOST) cpp = detect_cpp_compiler(env, MachineChoice.HOST)
for comp in (cc, cpp): for comp in (cc, cpp):
for opt in comp.get_options(): for opt in comp.get_options():
self.assertIn(str(opt), md) self.assertIn(str(opt), md)
@ -2556,7 +2559,7 @@ class AllPlatformTests(BasePlatformTests):
def test_clike_get_library_dirs(self): def test_clike_get_library_dirs(self):
env = get_fake_env() env = get_fake_env()
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
for d in cc.get_library_dirs(env): for d in cc.get_library_dirs(env):
self.assertTrue(os.path.exists(d)) self.assertTrue(os.path.exists(d))
self.assertTrue(os.path.isdir(d)) self.assertTrue(os.path.isdir(d))
@ -2572,8 +2575,8 @@ class AllPlatformTests(BasePlatformTests):
''' '''
testdir = os.path.join(self.common_test_dir, '3 static') testdir = os.path.join(self.common_test_dir, '3 static')
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
static_linker = env.detect_static_linker(cc) static_linker = detect_static_linker(env, cc)
if is_windows(): if is_windows():
raise unittest.SkipTest('https://github.com/mesonbuild/meson/issues/1526') raise unittest.SkipTest('https://github.com/mesonbuild/meson/issues/1526')
if not isinstance(static_linker, mesonbuild.linkers.ArLinker): if not isinstance(static_linker, mesonbuild.linkers.ArLinker):
@ -3041,9 +3044,9 @@ class AllPlatformTests(BasePlatformTests):
for lang, evar in langs: for lang, evar in langs:
# Detect with evar and do sanity checks on that # Detect with evar and do sanity checks on that
if evar in os.environ: if evar in os.environ:
ecc = getattr(env, f'detect_{lang}_compiler')(MachineChoice.HOST) ecc = compiler_from_language(env, lang, MachineChoice.HOST)
self.assertTrue(ecc.version) self.assertTrue(ecc.version)
elinker = env.detect_static_linker(ecc) elinker = detect_static_linker(env, ecc)
# 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(evar) evalue = os.environ.pop(evar)
# Very rough/strict heuristics. Would never work for actual # Very rough/strict heuristics. Would never work for actual
@ -3069,9 +3072,9 @@ class AllPlatformTests(BasePlatformTests):
# Check that we actually used the evalue correctly as the compiler # Check that we actually used the evalue correctly as the compiler
self.assertEqual(ecc.get_exelist(), split_args(evalue)) self.assertEqual(ecc.get_exelist(), split_args(evalue))
# Do auto-detection of compiler based on platform, PATH, etc. # Do auto-detection of compiler based on platform, PATH, etc.
cc = getattr(env, f'detect_{lang}_compiler')(MachineChoice.HOST) cc = compiler_from_language(env, lang, MachineChoice.HOST)
self.assertTrue(cc.version) self.assertTrue(cc.version)
linker = env.detect_static_linker(cc) linker = detect_static_linker(env, cc)
# Check compiler type # Check compiler type
if isinstance(cc, gnu): if isinstance(cc, gnu):
self.assertIsInstance(linker, ar) self.assertIsInstance(linker, ar)
@ -3129,8 +3132,8 @@ class AllPlatformTests(BasePlatformTests):
# Need a new env to re-run environment loading # Need a new env to re-run environment loading
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
wcc = getattr(env, f'detect_{lang}_compiler')(MachineChoice.HOST) wcc = compiler_from_language(env, lang, MachineChoice.HOST)
wlinker = env.detect_static_linker(wcc) wlinker = detect_static_linker(env, 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')
# Must be the same type since it's a wrapper around the same exelist # Must be the same type since it's a wrapper around the same exelist
@ -3148,7 +3151,7 @@ class AllPlatformTests(BasePlatformTests):
testdir = os.path.join(self.common_test_dir, '133 c cpp and asm') testdir = os.path.join(self.common_test_dir, '133 c cpp and asm')
# Skip if building with MSVC # Skip if building with MSVC
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
if env.detect_c_compiler(MachineChoice.HOST).get_id() == 'msvc': if detect_c_compiler(env, MachineChoice.HOST).get_id() == 'msvc':
raise unittest.SkipTest('MSVC can\'t compile assembly') raise unittest.SkipTest('MSVC can\'t compile assembly')
self.init(testdir) self.init(testdir)
commands = {'c-asm': {}, 'cpp-asm': {}, 'cpp-c-asm': {}, 'c-cpp-asm': {}} commands = {'c-asm': {}, 'cpp-asm': {}, 'cpp-c-asm': {}, 'c-cpp-asm': {}}
@ -3309,7 +3312,7 @@ class AllPlatformTests(BasePlatformTests):
testdir = os.path.join(self.common_test_dir, '5 linkstatic') testdir = os.path.join(self.common_test_dir, '5 linkstatic')
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
if env.detect_c_compiler(MachineChoice.HOST).get_id() == 'clang' and is_windows(): if detect_c_compiler(env, MachineChoice.HOST).get_id() == 'clang' and is_windows():
raise unittest.SkipTest('LTO not (yet) supported by windows clang') raise unittest.SkipTest('LTO not (yet) supported by windows clang')
self.init(testdir, extra_args='-Db_lto=true') self.init(testdir, extra_args='-Db_lto=true')
@ -3321,7 +3324,7 @@ class AllPlatformTests(BasePlatformTests):
testdir = os.path.join(self.common_test_dir, '6 linkshared') testdir = os.path.join(self.common_test_dir, '6 linkshared')
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
extra_args: T.List[str] = [] extra_args: T.List[str] = []
if cc.get_id() == 'clang': if cc.get_id() == 'clang':
if is_windows(): if is_windows():
@ -3347,7 +3350,7 @@ class AllPlatformTests(BasePlatformTests):
testdir = os.path.join(self.common_test_dir, '6 linkshared') testdir = os.path.join(self.common_test_dir, '6 linkshared')
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
if cc.get_id() != 'clang': if cc.get_id() != 'clang':
raise unittest.SkipTest('Only clang currently supports thinLTO') raise unittest.SkipTest('Only clang currently supports thinLTO')
if cc.linker.id not in {'ld.lld', 'ld.gold', 'ld64', 'lld-link'}: if cc.linker.id not in {'ld.lld', 'ld.gold', 'ld64', 'lld-link'}:
@ -3615,8 +3618,8 @@ class AllPlatformTests(BasePlatformTests):
def detect_prebuild_env(self): def detect_prebuild_env(self):
env = get_fake_env() env = get_fake_env()
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
stlinker = env.detect_static_linker(cc) stlinker = detect_static_linker(env, cc)
if mesonbuild.mesonlib.is_windows(): if mesonbuild.mesonlib.is_windows():
object_suffix = 'obj' object_suffix = 'obj'
shared_suffix = 'dll' shared_suffix = 'dll'
@ -4060,7 +4063,7 @@ class AllPlatformTests(BasePlatformTests):
env = get_fake_env() env = get_fake_env()
for l in ['cpp', 'cs', 'd', 'java', 'cuda', 'fortran', 'objc', 'objcpp', 'rust']: for l in ['cpp', 'cs', 'd', 'java', 'cuda', 'fortran', 'objc', 'objcpp', 'rust']:
try: try:
comp = env.detect_compiler_for(l, MachineChoice.HOST) comp = mesonbuild.compilers.detect_compiler_for(env, l, MachineChoice.HOST)
with tempfile.TemporaryDirectory() as d: with tempfile.TemporaryDirectory() as d:
comp.sanity_check(d, env) comp.sanity_check(d, env)
langs.append(l) langs.append(l)
@ -4170,7 +4173,7 @@ class AllPlatformTests(BasePlatformTests):
extra_args = None extra_args = None
libdir_flags = ['-L'] libdir_flags = ['-L']
env = get_fake_env(testdirlib, self.builddir, self.prefix) env = get_fake_env(testdirlib, self.builddir, self.prefix)
if env.detect_c_compiler(MachineChoice.HOST).get_id() in {'msvc', 'clang-cl', 'intel-cl'}: if detect_c_compiler(env, MachineChoice.HOST).get_id() in {'msvc', 'clang-cl', 'intel-cl'}:
# msvc-like compiler, also test it with msvc-specific flags # msvc-like compiler, also test it with msvc-specific flags
libdir_flags += ['/LIBPATH:', '-LIBPATH:'] libdir_flags += ['/LIBPATH:', '-LIBPATH:']
else: else:
@ -5562,7 +5565,7 @@ class AllPlatformTests(BasePlatformTests):
raise unittest.SkipTest('gcovr not found, or too old') raise unittest.SkipTest('gcovr not found, or too old')
testdir = os.path.join(self.common_test_dir, '1 trivial') testdir = os.path.join(self.common_test_dir, '1 trivial')
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
if cc.get_id() == 'clang': if cc.get_id() == 'clang':
if not mesonbuild.environment.detect_llvm_cov(): if not mesonbuild.environment.detect_llvm_cov():
raise unittest.SkipTest('llvm-cov not found') raise unittest.SkipTest('llvm-cov not found')
@ -5582,7 +5585,7 @@ class AllPlatformTests(BasePlatformTests):
raise unittest.SkipTest('gcovr not found, or too old') raise unittest.SkipTest('gcovr not found, or too old')
testdir = os.path.join(self.common_test_dir, '105 generatorcustom') testdir = os.path.join(self.common_test_dir, '105 generatorcustom')
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
if cc.get_id() == 'clang': if cc.get_id() == 'clang':
if not mesonbuild.environment.detect_llvm_cov(): if not mesonbuild.environment.detect_llvm_cov():
raise unittest.SkipTest('llvm-cov not found') raise unittest.SkipTest('llvm-cov not found')
@ -5602,7 +5605,7 @@ class AllPlatformTests(BasePlatformTests):
raise unittest.SkipTest('gcovr not found, or too old') raise unittest.SkipTest('gcovr not found, or too old')
testdir = os.path.join(self.common_test_dir, '1 trivial') testdir = os.path.join(self.common_test_dir, '1 trivial')
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
if cc.get_id() == 'clang': if cc.get_id() == 'clang':
if not mesonbuild.environment.detect_llvm_cov(): if not mesonbuild.environment.detect_llvm_cov():
raise unittest.SkipTest('llvm-cov not found') raise unittest.SkipTest('llvm-cov not found')
@ -5622,7 +5625,7 @@ class AllPlatformTests(BasePlatformTests):
raise unittest.SkipTest('gcovr not found, or too old') raise unittest.SkipTest('gcovr not found, or too old')
testdir = os.path.join(self.common_test_dir, '1 trivial') testdir = os.path.join(self.common_test_dir, '1 trivial')
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
if cc.get_id() == 'clang': if cc.get_id() == 'clang':
if not mesonbuild.environment.detect_llvm_cov(): if not mesonbuild.environment.detect_llvm_cov():
raise unittest.SkipTest('llvm-cov not found') raise unittest.SkipTest('llvm-cov not found')
@ -5642,7 +5645,7 @@ class AllPlatformTests(BasePlatformTests):
raise unittest.SkipTest('gcovr not found, or too old') raise unittest.SkipTest('gcovr not found, or too old')
testdir = os.path.join(self.common_test_dir, '1 trivial') testdir = os.path.join(self.common_test_dir, '1 trivial')
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
if cc.get_id() == 'clang': if cc.get_id() == 'clang':
if not mesonbuild.environment.detect_llvm_cov(): if not mesonbuild.environment.detect_llvm_cov():
raise unittest.SkipTest('llvm-cov not found') raise unittest.SkipTest('llvm-cov not found')
@ -5842,7 +5845,7 @@ class AllPlatformTests(BasePlatformTests):
'bar/barfile' 'bar/barfile'
] ]
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
if cc.get_argument_syntax() == 'msvc': if cc.get_argument_syntax() == 'msvc':
main_expected.append('bin/foo.pdb') main_expected.append('bin/foo.pdb')
bar_expected.append('bin/bar.pdb') bar_expected.append('bin/bar.pdb')
@ -5936,18 +5939,18 @@ class AllPlatformTests(BasePlatformTests):
env = get_fake_env() env = get_fake_env()
# Get the compiler so we know which compiler class to mock. # Get the compiler so we know which compiler class to mock.
cc = env.detect_compiler_for('c', MachineChoice.HOST) cc = mesonbuild.compilers.detect_compiler_for(env, 'c', MachineChoice.HOST)
cc_type = type(cc) cc_type = type(cc)
# Test a compiler that acts as a linker # Test a compiler that acts as a linker
with mock.patch.object(cc_type, 'INVOKES_LINKER', True): with mock.patch.object(cc_type, 'INVOKES_LINKER', True):
cc = env.detect_compiler_for('c', MachineChoice.HOST) cc = mesonbuild.compilers.detect_compiler_for(env, 'c', MachineChoice.HOST)
link_args = env.coredata.get_external_link_args(cc.for_machine, cc.language) link_args = env.coredata.get_external_link_args(cc.for_machine, cc.language)
self.assertEqual(sorted(link_args), sorted(['-DCFLAG', '-flto'])) self.assertEqual(sorted(link_args), sorted(['-DCFLAG', '-flto']))
# And one that doesn't # And one that doesn't
with mock.patch.object(cc_type, 'INVOKES_LINKER', False): with mock.patch.object(cc_type, 'INVOKES_LINKER', False):
cc = env.detect_compiler_for('c', MachineChoice.HOST) cc = mesonbuild.compilers.detect_compiler_for(env, 'c', MachineChoice.HOST)
link_args = env.coredata.get_external_link_args(cc.for_machine, cc.language) link_args = env.coredata.get_external_link_args(cc.for_machine, cc.language)
self.assertEqual(sorted(link_args), sorted(['-flto'])) self.assertEqual(sorted(link_args), sorted(['-flto']))
@ -6141,8 +6144,8 @@ class FailureTests(BasePlatformTests):
''' '''
env = get_fake_env() env = get_fake_env()
try: try:
env.detect_objc_compiler(MachineChoice.HOST) detect_objc_compiler(env, MachineChoice.HOST)
env.detect_objcpp_compiler(MachineChoice.HOST) detect_objcpp_compiler(env, MachineChoice.HOST)
except EnvironmentException: except EnvironmentException:
code = "add_languages('objc')\nadd_languages('objcpp')" code = "add_languages('objc')\nadd_languages('objcpp')"
self.assertMesonRaises(code, "Unknown compiler") self.assertMesonRaises(code, "Unknown compiler")
@ -6362,7 +6365,7 @@ class WindowsTests(BasePlatformTests):
''' '''
testdir = os.path.join(self.platform_test_dir, '1 basic') testdir = os.path.join(self.platform_test_dir, '1 basic')
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
if cc.get_argument_syntax() != 'msvc': if cc.get_argument_syntax() != 'msvc':
raise unittest.SkipTest('Not using MSVC') raise unittest.SkipTest('Not using MSVC')
# To force people to update this test, and also test # To force people to update this test, and also test
@ -6375,7 +6378,7 @@ class WindowsTests(BasePlatformTests):
# resource compiler depfile generation is not yet implemented for msvc # resource compiler depfile generation is not yet implemented for msvc
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
depfile_works = env.detect_c_compiler(MachineChoice.HOST).get_id() not in {'msvc', 'clang-cl', 'intel-cl'} depfile_works = detect_c_compiler(env, MachineChoice.HOST).get_id() not in {'msvc', 'clang-cl', 'intel-cl'}
self.init(testdir) self.init(testdir)
self.build() self.build()
@ -6406,7 +6409,7 @@ class WindowsTests(BasePlatformTests):
testdir = os.path.join(self.unit_test_dir, '45 vscpp17') testdir = os.path.join(self.unit_test_dir, '45 vscpp17')
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
if cc.get_argument_syntax() != 'msvc': if cc.get_argument_syntax() != 'msvc':
raise unittest.SkipTest('Test only applies to MSVC-like compilers') raise unittest.SkipTest('Test only applies to MSVC-like compilers')
@ -6424,7 +6427,7 @@ class WindowsTests(BasePlatformTests):
testdir = os.path.join(self.platform_test_dir, '1 basic') testdir = os.path.join(self.platform_test_dir, '1 basic')
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
if cc.get_argument_syntax() != 'msvc': if cc.get_argument_syntax() != 'msvc':
raise unittest.SkipTest('Test only applies to MSVC-like compilers') raise unittest.SkipTest('Test only applies to MSVC-like compilers')
@ -6448,28 +6451,28 @@ class WindowsTests(BasePlatformTests):
with mock.patch.dict(os.environ, {envvar: name}): with mock.patch.dict(os.environ, {envvar: name}):
env = get_fake_env() env = get_fake_env()
try: try:
comp = getattr(env, f'detect_{lang}_compiler')(MachineChoice.HOST) comp = compiler_from_language(env, lang, MachineChoice.HOST)
except EnvironmentException: except EnvironmentException:
raise unittest.SkipTest(f'Could not find a compiler for {lang}') raise unittest.SkipTest(f'Could not find a compiler for {lang}')
self.assertEqual(comp.linker.id, expected) self.assertEqual(comp.linker.id, expected)
def test_link_environment_variable_lld_link(self): def test_link_environment_variable_lld_link(self):
env = get_fake_env() env = get_fake_env()
comp = getattr(env, 'detect_c_compiler')(MachineChoice.HOST) comp = detect_c_compiler(env, MachineChoice.HOST)
if isinstance(comp, mesonbuild.compilers.GnuLikeCompiler): if isinstance(comp, mesonbuild.compilers.GnuLikeCompiler):
raise unittest.SkipTest('GCC cannot be used with link compatible linkers.') raise unittest.SkipTest('GCC cannot be used with link compatible linkers.')
self._check_ld('lld-link', 'c', 'lld-link') self._check_ld('lld-link', 'c', 'lld-link')
def test_link_environment_variable_link(self): def test_link_environment_variable_link(self):
env = get_fake_env() env = get_fake_env()
comp = getattr(env, 'detect_c_compiler')(MachineChoice.HOST) comp = detect_c_compiler(env, MachineChoice.HOST)
if isinstance(comp, mesonbuild.compilers.GnuLikeCompiler): if isinstance(comp, mesonbuild.compilers.GnuLikeCompiler):
raise unittest.SkipTest('GCC cannot be used with link compatible linkers.') raise unittest.SkipTest('GCC cannot be used with link compatible linkers.')
self._check_ld('link', 'c', 'link') self._check_ld('link', 'c', 'link')
def test_link_environment_variable_optlink(self): def test_link_environment_variable_optlink(self):
env = get_fake_env() env = get_fake_env()
comp = getattr(env, 'detect_c_compiler')(MachineChoice.HOST) comp = detect_c_compiler(env, MachineChoice.HOST)
if isinstance(comp, mesonbuild.compilers.GnuLikeCompiler): if isinstance(comp, mesonbuild.compilers.GnuLikeCompiler):
raise unittest.SkipTest('GCC cannot be used with link compatible linkers.') raise unittest.SkipTest('GCC cannot be used with link compatible linkers.')
self._check_ld('optlink', 'c', 'optlink') self._check_ld('optlink', 'c', 'optlink')
@ -6481,7 +6484,7 @@ class WindowsTests(BasePlatformTests):
@skip_if_not_language('d') @skip_if_not_language('d')
def test_link_environment_variable_d(self): def test_link_environment_variable_d(self):
env = get_fake_env() env = get_fake_env()
comp = getattr(env, 'detect_d_compiler')(MachineChoice.HOST) comp = detect_d_compiler(env, MachineChoice.HOST)
if comp.id == 'dmd': if comp.id == 'dmd':
raise unittest.SkipTest('meson cannot reliably make DMD use a different linker.') raise unittest.SkipTest('meson cannot reliably make DMD use a different linker.')
self._check_ld('lld-link', 'd', 'lld-link') self._check_ld('lld-link', 'd', 'lld-link')
@ -6498,7 +6501,7 @@ class WindowsTests(BasePlatformTests):
self.build() self.build()
# Test that binaries have a non-zero checksum # Test that binaries have a non-zero checksum
env = get_fake_env() env = get_fake_env()
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
cc_id = cc.get_id() cc_id = cc.get_id()
ld_id = cc.get_linker_id() ld_id = cc.get_linker_id()
dll = glob(os.path.join(self.builddir, '*mycpplib.dll'))[0] dll = glob(os.path.join(self.builddir, '*mycpplib.dll'))[0]
@ -6520,7 +6523,7 @@ class WindowsTests(BasePlatformTests):
''' '''
# Verify that the `b_vscrt` option is available # Verify that the `b_vscrt` option is available
env = get_fake_env() env = get_fake_env()
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
if OptionKey('b_vscrt') not in cc.base_options: if OptionKey('b_vscrt') not in cc.base_options:
raise unittest.SkipTest('Compiler does not support setting the VS CRT') raise unittest.SkipTest('Compiler does not support setting the VS CRT')
# Verify that qmake is for Qt5 # Verify that qmake is for Qt5
@ -6546,7 +6549,7 @@ class WindowsTests(BasePlatformTests):
''' '''
# Verify that the `b_vscrt` option is available # Verify that the `b_vscrt` option is available
env = get_fake_env() env = get_fake_env()
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
if OptionKey('b_vscrt') not in cc.base_options: if OptionKey('b_vscrt') not in cc.base_options:
raise unittest.SkipTest('Compiler does not support setting the VS CRT') raise unittest.SkipTest('Compiler does not support setting the VS CRT')
@ -6614,7 +6617,7 @@ class DarwinTests(BasePlatformTests):
''' '''
testdir = os.path.join(self.platform_test_dir, '7 bitcode') testdir = os.path.join(self.platform_test_dir, '7 bitcode')
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
if cc.id != 'clang': if cc.id != 'clang':
raise unittest.SkipTest('Not using Clang on OSX') raise unittest.SkipTest('Not using Clang on OSX')
# Try with bitcode enabled # Try with bitcode enabled
@ -6794,7 +6797,7 @@ class LinuxlikeTests(BasePlatformTests):
self.assertEqual(libhello_nolib.get_pkgconfig_variable('escaped_var', {}), r'hello\ world') self.assertEqual(libhello_nolib.get_pkgconfig_variable('escaped_var', {}), r'hello\ world')
self.assertEqual(libhello_nolib.get_pkgconfig_variable('unescaped_var', {}), 'hello world') self.assertEqual(libhello_nolib.get_pkgconfig_variable('unescaped_var', {}), 'hello world')
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
if cc.get_id() in {'gcc', 'clang'}: if cc.get_id() in {'gcc', 'clang'}:
for name in {'ct', 'ct0'}: for name in {'ct', 'ct0'}:
ct_dep = PkgConfigDependency(name, env, kwargs) ct_dep = PkgConfigDependency(name, env, kwargs)
@ -7069,7 +7072,7 @@ class LinuxlikeTests(BasePlatformTests):
''' '''
testdir = os.path.join(self.common_test_dir, '36 has function') testdir = os.path.join(self.common_test_dir, '36 has function')
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
cpp = env.detect_cpp_compiler(MachineChoice.HOST) cpp = detect_cpp_compiler(env, MachineChoice.HOST)
Oflag = '-O3' Oflag = '-O3'
OflagCPP = Oflag OflagCPP = Oflag
if cpp.get_id() in ('clang', 'gcc'): if cpp.get_id() in ('clang', 'gcc'):
@ -7161,7 +7164,7 @@ class LinuxlikeTests(BasePlatformTests):
''' '''
testdir = os.path.join(self.common_test_dir, '1 trivial') testdir = os.path.join(self.common_test_dir, '1 trivial')
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
self._test_stds_impl(testdir, cc) self._test_stds_impl(testdir, cc)
def test_compiler_cpp_stds(self): def test_compiler_cpp_stds(self):
@ -7171,7 +7174,7 @@ class LinuxlikeTests(BasePlatformTests):
''' '''
testdir = os.path.join(self.common_test_dir, '2 cpp') testdir = os.path.join(self.common_test_dir, '2 cpp')
env = get_fake_env(testdir, self.builddir, self.prefix) env = get_fake_env(testdir, self.builddir, self.prefix)
cpp = env.detect_cpp_compiler(MachineChoice.HOST) cpp = detect_cpp_compiler(env, MachineChoice.HOST)
self._test_stds_impl(testdir, cpp) self._test_stds_impl(testdir, cpp)
def test_unity_subproj(self): def test_unity_subproj(self):
@ -8011,7 +8014,7 @@ class LinuxlikeTests(BasePlatformTests):
if is_cygwin() or is_osx(): if is_cygwin() or is_osx():
raise unittest.SkipTest('Not applicable on Cygwin or OSX.') raise unittest.SkipTest('Not applicable on Cygwin or OSX.')
env = get_fake_env() env = get_fake_env()
cc = env.detect_c_compiler(MachineChoice.HOST) cc = detect_c_compiler(env, MachineChoice.HOST)
linker = cc.linker linker = cc.linker
if not linker.export_dynamic_args(env): if not linker.export_dynamic_args(env):
raise unittest.SkipTest('Not applicable for linkers without --export-dynamic') raise unittest.SkipTest('Not applicable for linkers without --export-dynamic')
@ -8124,7 +8127,7 @@ class LinuxlikeTests(BasePlatformTests):
for envvar in envvars: for envvar in envvars:
with mock.patch.dict(os.environ, {envvar: name}): with mock.patch.dict(os.environ, {envvar: name}):
env = get_fake_env() env = get_fake_env()
comp = getattr(env, f'detect_{lang}_compiler')(MachineChoice.HOST) comp = compiler_from_language(env, lang, MachineChoice.HOST)
if isinstance(comp, (mesonbuild.compilers.AppleClangCCompiler, if isinstance(comp, (mesonbuild.compilers.AppleClangCCompiler,
mesonbuild.compilers.AppleClangCPPCompiler, mesonbuild.compilers.AppleClangCPPCompiler,
mesonbuild.compilers.AppleClangObjCCompiler, mesonbuild.compilers.AppleClangObjCCompiler,
@ -8910,8 +8913,7 @@ class NativeFileTests(BasePlatformTests):
with more than one implementation, such as C, C++, ObjC, ObjC++, and D. with more than one implementation, such as C, C++, ObjC, ObjC++, and D.
""" """
env = get_fake_env() env = get_fake_env()
getter = getattr(env, f'detect_{lang}_compiler') getter = lambda: compiler_from_language(env, lang, for_machine)
getter = functools.partial(getter, for_machine)
cc = getter() cc = getter()
binary, newid = cb(cc) binary, newid = cb(cc)
env.binaries[for_machine].binaries[lang] = binary env.binaries[for_machine].binaries[lang] = binary
@ -9115,10 +9117,8 @@ class NativeFileTests(BasePlatformTests):
""" """
wrapper = self.helper_create_binary_wrapper(binary, version=version_str) wrapper = self.helper_create_binary_wrapper(binary, version=version_str)
env = get_fake_env() env = get_fake_env()
getter = getattr(env, f'detect_{lang}_compiler')
getter = functools.partial(getter, MachineChoice.HOST)
env.binaries.host.binaries[lang] = [wrapper] env.binaries.host.binaries[lang] = [wrapper]
compiler = getter() compiler = compiler_from_language(env, lang, MachineChoice.HOST)
self.assertEqual(compiler.version, version) self.assertEqual(compiler.version, version)
@skip_if_not_language('vala') @skip_if_not_language('vala')
@ -9145,7 +9145,7 @@ class NativeFileTests(BasePlatformTests):
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 = detect_swift_compiler(env, MachineChoice.HOST)
self.assertEqual(compiler.version, '1.2345') self.assertEqual(compiler.version, '1.2345')
def test_native_file_dirs(self): def test_native_file_dirs(self):
@ -10023,7 +10023,7 @@ class SubprojectsCommandTests(BasePlatformTests):
# If a user has git configuration init.defaultBranch set we want to override that # If a user has git configuration init.defaultBranch set we want to override that
with tempfile.TemporaryDirectory() as d: with tempfile.TemporaryDirectory() as d:
out = git(['--version'], str(d))[1] out = git(['--version'], str(d))[1]
if version_compare(mesonbuild.environment.search_version(out), '>= 2.28'): if version_compare(search_version(out), '>= 2.28'):
extra_cmd = ['--initial-branch', 'master'] extra_cmd = ['--initial-branch', 'master']
else: else:
extra_cmd = [] extra_cmd = []

Loading…
Cancel
Save