files: # Copyright 2013-2019 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.
  
  # This file contains the detection logic for external dependencies useful for
  # development purposes, such as testing, debugging, etc..
  
  import functools
  import glob
  import os
  import re
  
  from .. import mesonlib, mlog
  from ..mesonlib import version_compare, stringlistify, extract_as_list, MachineChoice
  from ..environment import get_llvm_tool_names
  from .base import (
      DependencyException, DependencyMethods, ExternalDependency, PkgConfigDependency,
      strip_system_libdirs, ConfigToolDependency, CMakeDependency, HasNativeKwarg
  )
  from .misc import ThreadDependency
  
  from typing import List, Tuple
  
  
  def get_shared_library_suffix(environment, for_machine: MachineChoice):
      """This is only gauranteed to work for languages that compile to machine
      code, not for languages like C# that use a bytecode and always end in .dll
      """
      m = environment.machines[for_machine]
      if m.is_windows():
          return '.dll'
      elif m.is_darwin():
          return '.dylib'
      return '.so'
  
  
  class GTestDependency(ExternalDependency):
      def __init__(self, environment, kwargs):
          super().__init__('gtest', environment, 'cpp', kwargs)
          self.main = kwargs.get('main', False)
          self.src_dirs = ['/usr/src/gtest/src', '/usr/src/googletest/googletest/src']
          self.detect()
          self._add_sub_dependency(ThreadDependency, environment, kwargs)
  
      def detect(self):
          gtest_detect = self.clib_compiler.find_library("gtest", self.env, [])
          gtest_main_detect = self.clib_compiler.find_library("gtest_main", self.env, [])
          if gtest_detect and (not self.main or gtest_main_detect):
              self.is_found = True
              self.compile_args = []
              self.link_args = gtest_detect
              if self.main:
                  self.link_args += gtest_main_detect
              self.sources = []
              self.prebuilt = True
          elif self.detect_srcdir():
              self.is_found = True
              self.compile_args = ['-I' + d for d in self.src_include_dirs]
              self.link_args = []
              if self.main:
                  self.sources = [self.all_src, self.main_src]
              else:
                  self.sources = [self.all_src]
              self.prebuilt = False
          else:
              self.is_found = False
  
      def detect_srcdir(self):
          for s in self.src_dirs:
              if os.path.exists(s):
                  self.src_dir = s
                  self.all_src = mesonlib.File.from_absolute_file(
                      os.path.join(self.src_dir, 'gtest-all.cc'))
                  self.main_src = mesonlib.File.from_absolute_file(
                      os.path.join(self.src_dir, 'gtest_main.cc'))
                  self.src_include_dirs = [os.path.normpath(os.path.join(self.src_dir, '..')),
                                           os.path.normpath(os.path.join(self.src_dir, '../include')),
                                           ]
                  return True
          return False
  
      def log_info(self):
          if self.prebuilt:
              return 'prebuilt'
          else:
              return 'building self'
  
      def log_tried(self):
          return 'system'
  
      @classmethod
      def _factory(cls, environment, kwargs):
          methods = cls._process_method_kw(kwargs)
          candidates = []
  
          if DependencyMethods.PKGCONFIG in methods:
              pcname = 'gtest_main' if kwargs.get('main', False) else 'gtest'
              candidates.append(functools.partial(PkgConfigDependency, pcname, environment, kwargs))
  
          if DependencyMethods.SYSTEM in methods:
              candidates.append(functools.partial(GTestDependency, environment, kwargs))
  
          return candidates
  
      @staticmethod
      def get_methods():
          return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM]
  
  
  class GMockDependency(ExternalDependency):
      def __init__(self, environment, kwargs):
          super().__init__('gmock', environment, 'cpp', kwargs)
          self.main = kwargs.get('main', False)
          self._add_sub_dependency(ThreadDependency, environment, kwargs)
  
          # If we are getting main() from GMock, we definitely
          # want to avoid linking in main() from GTest
          gtest_kwargs = kwargs.copy()
          if self.main:
              gtest_kwargs['main'] = False
  
          # GMock without GTest is pretty much useless
          # this also mimics the structure given in WrapDB,
          # where GMock always pulls in GTest
          gtest_dep = GTestDependency(environment, gtest_kwargs)
          if not gtest_dep.is_found:
              self.is_found = False
              return
          self.ext_deps.append(gtest_dep)
  
          # GMock may be a library or just source.
          # Work with both.
          gmock_detect = self.clib_compiler.find_library("gmock", self.env, [])
          gmock_main_detect = self.clib_compiler.find_library("gmock_main", self.env, [])
          if gmock_detect and (not self.main or gmock_main_detect):
              self.is_found = True
              self.link_args += gmock_detect
              if self.main:
                  self.link_args += gmock_main_detect
              self.prebuilt = True
              return
  
          for d in ['/usr/src/googletest/googlemock/src', '/usr/src/gmock/src', '/usr/src/gmock']:
              if os.path.exists(d):
                  self.is_found = True
                  # Yes, we need both because there are multiple
                  # versions of gmock that do different things.
                  d2 = os.path.normpath(os.path.join(d, '..'))
                  self.compile_args += ['-I' + d, '-I' + d2, '-I' + os.path.join(d2, 'include')]
                  all_src = mesonlib.File.from_absolute_file(os.path.join(d, 'gmock-all.cc'))
                  main_src = mesonlib.File.from_absolute_file(os.path.join(d, 'gmock_main.cc'))
                  if self.main:
                      self.sources += [all_src, main_src]
                  else:
                      self.sources += [all_src]
                  self.prebuilt = False
                  return
  
          self.is_found = False
  
      def log_info(self):
          if self.prebuilt:
              return 'prebuilt'
          else:
              return 'building self'
  
      def log_tried(self):
          return 'system'
  
      @classmethod
      def _factory(cls, environment, kwargs):
          methods = cls._process_method_kw(kwargs)
          candidates = []
  
          if DependencyMethods.PKGCONFIG in methods:
              pcname = 'gmock_main' if kwargs.get('main', False) else 'gmock'
              candidates.append(functools.partial(PkgConfigDependency, pcname, environment, kwargs))
  
          if DependencyMethods.SYSTEM in methods:
              candidates.append(functools.partial(GMockDependency, environment, kwargs))
  
          return candidates
  
      @staticmethod
      def get_methods():
          return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM]
  
  
  class LLVMDependencyConfigTool(ConfigToolDependency):
      """
      LLVM uses a special tool, llvm-config, which has arguments for getting
      c args, cxx args, and ldargs as well as version.
      """
      tool_name = 'llvm-config'
      __cpp_blacklist = {'-DNDEBUG'}
  
      def __init__(self, environment, kwargs):
          # Already called by `super().__init__`, but need `self.for_machine`
          # before `super().__init__` is called.
          HasNativeKwarg.__init__(self, kwargs)
  
          self.tools = get_llvm_tool_names('llvm-config')
  
          # Fedora starting with Fedora 30 adds a suffix of the number
          # of bits in the isa that llvm targets, for example, on x86_64
          # and aarch64 the name will be llvm-config-64, on x86 and arm
          # it will be llvm-config-32.
          if environment.machines[self.for_machine].is_64_bit:
  
  
  [... the rest is omitted ...]
