diff options
| author | Paolo Bonzini <pbonzini@redhat.com> | 2025-10-07 18:22:06 +0200 |
|---|---|---|
| committer | Jussi Pakkanen <jussi.pakkanen@mailbox.org> | 2025-10-29 18:59:30 +0200 |
| commit | 795e7431ffafa0cc1257d64c5fdd0f2c3cb6d841 (patch) | |
| tree | 40ff7c80d4ae38cb1b144824a284e0115368e7c0 /mesonbuild/environment.py | |
| parent | 1614401329f11d3763a56ed5ce207aba511a6a9d (diff) | |
| download | meson-795e7431ffafa0cc1257d64c5fdd0f2c3cb6d841.tar.gz | |
environment: move tool detection functions to a new module
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'mesonbuild/environment.py')
| -rw-r--r-- | mesonbuild/environment.py | 239 |
1 files changed, 3 insertions, 236 deletions
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 4d89c88ef..90b10697a 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -5,7 +5,7 @@ from __future__ import annotations import itertools -import os, re, shutil +import os, re import typing as T import collections @@ -17,8 +17,8 @@ from . import options from .mesonlib import ( MesonException, MachineChoice, Popen_safe, PerMachine, - PerMachineDefaultable, PerThreeMachineDefaultable, split_args, quote_arg, - search_version, MesonBugException + PerMachineDefaultable, PerThreeMachineDefaultable, split_args, + MesonBugException ) from .options import OptionKey from . import mlog @@ -78,239 +78,6 @@ def _get_env_var(for_machine: MachineChoice, is_cross: bool, var_name: str) -> T return value -def detect_gcovr(gcovr_exe: str = 'gcovr', min_version: str = '3.3', log: bool = False) \ - -> T.Union[T.Tuple[None, None], T.Tuple[str, str]]: - try: - p, found = Popen_safe([gcovr_exe, '--version'])[0:2] - except (FileNotFoundError, PermissionError): - # Doesn't exist in PATH or isn't executable - return None, None - found = search_version(found) - if p.returncode == 0 and mesonlib.version_compare(found, '>=' + min_version): - if log: - mlog.log('Found gcovr-{} at {}'.format(found, quote_arg(shutil.which(gcovr_exe)))) - return gcovr_exe, found - return None, None - -def detect_lcov(lcov_exe: str = 'lcov', log: bool = False) \ - -> T.Union[T.Tuple[None, None], T.Tuple[str, str]]: - try: - p, found = Popen_safe([lcov_exe, '--version'])[0:2] - except (FileNotFoundError, PermissionError): - # Doesn't exist in PATH or isn't executable - return None, None - found = search_version(found) - if p.returncode == 0 and found: - if log: - mlog.log('Found lcov-{} at {}'.format(found, quote_arg(shutil.which(lcov_exe)))) - return lcov_exe, found - return None, None - -def detect_llvm_cov(suffix: T.Optional[str] = None) -> T.Optional[str]: - # If there's a known suffix or forced lack of suffix, use that - if suffix is not None: - if suffix == '': - tool = 'llvm-cov' - else: - tool = f'llvm-cov-{suffix}' - if shutil.which(tool) is not None: - return tool - else: - # Otherwise guess in the dark - tools = get_llvm_tool_names('llvm-cov') - for tool in tools: - if shutil.which(tool): - return tool - return None - -def compute_llvm_suffix(coredata: coredata.CoreData) -> T.Optional[str]: - # Check to see if the user is trying to do coverage for either a C or C++ project - compilers = coredata.compilers[MachineChoice.BUILD] - cpp_compiler_is_clang = 'cpp' in compilers and compilers['cpp'].id == 'clang' - c_compiler_is_clang = 'c' in compilers and compilers['c'].id == 'clang' - # Extract first the C++ compiler if available. If it's a Clang of some kind, compute the suffix if possible - if cpp_compiler_is_clang: - suffix = compilers['cpp'].version.split('.')[0] - return suffix - - # Then the C compiler, again checking if it's some kind of Clang and computing the suffix - if c_compiler_is_clang: - suffix = compilers['c'].version.split('.')[0] - return suffix - - # Neither compiler is a Clang, or no compilers are for C or C++ - return None - -def detect_lcov_genhtml(lcov_exe: str = 'lcov', genhtml_exe: str = 'genhtml') \ - -> T.Tuple[str, T.Optional[str], str]: - lcov_exe, lcov_version = detect_lcov(lcov_exe) - if shutil.which(genhtml_exe) is None: - genhtml_exe = None - - return lcov_exe, lcov_version, genhtml_exe - -def find_coverage_tools(coredata: coredata.CoreData) -> T.Tuple[T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str]]: - gcovr_exe, gcovr_version = detect_gcovr() - - llvm_cov_exe = detect_llvm_cov(compute_llvm_suffix(coredata)) - # Some platforms may provide versioned clang but only non-versioned llvm utils - if llvm_cov_exe is None: - llvm_cov_exe = detect_llvm_cov('') - - lcov_exe, lcov_version, genhtml_exe = detect_lcov_genhtml() - - return gcovr_exe, gcovr_version, lcov_exe, lcov_version, genhtml_exe, llvm_cov_exe - -def detect_ninja(version: str = '1.8.2', log: bool = False) -> T.Optional[T.List[str]]: - r = detect_ninja_command_and_version(version, log) - return r[0] if r else None - -def detect_ninja_command_and_version(version: str = '1.8.2', log: bool = False) -> T.Optional[T.Tuple[T.List[str], str]]: - env_ninja = os.environ.get('NINJA', None) - for n in [env_ninja] if env_ninja else ['ninja', 'ninja-build', 'samu']: - prog = ExternalProgram(n, silent=True) - if not prog.found(): - continue - try: - p, found = Popen_safe(prog.command + ['--version'])[0:2] - except (FileNotFoundError, PermissionError): - # Doesn't exist in PATH or isn't executable - continue - found = found.strip() - # Perhaps we should add a way for the caller to know the failure mode - # (not found or too old) - if p.returncode == 0 and mesonlib.version_compare(found, '>=' + version): - if log: - name = os.path.basename(n) - if name.endswith('-' + found): - name = name[0:-1 - len(found)] - if name == 'ninja-build': - name = 'ninja' - if name == 'samu': - name = 'samurai' - mlog.log('Found {}-{} at {}'.format(name, found, - ' '.join([quote_arg(x) for x in prog.command]))) - return (prog.command, found) - return None - -def get_llvm_tool_names(tool: str) -> T.List[str]: - # Ordered list of possible suffixes of LLVM executables to try. Start with - # base, then try newest back to oldest (3.5 is arbitrary), and finally the - # devel version. Please note that the development snapshot in Debian does - # not have a distinct name. Do not move it to the beginning of the list - # unless it becomes a stable release. - suffixes = [ - '', # base (no suffix) - '-21.1', '21.1', - '-21', '21', - '-20.1', '20.1', - '-20', '20', - '-19.1', '19.1', - '-19', '19', - '-18.1', '18.1', - '-18', '18', - '-17', '17', - '-16', '16', - '-15', '15', - '-14', '14', - '-13', '13', - '-12', '12', - '-11', '11', - '-10', '10', - '-9', '90', - '-8', '80', - '-7', '70', - '-6.0', '60', - '-5.0', '50', - '-4.0', '40', - '-3.9', '39', - '-3.8', '38', - '-3.7', '37', - '-3.6', '36', - '-3.5', '35', - '-20', # Debian development snapshot - '-devel', # FreeBSD development snapshot - ] - names: T.List[str] = [] - for suffix in suffixes: - names.append(tool + suffix) - return names - -def detect_scanbuild() -> T.List[str]: - """ Look for scan-build binary on build platform - - First, if a SCANBUILD env variable has been provided, give it precedence - on all platforms. - - For most platforms, scan-build is found is the PATH contains a binary - named "scan-build". However, some distribution's package manager (FreeBSD) - don't. For those, loop through a list of candidates to see if one is - available. - - Return: a single-element list of the found scan-build binary ready to be - passed to Popen() - """ - exelist: T.List[str] = [] - if 'SCANBUILD' in os.environ: - exelist = split_args(os.environ['SCANBUILD']) - - else: - tools = get_llvm_tool_names('scan-build') - for tool in tools: - which = shutil.which(tool) - if which is not None: - exelist = [which] - break - - if exelist: - tool = exelist[0] - if os.path.isfile(tool) and os.access(tool, os.X_OK): - return [tool] - return [] - -def detect_clangformat() -> T.List[str]: - """ Look for clang-format binary on build platform - - Do the same thing as detect_scanbuild to find clang-format except it - currently does not check the environment variable. - - Return: a single-element list of the found clang-format binary ready to be - passed to Popen() - """ - tools = get_llvm_tool_names('clang-format') - for tool in tools: - path = shutil.which(tool) - if path is not None: - return [path] - return [] - -def detect_clangtidy() -> T.List[str]: - """ Look for clang-tidy binary on build platform - - Return: a single-element list of the found clang-tidy binary ready to be - passed to Popen() - """ - tools = get_llvm_tool_names('clang-tidy') - for tool in tools: - path = shutil.which(tool) - if path is not None: - return [path] - return [] - -def detect_clangapply() -> T.List[str]: - """ Look for clang-apply-replacements binary on build platform - - Return: a single-element list of the found clang-apply-replacements binary - ready to be passed to Popen() - """ - tools = get_llvm_tool_names('clang-apply-replacements') - for tool in tools: - path = shutil.which(tool) - if path is not None: - return [path] - return [] - - class Environment: private_dir = 'meson-private' log_dir = 'meson-logs' |