files: mesonbuild/dependencies/dev.py
files: # Copyright 2013-2019 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.
  
  # This file contains the detection logic for external dependencies useful for
  # development purposes, such as testing, debugging, etc..
  
  import functools
  import glob
  import os
  import re
  
  from .. import mesonlib, mlog
  from ..mesonlib import version_compare, stringlistify, extract_as_list, MachineChoice
  from .base import (
      DependencyException, DependencyMethods, ExternalDependency, PkgConfigDependency,
      strip_system_libdirs, ConfigToolDependency, CMakeDependency, HasNativeKwarg
  )
  from .misc import ThreadDependency
  
  from typing import List, Tuple
  
  
  def get_shared_library_suffix(environment, for_machine: MachineChoice):
      """This is only gauranteed to work for languages that compile to machine
      code, not for languages like C# that use a bytecode and always end in .dll
      """
      m = environment.machines[for_machine]
      if m.is_windows():
          return '.dll'
      elif m.is_darwin():
          return '.dylib'
      return '.so'
  
  
  class GTestDependency(ExternalDependency):
      def __init__(self, environment, kwargs):
          super().__init__('gtest', environment, 'cpp', kwargs)
          self.main = kwargs.get('main', False)
          self.src_dirs = ['/usr/src/gtest/src', '/usr/src/googletest/googletest/src']
          self.detect()
          self._add_sub_dependency(ThreadDependency, environment, kwargs)
  
      def detect(self):
          gtest_detect = self.clib_compiler.find_library("gtest", self.env, [])
          gtest_main_detect = self.clib_compiler.find_library("gtest_main", self.env, [])
          if gtest_detect and (not self.main or gtest_main_detect):
              self.is_found = True
              self.compile_args = []
              self.link_args = gtest_detect
              if self.main:
                  self.link_args += gtest_main_detect
              self.sources = []
              self.prebuilt = True
          elif self.detect_srcdir():
              self.is_found = True
              self.compile_args = ['-I' + d for d in self.src_include_dirs]
              self.link_args = []
              if self.main:
                  self.sources = [self.all_src, self.main_src]
              else:
                  self.sources = [self.all_src]
              self.prebuilt = False
          else:
              self.is_found = False
  
      def detect_srcdir(self):
          for s in self.src_dirs:
              if os.path.exists(s):
                  self.src_dir = s
                  self.all_src = mesonlib.File.from_absolute_file(
                      os.path.join(self.src_dir, 'gtest-all.cc'))
                  self.main_src = mesonlib.File.from_absolute_file(
                      os.path.join(self.src_dir, 'gtest_main.cc'))
                  self.src_include_dirs = [os.path.normpath(os.path.join(self.src_dir, '..')),
                                           os.path.normpath(os.path.join(self.src_dir, '../include')),
                                           ]
                  return True
          return False
  
      def log_info(self):
          if self.prebuilt:
              return 'prebuilt'
          else:
              return 'building self'
  
      def log_tried(self):
          return 'system'
  
      @classmethod
      def _factory(cls, environment, kwargs):
          methods = cls._process_method_kw(kwargs)
          candidates = []
  
          if DependencyMethods.PKGCONFIG in methods:
              pcname = 'gtest_main' if kwargs.get('main', False) else 'gtest'
              candidates.append(functools.partial(PkgConfigDependency, pcname, environment, kwargs))
  
          if DependencyMethods.SYSTEM in methods:
              candidates.append(functools.partial(GTestDependency, environment, kwargs))
  
          return candidates
  
      @staticmethod
      def get_methods():
          return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM]
  
  
  class GMockDependency(ExternalDependency):
      def __init__(self, environment, kwargs):
          super().__init__('gmock', environment, 'cpp', kwargs)
          self.main = kwargs.get('main', False)
          self._add_sub_dependency(ThreadDependency, environment, kwargs)
  
          # If we are getting main() from GMock, we definitely
          # want to avoid linking in main() from GTest
          gtest_kwargs = kwargs.copy()
          if self.main:
              gtest_kwargs['main'] = False
  
          # GMock without GTest is pretty much useless
          # this also mimics the structure given in WrapDB,
          # where GMock always pulls in GTest
          gtest_dep = GTestDependency(environment, gtest_kwargs)
          if not gtest_dep.is_found:
              self.is_found = False
              return
          self.ext_deps.append(gtest_dep)
  
          # GMock may be a library or just source.
          # Work with both.
          gmock_detect = self.clib_compiler.find_library("gmock", self.env, [])
          gmock_main_detect = self.clib_compiler.find_library("gmock_main", self.env, [])
          if gmock_detect and (not self.main or gmock_main_detect):
              self.is_found = True
              self.link_args += gmock_detect
              if self.main:
                  self.link_args += gmock_main_detect
              self.prebuilt = True
              return
  
          for d in ['/usr/src/googletest/googlemock/src', '/usr/src/gmock/src', '/usr/src/gmock']:
              if os.path.exists(d):
                  self.is_found = True
                  # Yes, we need both because there are multiple
                  # versions of gmock that do different things.
                  d2 = os.path.normpath(os.path.join(d, '..'))
                  self.compile_args += ['-I' + d, '-I' + d2, '-I' + os.path.join(d2, 'include')]
                  all_src = mesonlib.File.from_absolute_file(os.path.join(d, 'gmock-all.cc'))
                  main_src = mesonlib.File.from_absolute_file(os.path.join(d, 'gmock_main.cc'))
                  if self.main:
                      self.sources += [all_src, main_src]
                  else:
                      self.sources += [all_src]
                  self.prebuilt = False
                  return
  
          self.is_found = False
  
      def log_info(self):
          if self.prebuilt:
              return 'prebuilt'
          else:
              return 'building self'
  
      def log_tried(self):
          return 'system'
  
      @classmethod
      def _factory(cls, environment, kwargs):
          methods = cls._process_method_kw(kwargs)
          candidates = []
  
          if DependencyMethods.PKGCONFIG in methods:
              pcname = 'gmock_main' if kwargs.get('main', False) else 'gmock'
              candidates.append(functools.partial(PkgConfigDependency, pcname, environment, kwargs))
  
          if DependencyMethods.SYSTEM in methods:
              candidates.append(functools.partial(GMockDependency, environment, kwargs))
  
          return candidates
  
      @staticmethod
      def get_methods():
          return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM]
  
  
  class LLVMDependencyConfigTool(ConfigToolDependency):
      """
      LLVM uses a special tool, llvm-config, which has arguments for getting
      c args, cxx args, and ldargs as well as version.
      """
      tool_name = 'llvm-config'
      __cpp_blacklist = {'-DNDEBUG'}
  
      def __init__(self, environment, kwargs):
          # Already called by `super().__init__`, but need `self.for_machine`
          # before `super().__init__` is called.
          HasNativeKwarg.__init__(self, kwargs)
  
          # Ordered list of llvm-config binaries to try. Start with base, then try
          # newest back to oldest (3.5 is arbitrary), and finally the devel version.
          # Please note that llvm-config-6.0 is a development snapshot and it should
          # not be moved to the beginning of the list.
          self.tools = [
              'llvm-config', # base
              'llvm-config-8',   'llvm-config80',
              'llvm-config-7',   'llvm-config70',
             
  
  [... the rest is omitted ...]
files: mesonbuild/dependencies/dev.py
files: # Copyright 2012-2016 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.
  
  import os, platform, re, sys, shutil, subprocess, typing
  import tempfile
  import shlex
  
  from . import coredata
  from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, DLinker, CcrxLinker, IntelVisualStudioLinker
  from . import mesonlib
  from .mesonlib import (
      MesonException, EnvironmentException, MachineChoice, Popen_safe,
      PerMachineDefaultable, PerThreeMachineDefaultable, split_args, quote_arg
  )
  from . import mlog
  
  from .envconfig import (
      BinaryTable, Directories, MachineInfo, MesonConfigFile,
      Properties, known_cpu_families,
  )
  from . import compilers
  from .compilers import (
      Compiler,
      CompilerType,
      is_assembly,
      is_header,
      is_library,
      is_llvm_ir,
      is_object,
      is_source,
  )
  from .linkers import (
      AppleDynamicLinker,
      ArmClangDynamicLinker,
      ArmDynamicLinker,
      CcrxDynamicLinker,
      ClangClDynamicLinker,
      DynamicLinker,
      GnuDynamicLinker,
      LLVMDynamicLinker,
      MSVCDynamicLinker,
      OptlinkDynamicLinker,
      PGIDynamicLinker,
      PGIStaticLinker,
      SolarisDynamicLinker,
      XildAppleDynamicLinker,
      XildLinuxDynamicLinker,
      XilinkDynamicLinker,
      CudaLinker,
  )
  from functools import lru_cache
  from .compilers import (
      ArmCCompiler,
      ArmCPPCompiler,
      ArmclangCCompiler,
      ArmclangCPPCompiler,
      ClangCCompiler,
      ClangCPPCompiler,
      ClangObjCCompiler,
      ClangObjCPPCompiler,
      ClangClCCompiler,
      ClangClCPPCompiler,
      FlangFortranCompiler,
      G95FortranCompiler,
      GnuCCompiler,
      GnuCPPCompiler,
      GnuFortranCompiler,
      GnuObjCCompiler,
      GnuObjCPPCompiler,
      ElbrusCCompiler,
      ElbrusCPPCompiler,
      ElbrusFortranCompiler,
      EmscriptenCCompiler,
      EmscriptenCPPCompiler,
      IntelCCompiler,
      IntelClCCompiler,
      IntelCPPCompiler,
      IntelClCPPCompiler,
      IntelFortranCompiler,
      IntelClFortranCompiler,
      JavaCompiler,
      MonoCompiler,
      CudaCompiler,
      VisualStudioCsCompiler,
      NAGFortranCompiler,
      Open64FortranCompiler,
      PathScaleFortranCompiler,
      PGICCompiler,
      PGICPPCompiler,
      PGIFortranCompiler,
      RustCompiler,
      CcrxCCompiler,
      CcrxCPPCompiler,
      SunFortranCompiler,
      ValaCompiler,
      VisualStudioCCompiler,
      VisualStudioCPPCompiler,
  )
  
  build_filename = 'meson.build'
  
  CompilersDict = typing.Dict[str, Compiler]
  
  def detect_gcovr(min_version='3.3', new_rootdir_version='4.2', log=False):
      gcovr_exe = 'gcovr'
      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, mesonlib.version_compare(found, '>=' + new_rootdir_version)
      return None, None
  
  def find_coverage_tools():
      gcovr_exe, gcovr_new_rootdir = detect_gcovr()
  
      lcov_exe = 'lcov'
      genhtml_exe = 'genhtml'
  
      if not mesonlib.exe_exists([lcov_exe, '--version']):
          lcov_exe = None
      if not mesonlib.exe_exists([genhtml_exe, '--version']):
          genhtml_exe = None
  
      return gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe
  
  def detect_ninja(version: str = '1.5', log: bool = False) -> str:
      env_ninja = os.environ.get('NINJA', None)
      for n in [env_ninja] if env_ninja else ['ninja', 'ninja-build', 'samu']:
          try:
              p, found = Popen_safe([n, '--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):
              n = shutil.which(n)
              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, quote_arg(n)))
              return n
  
  def get_llvm_tool_names(tool: str) -> typing.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)
          '-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',
          '-9',     # Debian development snapshot
          '-devel', # FreeBSD development snapshot
      ]
      names = []
      for suffix in suffixes:
          names.append(tool + suffix)
      return names
  
  def detect_scanbuild():
      """ 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 = []
      if 'SCANBUILD' in os.environ:
          exelist = split_args(os.environ['SCANBUILD'])
  
      else:
          tools = get_llvm_tool_names('scan-build')
          for tool in tools:
              if shutil.which(tool) is not None:
                  exelist = [shutil.which(tool)]
                  break
  
      if exelist:
          tool = exelist[0]
          if os.path.isfile(tool) and os.access(tool, os.X_OK):
              return [tool]
      return []
  
  def detect_native_windows_arch():
      """
      The architecture of Windows itself: x86, amd64 or arm64
      """
      # These env variables are always available. See:
      # https://msdn.microsoft.com/en-us/library/aa384274(VS.85).aspx
      # https://blogs.msdn.microsoft.com/david.wang/2006/03/27/howto-detect-process-bitness/
      arch = os.environ.get('PROCESSOR_ARCHIT
  
  [... the rest is omitted ...]
files: mesonbuild/environment.py
files: # Copyright 2012-2016 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.
  
  import os, platform, re, sys, shutil, subprocess, typing
  import tempfile
  import shlex
  
  from . import coredata
  from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, DLinker, CcrxLinker, IntelVisualStudioLinker
  from . import mesonlib
  from .mesonlib import (
      MesonException, EnvironmentException, MachineChoice, Popen_safe,
      PerMachineDefaultable, PerThreeMachineDefaultable, split_args, quote_arg
  )
  from . import mlog
  
  from .envconfig import (
      BinaryTable, Directories, MachineInfo, MesonConfigFile,
      Properties, known_cpu_families,
  )
  from . import compilers
  from .compilers import (
      Compiler,
      CompilerType,
      is_assembly,
      is_header,
      is_library,
      is_llvm_ir,
      is_object,
      is_source,
  )
  from .linkers import (
      AppleDynamicLinker,
      ArmClangDynamicLinker,
      ArmDynamicLinker,
      CcrxDynamicLinker,
      ClangClDynamicLinker,
      DynamicLinker,
      GnuDynamicLinker,
      LLVMDynamicLinker,
      MSVCDynamicLinker,
      OptlinkDynamicLinker,
      PGIDynamicLinker,
      PGIStaticLinker,
      SolarisDynamicLinker,
      XildAppleDynamicLinker,
      XildLinuxDynamicLinker,
      XilinkDynamicLinker,
      CudaLinker,
  )
  from functools import lru_cache
  from .compilers import (
      ArmCCompiler,
      ArmCPPCompiler,
      ArmclangCCompiler,
      ArmclangCPPCompiler,
      ClangCCompiler,
      ClangCPPCompiler,
      ClangObjCCompiler,
      ClangObjCPPCompiler,
      ClangClCCompiler,
      ClangClCPPCompiler,
      FlangFortranCompiler,
      G95FortranCompiler,
      GnuCCompiler,
      GnuCPPCompiler,
      GnuFortranCompiler,
      GnuObjCCompiler,
      GnuObjCPPCompiler,
      ElbrusCCompiler,
      ElbrusCPPCompiler,
      ElbrusFortranCompiler,
      EmscriptenCCompiler,
      EmscriptenCPPCompiler,
      IntelCCompiler,
      IntelClCCompiler,
      IntelCPPCompiler,
      IntelClCPPCompiler,
      IntelFortranCompiler,
      IntelClFortranCompiler,
      JavaCompiler,
      MonoCompiler,
      CudaCompiler,
      VisualStudioCsCompiler,
      NAGFortranCompiler,
      Open64FortranCompiler,
      PathScaleFortranCompiler,
      PGICCompiler,
      PGICPPCompiler,
      PGIFortranCompiler,
      RustCompiler,
      CcrxCCompiler,
      CcrxCPPCompiler,
      SunFortranCompiler,
      ValaCompiler,
      VisualStudioCCompiler,
      VisualStudioCPPCompiler,
  )
  
  build_filename = 'meson.build'
  
  CompilersDict = typing.Dict[str, Compiler]
  
  def detect_gcovr(min_version='3.3', new_rootdir_version='4.2', log=False):
      gcovr_exe = 'gcovr'
      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, mesonlib.version_compare(found, '>=' + new_rootdir_version)
      return None, None
  
  def find_coverage_tools():
      gcovr_exe, gcovr_new_rootdir = detect_gcovr()
  
      lcov_exe = 'lcov'
      genhtml_exe = 'genhtml'
  
      if not mesonlib.exe_exists([lcov_exe, '--version']):
          lcov_exe = None
      if not mesonlib.exe_exists([genhtml_exe, '--version']):
          genhtml_exe = None
  
      return gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe
  
  def detect_ninja(version: str = '1.5', log: bool = False) -> str:
      env_ninja = os.environ.get('NINJA', None)
      for n in [env_ninja] if env_ninja else ['ninja', 'ninja-build', 'samu']:
          try:
              p, found = Popen_safe([n, '--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):
              n = shutil.which(n)
              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, quote_arg(n)))
              return n
  
  def detect_scanbuild():
      """ 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 = []
      if 'SCANBUILD' in os.environ:
          exelist = split_args(os.environ['SCANBUILD'])
  
      else:
          tools = [
              'scan-build',  # base
              'scan-build-8',   'scan-build80',
              'scan-build-7',   'scan-build70',
              'scan-build-6.0', 'scan-build60',
              'scan-build-5.0', 'scan-build50',
              'scan-build-4.0', 'scan-build40',
              'scan-build-3.9', 'scan-build39',
              'scan-build-3.8', 'scan-build38',
              'scan-build-3.7', 'scan-build37',
              'scan-build-3.6', 'scan-build36',
              'scan-build-3.5', 'scan-build35',
              'scan-build-9',   'scan-build-devel',  # development snapshot
          ]
          for tool in tools:
              if shutil.which(tool) is not None:
                  exelist = [shutil.which(tool)]
                  break
  
      if exelist:
          tool = exelist[0]
          if os.path.isfile(tool) and os.access(tool, os.X_OK):
              return [tool]
      return []
  
  def detect_native_windows_arch():
      """
      The architecture of Windows itself: x86, amd64 or arm64
      """
      # These env variables are always available. See:
      # https://msdn.microsoft.com/en-us/library/aa384274(VS.85).aspx
      # https://blogs.msdn.microsoft.com/david.wang/2006/03/27/howto-detect-process-bitness/
      arch = os.environ.get('PROCESSOR_ARCHITEW6432', '').lower()
      if not arch:
          try:
              # If this doesn't exist, something is messing with the environment
              arch = os.environ['PROCESSOR_ARCHITECTURE'].lower()
          except KeyError:
              raise EnvironmentException('Unable to detect native OS architecture')
      return arch
  
  def detect_windows_arch(compilers: CompilersDict) -> str:
     
  
  [... the rest is omitted ...]
files: mesonbuild/environment.py