files.new_contents: # 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, pickle, re
  from .. import build
  from .. import dependencies
  from .. import mesonlib
  from .. import mlog
  from .. import compilers
  import json
  import subprocess
  from ..mesonlib import MesonException, OrderedSet
  from ..mesonlib import classify_unity_sources
  from ..mesonlib import File
  from ..compilers import CompilerArgs
  from collections import OrderedDict
  import shlex
  
  class CleanTrees:
      '''
      Directories outputted by custom targets that have to be manually cleaned
      because on Linux `ninja clean` only deletes empty directories.
      '''
      def __init__(self, build_dir, trees):
          self.build_dir = build_dir
          self.trees = trees
  
  class InstallData:
      def __init__(self, source_dir, build_dir, prefix, strip_bin,
                   install_umask, mesonintrospect):
          self.source_dir = source_dir
          self.build_dir = build_dir
          self.prefix = prefix
          self.strip_bin = strip_bin
          self.install_umask = install_umask
          self.targets = []
          self.headers = []
          self.man = []
          self.data = []
          self.po_package_name = ''
          self.po = []
          self.install_scripts = []
          self.install_subdirs = []
          self.mesonintrospect = mesonintrospect
  
  class TargetInstallData:
      def __init__(self, fname, outdir, aliases, strip, install_name_mappings, install_rpath, install_mode):
          self.fname = fname
          self.outdir = outdir
          self.aliases = aliases
          self.strip = strip
          self.install_name_mappings = install_name_mappings
          self.install_rpath = install_rpath
          self.install_mode = install_mode
  
  class ExecutableSerialisation:
      def __init__(self, name, fname, cmd_args, env, is_cross, exe_wrapper,
                   workdir, extra_paths, capture):
          self.name = name
          self.fname = fname
          self.cmd_args = cmd_args
          self.env = env
          self.is_cross = is_cross
          self.exe_runner = exe_wrapper
          self.workdir = workdir
          self.extra_paths = extra_paths
          self.capture = capture
  
  class TestSerialisation:
      def __init__(self, name, project, suite, fname, is_cross_built, exe_wrapper, is_parallel,
                   cmd_args, env, should_fail, timeout, workdir, extra_paths):
          self.name = name
          self.project_name = project
          self.suite = suite
          self.fname = fname
          self.is_cross_built = is_cross_built
          self.exe_runner = exe_wrapper
          self.is_parallel = is_parallel
          self.cmd_args = cmd_args
          self.env = env
          self.should_fail = should_fail
          self.timeout = timeout
          self.workdir = workdir
          self.extra_paths = extra_paths
  
  class OptionProxy:
      def __init__(self, name, value):
          self.name = name
          self.value = value
  
  class OptionOverrideProxy:
      '''Mimic an option list but transparently override
      selected option values.'''
      def __init__(self, overrides, *options):
          self.overrides = overrides
          self.options = options
  
      def __getitem__(self, option_name):
          for opts in self.options:
              if option_name in opts:
                  return self._get_override(option_name, opts[option_name])
          raise KeyError('Option not found', option_name)
  
      def _get_override(self, option_name, base_opt):
          if option_name in self.overrides:
              return OptionProxy(base_opt.name, base_opt.validate_value(self.overrides[option_name]))
          return base_opt
  
  # This class contains the basic functionality that is needed by all backends.
  # Feel free to move stuff in and out of it as you see fit.
  class Backend:
      def __init__(self, build):
          self.build = build
          self.environment = build.environment
          self.processed_targets = {}
          self.build_to_src = os.path.relpath(self.environment.get_source_dir(),
                                              self.environment.get_build_dir())
  
      def get_target_filename(self, t):
          if isinstance(t, build.CustomTarget):
              if len(t.get_outputs()) != 1:
                  mlog.warning('custom_target {!r} has more than one output! '
                               'Using the first one.'.format(t.name))
              filename = t.get_outputs()[0]
          else:
              assert(isinstance(t, build.BuildTarget))
              filename = t.get_filename()
          return os.path.join(self.get_target_dir(t), filename)
  
      def get_target_filename_abs(self, target):
          return os.path.join(self.environment.get_build_dir(), self.get_target_filename(target))
  
      def get_builtin_options_for_target(self, target):
          return OptionOverrideProxy(target.option_overrides,
                                     self.environment.coredata.builtins)
  
      def get_base_options_for_target(self, target):
          return OptionOverrideProxy(target.option_overrides,
                                     self.environment.coredata.builtins,
                                     self.environment.coredata.base_options)
  
      def get_compiler_options_for_target(self, target):
          return OptionOverrideProxy(target.option_overrides,
                                     # no code depends on builtins for now
                                     self.environment.coredata.compiler_options)
  
      def get_option_for_target(self, option_name, target):
          if option_name in target.option_overrides:
              override = target.option_overrides[option_name]
              return self.environment.coredata.validate_option_value(option_name, override)
          return self.environment.coredata.get_builtin_option(option_name)
  
      def get_target_filename_for_linking(self, target):
          # On some platforms (msvc for instance), the file that is used for
          # dynamic linking is not the same as the dynamic library itself. This
          # file is called an import library, and we want to link against that.
          # On all other platforms, we link to the library directly.
          if isinstance(target, build.SharedLibrary):
              link_lib = target.get_import_filename() or target.get_filename()
              return os.path.join(self.get_target_dir(target), link_lib)
          elif isinstance(target, build.StaticLibrary):
              return os.path.join(self.get_target_dir(target), target.get_filename())
          elif isinstance(target, build.Executable):
              if target.import_filename:
                  return os.path.join(self.get_target_dir(target), target.get_import_filename())
              else:
                  return None
          raise AssertionError('BUG: Tried to link to {!r} which is not linkable'.format(target))
  
      def get_target_dir(self, target):
          if self.environment.coredata.get_builtin_option('layout') == 'mirror':
              dirname = target.get_subdir()
          else:
              dirname = 'meson-out'
          return dirname
  
      def get_target_dir_relative_to(self, t, o):
          '''Get a target dir relative to another target's directory'''
          target_dir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(t))
          othert_dir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(o))
          return os.path.relpath(target_dir, othert_dir)
  
      def get_target_source_dir(self, target):
          # if target dir is empty, avoid extraneous trailing / from os.path.join()
          target_dir = self.get_target_dir(target)
          if target_dir:
              return os.path.join(self.build_to_src, target_dir)
          return self.build_to_src
  
      def get_target_private_dir(self, target):
          return os.path.join(self.get_target_dir(target), target.get_id())
  
      def get_target_private_dir_abs(self, target):
          return os.path.join(self.environment.get_build_dir(), self.get_target_private_dir(target))
  
      def get_target_generated_dir(self, target, gensrc, src):
          """
          Takes a BuildTarget, a generator source (CustomTarget or GeneratedList),
          and a generated source filename.
          Returns the full path of the generated source relative to the build root
          """
          # CustomTarget generators output to the build dir of the CustomTarget
          if isinstance(gensrc, (build.CustomTarget, build.CustomTargetIndex)):
              return os.path.join(self.get_target_dir(gensrc), src)
          # GeneratedList generators output to the private build directory of the
          # target that the GeneratedList is used in
          return os.path.join(self.get_target_private_dir(target), src)
  
      def get_unity_source_file(self, target, suffix):
          # There is a potential conflict here, but it is unlikely that
          # anyone both enables unity builds and has a file called foo-unity.cpp.
          osrc = target.name + '-unity.' + suffix
          return mesonlib.File.from_built_file(self.get_target_private_dir(target), osrc)
  
      def generate_unity_files(self, target, unity_src):
          abs_files = []
          result = []
          compsrcs = classify_unity_sources(target.compilers.values(), unity_src)
  
          def init_language_file(suffix):
              unity_src = self.get_unity_source_file(target, suffix)
              outfileabs = unity_src.absolute_path(self.environment.get_source_dir(),
                                                   self.environment.get_build_dir())
              outfileabs_tmp = outfileabs + '.tmp'
              abs_files.append(outfileabs)
              outfileabs_tmp_dir = os.path.dirname(outfileabs_tmp)
              if not os.path.exists(outfileabs_tmp_dir):
                  os.makedirs(outfileabs_tmp_dir)
              result.append(unity_src)
              return open(outfileabs_tmp, 'w')
  
          # For each language, generate a unity source file and return the list
          for comp, srcs in compsrcs.items():
              with init_language_file(comp.get_default_suffix()) as ofile:
                  for src in srcs:
                      ofile.write('#include<%s>\n' % src)
          [mesonlib.replace_if_different(x, x + '.tmp') for x in abs_files]
          return result
  
      def relpath(self, todir, fromdir):
          return os.path.relpath(os.path.join('dummyprefixdir', todir),
                                 os.path.join('dummyprefixdir', fromdir))
  
      def flatten_object_list(self, target, proj_dir_to_build_root=''):
          return self._flatten_object_list(target, target.get_objects(), proj_dir_to_build_root)
  
      def _flatten_object_list(self, target, objects, proj_dir_to_build_root):
          obj_list = []
          for obj in objects:
              if isinstance(obj, str):
                  o = os.path.join(proj_dir_to_build_root,
                                   self.build_to_src, target.get_subdir(), obj)
                  obj_list.append(o)
              elif isinstance(obj, mesonlib.File):
                  obj_list.append(obj.rel_to_builddir(self.build_to_src))
              elif isinstance(obj, build.ExtractedObjects):
                  if obj.recursive:
                      obj_list += self._flatten_object_list(obj.target, obj.objlist, proj_dir_to_build_root)
                  obj_list += self.determine_ext_objs(obj, proj_dir_to_build_root)
              else:
                  raise MesonException('Unknown data type in object list.')
          return obj_list
  
      def serialize_executable(self, exe, cmd_args, workdir, env={},
                               extra_paths=None, capture=None):
          import hashlib
          if extra_paths is None:
              # The callee didn't check if we needed extra paths, so check it here
              if mesonlib.is_windows() or mesonlib.is_cygwin():
                  extra_paths = self.determine_windows_extra_paths(exe, [])
              else:
                  extra_paths = []
          # Can't just use exe.name here; it will likely be run more than once
          if isinstance(exe, (dependencies.ExternalProgram,
                              build.BuildTarget, build.CustomTarget)):
              basename = exe.name
          else:
              basename = os.path.basename(exe)
          # Take a digest of the cmd args, env, workdir, and capture. This avoids
          # collisions and also makes the name deterministic over regenerations
          # which avoids a rebuild by Ninja because the cmdline stays the same.
          data = bytes(str(sorted(env.items())) + str(cmd_args) + str(workdir) + str(capture),
                       encoding='utf-8')
          digest = hashlib.sha1(data).hexdigest()
          scratch_file = 'meson_exe_{0}_{1}.dat'.format(basename, digest)
          exe_data = os.path.join(self.environment.get_scratch_dir(), scratch_file)
          with open(exe_data, 'wb') as f:
              if isinstance(exe, dependencies.ExternalProgram):
                  exe_cmd = exe.get_command()
                  exe_needs_wrapper = False
              elif isinstance(exe, (build.BuildTarget, build.CustomTarget)):
                  exe_cmd = [self.get_target_filename_abs(exe)]
                  exe_needs_wrapper = exe.is_cross
              else:
                  exe_cmd = [exe]
                  exe_needs_wrapper = False
              is_cross_built = exe_needs_wrapper and \
                  self.environment.is_cross_build() and \
                  self.environment.cross_info.need_cross_compiler() and \
                  self.environment.cross_info.need_exe_wrapper()
              if is_cross_built:
                  exe_wrapper = self.environment.cross_info.config['binaries'].get('exe_wrapper', None)
              else:
                  exe_wrapper = None
              es = ExecutableSerialisation(basename, exe_cmd, cmd_args, env,
                                           is_cross_built, exe_wrapper, workdir,
                                           extra_paths, capture)
              pickle.dump(es, f)
          return exe_data
  
      def serialize_tests(self):
          test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat')
          with open(test_data, 'wb') as datafile:
              self.write_test_file(datafile)
          benchmark_data = os.path.join(self.environment.get_scratch_dir(), 'meson_benchmark_setup.dat')
          with open(benchmark_data, 'wb') as datafile:
              self.write_benchmark_file(datafile)
          return test_data, benchmark_data
  
      def determine_linker_and_stdlib_args(self, target):
          '''
          If we're building a static library, there is only one static linker.
          Otherwise, we query the target for the dynamic linker.
          '''
          if isinstance(target, build.StaticLibrary):
              if target.is_cross:
                  return self.build.static_cross_linker, []
              else:
                  return self.build.static_linker, []
          l, stdlib_args = target.get_clink_dynamic_linker_and_stdlibs()
          return l, stdlib_args
  
      @staticmethod
      def _libdir_is_system(libdir, compilers):
          for cc in compilers.values():
              if libdir in cc.get_library_dirs():
                  return True
          return False
  
      def rpaths_for_bundled_shared_libraries(self, target, exclude_system=True):
          paths = []
          for dep in target.external_deps:
              if not isinstance(dep, (dependencies.ExternalLibrary, dependencies.PkgConfigDependency)):
                  continue
              la = dep.link_args
              if len(la) != 1 or not os.path.isabs(la[0]):
                  continue
              # The only link argument is an absolute path to a library file.
              libpath = la[0]
              libdir = os.path.dirname(libpath)
              if exclude_system and self._libdir_is_system(libdir, target.compilers):
                  # No point in adding system paths.
                  continue
              # Windows doesn't support rpaths, but we use this function to
              # emulate rpaths by setting PATH, so also accept DLLs here
              if os.path.splitext(libpath)[1] not in ['.dll', '.lib', '.so', '.dylib']:
                  continue
              if libdir.startswith(self.environment.get_source_dir()):
                  rel_to_src = libdir[len(self.environment.get_source_dir()) + 1:]
                  assert not os.path.isabs(rel_to_src), 'rel_to_src: {} is absolute'.format(rel_to_src)
                  paths.append(os.path.join(self.build_to_src, rel_to_src))
              else:
                  paths.append(libdir)
          return paths
  
      def determine_rpath_dirs(self, target):
          link_deps = target.get_all_link_deps()
          result = set()
          for ld in link_deps:
              if ld is target:
                  continue
              result.add(self.get_target_dir(ld))
          result.update(self.rpaths_for_bundled_shared_libraries(target))
          return list(result)
  
      def object_filename_from_source(self, target, source):
          assert isinstance(source, mesonlib.File)
          build_dir = self.environment.get_build_dir()
          rel_src = source.rel_to_builddir(self.build_to_src)
  
          # foo.vala files compile down to foo.c and then foo.c.o, not foo.vala.o
          if rel_src.endswith(('.vala', '.gs')):
              # See description in generate_vala_compile for this logic.
              if source.is_built:
                  if os.path.isabs(rel_src):
                      rel_src = rel_src[len(build_dir) + 1:]
                  rel_src = os.path.relpath(rel_src, self.get_target_private_dir(target))
              else:
                  rel_src = os.path.basename(rel_src)
              # A meson- prefixed directory is reserved; hopefully no-one creates a file name with such a weird prefix.
              source = 'meson-generated_' + rel_src[:-5] + '.c'
          elif source.is_built:
              if os.path.isabs(rel_src):
                  rel_src = rel_src[len(build_dir) + 1:]
              targetdir = self.get_target_private_dir(target)
              # A meson- prefixed directory is reserved; hopefully no-one creates a file name with such a weird prefix.
              source = 'meson-generated_' + os.path.relpath(rel_src, targetdir)
          else:
              if os.path.isabs(rel_src):
                  # Not from the source directory; hopefully this doesn't conflict with user's source files.
                  source = os.path.basename(rel_src)
              else:
                  source = os.path.relpath(os.path.join(build_dir, rel_src),
                                           os.path.join(self.environment.get_source_dir(), target.get_subdir()))
          return source.replace('/', '_').replace('\\', '_') + '.' + self.environment.get_object_suffix()
  
      def determine_ext_objs(self, extobj, proj_dir_to_build_root):
          result = []
  
          # Merge sources and generated sources
          sources = list(extobj.srclist)
          for gensrc in extobj.genlist:
              for s in gensrc.get_outputs():
                  path = self.get_target_generated_dir(extobj.target, gensrc, s)
                  dirpart, fnamepart = os.path.split(path)
                  sources.append(File(True, dirpart, fnamepart))
  
          # Filter out headers and all non-source files
          sources = [s for s in sources if self.environment.is_source(s) and not self.environment.is_header(s)]
  
          # extobj could contain only objects and no sources
          if not sources:
              return result
  
          targetdir = self.get_target_private_dir(extobj.target)
  
          # With unity builds, there's just one object that contains all the
         
  
  [... the rest is omitted ...]
files.new_path: mesonbuild/backend/backends.py
files.old_contents: # 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, pickle, re
  from .. import build
  from .. import dependencies
  from .. import mesonlib
  from .. import mlog
  from .. import compilers
  import json
  import subprocess
  from ..mesonlib import MesonException, OrderedSet
  from ..mesonlib import classify_unity_sources
  from ..mesonlib import File
  from ..compilers import CompilerArgs
  from collections import OrderedDict
  import shlex
  
  class CleanTrees:
      '''
      Directories outputted by custom targets that have to be manually cleaned
      because on Linux `ninja clean` only deletes empty directories.
      '''
      def __init__(self, build_dir, trees):
          self.build_dir = build_dir
          self.trees = trees
  
  class InstallData:
      def __init__(self, source_dir, build_dir, prefix, strip_bin,
                   install_umask, mesonintrospect):
          self.source_dir = source_dir
          self.build_dir = build_dir
          self.prefix = prefix
          self.strip_bin = strip_bin
          self.install_umask = install_umask
          self.targets = []
          self.headers = []
          self.man = []
          self.data = []
          self.po_package_name = ''
          self.po = []
          self.install_scripts = []
          self.install_subdirs = []
          self.mesonintrospect = mesonintrospect
  
  class TargetInstallData:
      def __init__(self, fname, outdir, aliases, strip, install_name_mappings, install_rpath, install_mode):
          self.fname = fname
          self.outdir = outdir
          self.aliases = aliases
          self.strip = strip
          self.install_name_mappings = install_name_mappings
          self.install_rpath = install_rpath
          self.install_mode = install_mode
  
  class ExecutableSerialisation:
      def __init__(self, name, fname, cmd_args, env, is_cross, exe_wrapper,
                   workdir, extra_paths, capture):
          self.name = name
          self.fname = fname
          self.cmd_args = cmd_args
          self.env = env
          self.is_cross = is_cross
          self.exe_runner = exe_wrapper
          self.workdir = workdir
          self.extra_paths = extra_paths
          self.capture = capture
  
  class TestSerialisation:
      def __init__(self, name, project, suite, fname, is_cross_built, exe_wrapper, is_parallel,
                   cmd_args, env, should_fail, timeout, workdir, extra_paths):
          self.name = name
          self.project_name = project
          self.suite = suite
          self.fname = fname
          self.is_cross_built = is_cross_built
          self.exe_runner = exe_wrapper
          self.is_parallel = is_parallel
          self.cmd_args = cmd_args
          self.env = env
          self.should_fail = should_fail
          self.timeout = timeout
          self.workdir = workdir
          self.extra_paths = extra_paths
  
  class OptionProxy:
      def __init__(self, name, value):
          self.name = name
          self.value = value
  
  class OptionOverrideProxy:
      '''Mimic an option list but transparently override
      selected option values.'''
      def __init__(self, overrides, *options):
          self.overrides = overrides
          self.options = options
  
      def __getitem__(self, option_name):
          for opts in self.options:
              if option_name in opts:
                  return self._get_override(option_name, opts[option_name])
          raise KeyError('Option not found', option_name)
  
      def _get_override(self, option_name, base_opt):
          if option_name in self.overrides:
              return OptionProxy(base_opt.name, base_opt.validate_value(self.overrides[option_name]))
          return base_opt
  
  # This class contains the basic functionality that is needed by all backends.
  # Feel free to move stuff in and out of it as you see fit.
  class Backend:
      def __init__(self, build):
          self.build = build
          self.environment = build.environment
          self.processed_targets = {}
          self.build_to_src = os.path.relpath(self.environment.get_source_dir(),
                                              self.environment.get_build_dir())
  
      def get_target_filename(self, t):
          if isinstance(t, build.CustomTarget):
              if len(t.get_outputs()) != 1:
                  mlog.warning('custom_target {!r} has more than one output! '
                               'Using the first one.'.format(t.name))
              filename = t.get_outputs()[0]
          else:
              assert(isinstance(t, build.BuildTarget))
              filename = t.get_filename()
          return os.path.join(self.get_target_dir(t), filename)
  
      def get_target_filename_abs(self, target):
          return os.path.join(self.environment.get_build_dir(), self.get_target_filename(target))
  
      def get_builtin_options_for_target(self, target):
          return OptionOverrideProxy(target.option_overrides,
                                     self.environment.coredata.builtins)
  
      def get_base_options_for_target(self, target):
          return OptionOverrideProxy(target.option_overrides,
                                     self.environment.coredata.builtins,
                                     self.environment.coredata.base_options)
  
      def get_compiler_options_for_target(self, target):
          return OptionOverrideProxy(target.option_overrides,
                                     # no code depends on builtins for now
                                     self.environment.coredata.compiler_options)
  
      def get_option_for_target(self, option_name, target):
          if option_name in target.option_overrides:
              override = target.option_overrides[option_name]
              return self.environment.coredata.validate_option_value(option_name, override)
          return self.environment.coredata.get_builtin_option(option_name)
  
      def get_target_filename_for_linking(self, target):
          # On some platforms (msvc for instance), the file that is used for
          # dynamic linking is not the same as the dynamic library itself. This
          # file is called an import library, and we want to link against that.
          # On all other platforms, we link to the library directly.
          if isinstance(target, build.SharedLibrary):
              link_lib = target.get_import_filename() or target.get_filename()
              return os.path.join(self.get_target_dir(target), link_lib)
          elif isinstance(target, build.StaticLibrary):
              return os.path.join(self.get_target_dir(target), target.get_filename())
          elif isinstance(target, build.Executable):
              if target.import_filename:
                  return os.path.join(self.get_target_dir(target), target.get_import_filename())
              else:
                  return None
          raise AssertionError('BUG: Tried to link to {!r} which is not linkable'.format(target))
  
      def get_target_dir(self, target):
          if self.environment.coredata.get_builtin_option('layout') == 'mirror':
              dirname = target.get_subdir()
          else:
              dirname = 'meson-out'
          return dirname
  
      def get_target_dir_relative_to(self, t, o):
          '''Get a target dir relative to another target's directory'''
          target_dir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(t))
          othert_dir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(o))
          return os.path.relpath(target_dir, othert_dir)
  
      def get_target_source_dir(self, target):
          # if target dir is empty, avoid extraneous trailing / from os.path.join()
          target_dir = self.get_target_dir(target)
          if target_dir:
              return os.path.join(self.build_to_src, target_dir)
          return self.build_to_src
  
      def get_target_private_dir(self, target):
          return os.path.join(self.get_target_dir(target), target.get_id())
  
      def get_target_private_dir_abs(self, target):
          return os.path.join(self.environment.get_build_dir(), self.get_target_private_dir(target))
  
      def get_target_generated_dir(self, target, gensrc, src):
          """
          Takes a BuildTarget, a generator source (CustomTarget or GeneratedList),
          and a generated source filename.
          Returns the full path of the generated source relative to the build root
          """
          # CustomTarget generators output to the build dir of the CustomTarget
          if isinstance(gensrc, (build.CustomTarget, build.CustomTargetIndex)):
              return os.path.join(self.get_target_dir(gensrc), src)
          # GeneratedList generators output to the private build directory of the
          # target that the GeneratedList is used in
          return os.path.join(self.get_target_private_dir(target), src)
  
      def get_unity_source_file(self, target, suffix):
          # There is a potential conflict here, but it is unlikely that
          # anyone both enables unity builds and has a file called foo-unity.cpp.
          osrc = target.name + '-unity.' + suffix
          return mesonlib.File.from_built_file(self.get_target_private_dir(target), osrc)
  
      def generate_unity_files(self, target, unity_src):
          abs_files = []
          result = []
          compsrcs = classify_unity_sources(target.compilers.values(), unity_src)
  
          def init_language_file(suffix):
              unity_src = self.get_unity_source_file(target, suffix)
              outfileabs = unity_src.absolute_path(self.environment.get_source_dir(),
                                                   self.environment.get_build_dir())
              outfileabs_tmp = outfileabs + '.tmp'
              abs_files.append(outfileabs)
              outfileabs_tmp_dir = os.path.dirname(outfileabs_tmp)
              if not os.path.exists(outfileabs_tmp_dir):
                  os.makedirs(outfileabs_tmp_dir)
              result.append(unity_src)
              return open(outfileabs_tmp, 'w')
  
          # For each language, generate a unity source file and return the list
          for comp, srcs in compsrcs.items():
              with init_language_file(comp.get_default_suffix()) as ofile:
                  for src in srcs:
                      ofile.write('#include<%s>\n' % src)
          [mesonlib.replace_if_different(x, x + '.tmp') for x in abs_files]
          return result
  
      def relpath(self, todir, fromdir):
          return os.path.relpath(os.path.join('dummyprefixdir', todir),
                                 os.path.join('dummyprefixdir', fromdir))
  
      def flatten_object_list(self, target, proj_dir_to_build_root=''):
          return self._flatten_object_list(target, target.get_objects(), proj_dir_to_build_root)
  
      def _flatten_object_list(self, target, objects, proj_dir_to_build_root):
          obj_list = []
          for obj in objects:
              if isinstance(obj, str):
                  o = os.path.join(proj_dir_to_build_root,
                                   self.build_to_src, target.get_subdir(), obj)
                  obj_list.append(o)
              elif isinstance(obj, mesonlib.File):
                  obj_list.append(obj.rel_to_builddir(self.build_to_src))
              elif isinstance(obj, build.ExtractedObjects):
                  if obj.recursive:
                      obj_list += self._flatten_object_list(obj.target, obj.objlist, proj_dir_to_build_root)
                  obj_list += self.determine_ext_objs(obj, proj_dir_to_build_root)
              else:
                  raise MesonException('Unknown data type in object list.')
          return obj_list
  
      def serialize_executable(self, exe, cmd_args, workdir, env={},
                               extra_paths=None, capture=None):
          import hashlib
          if extra_paths is None:
              # The callee didn't check if we needed extra paths, so check it here
              if mesonlib.is_windows() or mesonlib.is_cygwin():
                  extra_paths = self.determine_windows_extra_paths(exe, [])
              else:
                  extra_paths = []
          # Can't just use exe.name here; it will likely be run more than once
          if isinstance(exe, (dependencies.ExternalProgram,
                              build.BuildTarget, build.CustomTarget)):
              basename = exe.name
          else:
              basename = os.path.basename(exe)
          # Take a digest of the cmd args, env, workdir, and capture. This avoids
          # collisions and also makes the name deterministic over regenerations
          # which avoids a rebuild by Ninja because the cmdline stays the same.
          data = bytes(str(sorted(env.items())) + str(cmd_args) + str(workdir) + str(capture),
                       encoding='utf-8')
          digest = hashlib.sha1(data).hexdigest()
          scratch_file = 'meson_exe_{0}_{1}.dat'.format(basename, digest)
          exe_data = os.path.join(self.environment.get_scratch_dir(), scratch_file)
          with open(exe_data, 'wb') as f:
              if isinstance(exe, dependencies.ExternalProgram):
                  exe_cmd = exe.get_command()
                  exe_needs_wrapper = False
              elif isinstance(exe, (build.BuildTarget, build.CustomTarget)):
                  exe_cmd = [self.get_target_filename_abs(exe)]
                  exe_needs_wrapper = exe.is_cross
              else:
                  exe_cmd = [exe]
                  exe_needs_wrapper = False
              is_cross_built = exe_needs_wrapper and \
                  self.environment.is_cross_build() and \
                  self.environment.cross_info.need_cross_compiler() and \
                  self.environment.cross_info.need_exe_wrapper()
              if is_cross_built:
                  exe_wrapper = self.environment.cross_info.config['binaries'].get('exe_wrapper', None)
              else:
                  exe_wrapper = None
              es = ExecutableSerialisation(basename, exe_cmd, cmd_args, env,
                                           is_cross_built, exe_wrapper, workdir,
                                           extra_paths, capture)
              pickle.dump(es, f)
          return exe_data
  
      def serialize_tests(self):
          test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat')
          with open(test_data, 'wb') as datafile:
              self.write_test_file(datafile)
          benchmark_data = os.path.join(self.environment.get_scratch_dir(), 'meson_benchmark_setup.dat')
          with open(benchmark_data, 'wb') as datafile:
              self.write_benchmark_file(datafile)
          return test_data, benchmark_data
  
      def determine_linker_and_stdlib_args(self, target):
          '''
          If we're building a static library, there is only one static linker.
          Otherwise, we query the target for the dynamic linker.
          '''
          if isinstance(target, build.StaticLibrary):
              if target.is_cross:
                  return self.build.static_cross_linker, []
              else:
                  return self.build.static_linker, []
          l, stdlib_args = target.get_clike_dynamic_linker_and_stdlibs()
          return l, stdlib_args
  
      @staticmethod
      def _libdir_is_system(libdir, compilers):
          for cc in compilers.values():
              if libdir in cc.get_library_dirs():
                  return True
          return False
  
      def rpaths_for_bundled_shared_libraries(self, target, exclude_system=True):
          paths = []
          for dep in target.external_deps:
              if not isinstance(dep, (dependencies.ExternalLibrary, dependencies.PkgConfigDependency)):
                  continue
              la = dep.link_args
              if len(la) != 1 or not os.path.isabs(la[0]):
                  continue
              # The only link argument is an absolute path to a library file.
              libpath = la[0]
              libdir = os.path.dirname(libpath)
              if exclude_system and self._libdir_is_system(libdir, target.compilers):
                  # No point in adding system paths.
                  continue
              # Windows doesn't support rpaths, but we use this function to
              # emulate rpaths by setting PATH, so also accept DLLs here
              if os.path.splitext(libpath)[1] not in ['.dll', '.lib', '.so', '.dylib']:
                  continue
              if libdir.startswith(self.environment.get_source_dir()):
                  rel_to_src = libdir[len(self.environment.get_source_dir()) + 1:]
                  assert not os.path.isabs(rel_to_src), 'rel_to_src: {} is absolute'.format(rel_to_src)
                  paths.append(os.path.join(self.build_to_src, rel_to_src))
              else:
                  paths.append(libdir)
          return paths
  
      def determine_rpath_dirs(self, target):
          link_deps = target.get_all_link_deps()
          result = set()
          for ld in link_deps:
              if ld is target:
                  continue
              result.add(self.get_target_dir(ld))
          result.update(self.rpaths_for_bundled_shared_libraries(target))
          return list(result)
  
      def object_filename_from_source(self, target, source):
          assert isinstance(source, mesonlib.File)
          build_dir = self.environment.get_build_dir()
          rel_src = source.rel_to_builddir(self.build_to_src)
  
          # foo.vala files compile down to foo.c and then foo.c.o, not foo.vala.o
          if rel_src.endswith(('.vala', '.gs')):
              # See description in generate_vala_compile for this logic.
              if source.is_built:
                  if os.path.isabs(rel_src):
                      rel_src = rel_src[len(build_dir) + 1:]
                  rel_src = os.path.relpath(rel_src, self.get_target_private_dir(target))
              else:
                  rel_src = os.path.basename(rel_src)
              # A meson- prefixed directory is reserved; hopefully no-one creates a file name with such a weird prefix.
              source = 'meson-generated_' + rel_src[:-5] + '.c'
          elif source.is_built:
              if os.path.isabs(rel_src):
                  rel_src = rel_src[len(build_dir) + 1:]
              targetdir = self.get_target_private_dir(target)
              # A meson- prefixed directory is reserved; hopefully no-one creates a file name with such a weird prefix.
              source = 'meson-generated_' + os.path.relpath(rel_src, targetdir)
          else:
              if os.path.isabs(rel_src):
                  # Not from the source directory; hopefully this doesn't conflict with user's source files.
                  source = os.path.basename(rel_src)
              else:
                  source = os.path.relpath(os.path.join(build_dir, rel_src),
                                           os.path.join(self.environment.get_source_dir(), target.get_subdir()))
          return source.replace('/', '_').replace('\\', '_') + '.' + self.environment.get_object_suffix()
  
      def determine_ext_objs(self, extobj, proj_dir_to_build_root):
          result = []
  
          # Merge sources and generated sources
          sources = list(extobj.srclist)
          for gensrc in extobj.genlist:
              for s in gensrc.get_outputs():
                  path = self.get_target_generated_dir(extobj.target, gensrc, s)
                  dirpart, fnamepart = os.path.split(path)
                  sources.append(File(True, dirpart, fnamepart))
  
          # Filter out headers and all non-source files
          sources = [s for s in sources if self.environment.is_source(s) and not self.environment.is_header(s)]
  
          # extobj could contain only objects and no sources
          if not sources:
              return result
  
          targetdir = self.get_target_private_dir(extobj.target)
  
          # With unity builds, there's just one object that contains all the
         
  
  [... the rest is omitted ...]
files.old_path: mesonbuild/backend/backends.py
files.new_contents: # Copyright 2012-2017 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 copy, os, re
  from collections import OrderedDict
  import itertools, pathlib
  import pickle
  
  from . import environment
  from . import dependencies
  from . import mlog
  from .mesonlib import File, MesonException, listify, extract_as_list
  from .mesonlib import typeslistify, stringlistify, classify_unity_sources
  from .mesonlib import get_filenames_templates_dict, substitute_values
  from .mesonlib import for_windows, for_darwin, for_cygwin, for_android, has_path_sep
  from .compilers import is_object, clink_langs, sort_clink, lang_suffixes
  from .interpreterbase import FeatureNew, FeatureNewKwargs
  
  pch_kwargs = set(['c_pch', 'cpp_pch'])
  
  lang_arg_kwargs = set([
      'c_args',
      'cpp_args',
      'd_args',
      'd_import_dirs',
      'd_unittest',
      'd_module_versions',
      'fortran_args',
      'java_args',
      'objc_args',
      'objcpp_args',
      'rust_args',
      'vala_args',
      'cs_args',
  ])
  
  vala_kwargs = set(['vala_header', 'vala_gir', 'vala_vapi'])
  rust_kwargs = set(['rust_crate_type'])
  cs_kwargs = set(['resources', 'cs_args'])
  
  buildtarget_kwargs = set([
      'build_by_default',
      'build_rpath',
      'dependencies',
      'extra_files',
      'gui_app',
      'link_with',
      'link_whole',
      'link_args',
      'link_depends',
      'implicit_include_directories',
      'include_directories',
      'install',
      'install_rpath',
      'install_dir',
      'install_mode',
      'name_prefix',
      'name_suffix',
      'native',
      'objects',
      'override_options',
      'sources',
  ])
  
  known_build_target_kwargs = (
      buildtarget_kwargs |
      lang_arg_kwargs |
      pch_kwargs |
      vala_kwargs |
      rust_kwargs |
      cs_kwargs)
  
  known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic'}
  known_shlib_kwargs = known_build_target_kwargs | {'version', 'soversion', 'vs_module_defs'}
  known_shmod_kwargs = known_build_target_kwargs
  known_stlib_kwargs = known_build_target_kwargs | {'pic'}
  known_jar_kwargs = known_exe_kwargs | {'main_class'}
  
  class InvalidArguments(MesonException):
      pass
  
  class Build:
      """A class that holds the status of one build including
      all dependencies and so on.
      """
  
      def __init__(self, environment):
          self.project_name = 'name of master project'
          self.project_version = None
          self.environment = environment
          self.projects = {}
          self.targets = OrderedDict()
          self.compilers = OrderedDict()
          self.cross_compilers = OrderedDict()
          self.global_args = {}
          self.projects_args = {}
          self.global_link_args = {}
          self.projects_link_args = {}
          self.tests = []
          self.benchmarks = []
          self.headers = []
          self.man = []
          self.data = []
          self.static_linker = None
          self.static_cross_linker = None
          self.subprojects = {}
          self.subproject_dir = ''
          self.install_scripts = []
          self.postconf_scripts = []
          self.install_dirs = []
          self.dep_manifest_name = None
          self.dep_manifest = {}
          self.cross_stdlibs = {}
          self.test_setups = {}
          self.find_overrides = {}
          self.searched_programs = set() # The list of all programs that have been searched for.
  
      def add_compiler(self, compiler):
          if self.static_linker is None and compiler.needs_static_linker():
              self.static_linker = self.environment.detect_static_linker(compiler)
          lang = compiler.get_language()
          if lang not in self.compilers:
              self.compilers[lang] = compiler
  
      def add_cross_compiler(self, compiler):
          if not self.cross_compilers:
              self.static_cross_linker = self.environment.detect_static_linker(compiler)
          lang = compiler.get_language()
          if lang not in self.cross_compilers:
              self.cross_compilers[lang] = compiler
  
      def get_project(self):
          return self.projects['']
  
      def get_subproject_dir(self):
          return self.subproject_dir
  
      def get_targets(self):
          return self.targets
  
      def get_tests(self):
          return self.tests
  
      def get_benchmarks(self):
          return self.benchmarks
  
      def get_headers(self):
          return self.headers
  
      def get_man(self):
          return self.man
  
      def get_data(self):
          return self.data
  
      def get_install_subdirs(self):
          return self.install_dirs
  
      def get_global_args(self, compiler):
          return self.global_args.get(compiler.get_language(), [])
  
      def get_project_args(self, compiler, project):
          args = self.projects_args.get(project)
          if not args:
              return []
          return args.get(compiler.get_language(), [])
  
      def get_global_link_args(self, compiler):
          return self.global_link_args.get(compiler.get_language(), [])
  
      def get_project_link_args(self, compiler, project):
          link_args = self.projects_link_args.get(project)
          if not link_args:
              return []
  
          return link_args.get(compiler.get_language(), [])
  
  class IncludeDirs:
      def __init__(self, curdir, dirs, is_system, extra_build_dirs=None):
          self.curdir = curdir
          self.incdirs = dirs
          self.is_system = is_system
          # Interpreter has validated that all given directories
          # actually exist.
          if extra_build_dirs is None:
              self.extra_build_dirs = []
          else:
              self.extra_build_dirs = extra_build_dirs
  
      def __repr__(self):
          r = '<{} {}/{}>'
          return r.format(self.__class__.__name__, self.curdir, self.incdirs)
  
      def get_curdir(self):
          return self.curdir
  
      def get_incdirs(self):
          return self.incdirs
  
      def get_extra_build_dirs(self):
          return self.extra_build_dirs
  
  class ExtractedObjects:
      '''
      Holds a list of sources for which the objects must be extracted
      '''
      def __init__(self, target, srclist=[], genlist=[], objlist=[], recursive=True):
          self.target = target
          self.recursive = recursive
          self.srclist = srclist
          self.genlist = genlist
          self.objlist = objlist
          if self.target.is_unity:
              self.check_unity_compatible()
  
      def __repr__(self):
          r = '<{0} {1!r}: {2}>'
          return r.format(self.__class__.__name__, self.target.name, self.srclist)
  
      def classify_all_sources(self, sources, generated_sources):
          # Merge sources and generated sources
          sources = list(sources)
          for gensrc in generated_sources:
              for s in gensrc.get_outputs():
                  # We cannot know the path where this source will be generated,
                  # but all we need here is the file extension to determine the
                  # compiler.
                  sources.append(s)
  
          # Filter out headers and all non-source files
          sources = [s for s in sources if environment.is_source(s) and not environment.is_header(s)]
  
          return classify_unity_sources(self.target.compilers.values(), sources)
  
      def check_unity_compatible(self):
          # Figure out if the extracted object list is compatible with a Unity
          # build. When we're doing a Unified build, we go through the sources,
          # and create a single source file from each subset of the sources that
          # can be compiled with a specific compiler. Then we create one object
          # from each unified source file. So for each compiler we can either
          # extra all its sources or none.
          cmpsrcs = self.classify_all_sources(self.target.sources, self.target.generated)
          extracted_cmpsrcs = self.classify_all_sources(self.srclist, self.genlist)
  
          for comp, srcs in extracted_cmpsrcs.items():
              if set(srcs) != set(cmpsrcs[comp]):
                  raise MesonException('Single object files can not be extracted '
                                       'in Unity builds. You can only extract all '
                                       'the object files for each compiler at once.')
  
  class EnvironmentVariables:
      def __init__(self):
          self.envvars = []
  
      def __repr__(self):
          repr_str = "<{0}: {1}>"
          return repr_str.format(self.__class__.__name__, self.envvars)
  
      def get_value(self, values, kwargs):
          separator = kwargs.get('separator', os.pathsep)
  
          value = ''
          for var in values:
              value += separator + var
          return separator, value.strip(separator)
  
      def set(self, env, name, values, kwargs):
          return self.get_value(values, kwargs)[1]
  
      def append(self, env, name, values, kwargs):
          sep, value = self.get_value(values, kwargs)
          if name in env:
              return env[name] + sep + value
          return value
  
      def prepend(self, env, name, values, kwargs):
          sep, value = self.get_value(values, kwargs)
          if name in env:
              return value + sep + env[name]
  
          return value
  
      def get_env(self, full_env):
          env = full_env.copy()
          for method, name, values, kwargs in self.envvars:
              env[name] = method(full_env, name, values, kwargs)
          return env
  
  class Target:
      def __init__(self, name, subdir, subproject, build_by_default):
          if has_path_sep(name):
              # Fix failing test 53 when this becomes an error.
              mlog.warning('''Target "%s" has a path separator in its name.
  This is not supported, it can cause unexpected failures and will become
  a hard error in the future.''' % name)
          self.name = name
          self.subdir = subdir
          self.subproject = subproject
          self.build_by_default = build_by_default
          self.install = False
          self.build_always_stale = False
          self.option_overrides = {}
  
      def get_basename(self):
          return self.name
  
      def get_subdir(self):
          return self.subdir
  
      def get_id(self):
          # This ID must also be a valid file name on all OSs.
          # It should also avoid shell metacharacters for obvious
          # reasons. '@' is not used as often as '_' in source code names.
          # In case of collisions consider using checksums.
          # FIXME replace with assert when slash in names is prohibited
          name_part = self.name.replace('/', '@').replace('\\', '@')
          assert not has_path_sep(self.type_suffix())
          myid = name_part + self.type_suffix()
          if self.subdir:
              subdir_part = self.subdir.replace('/', '@').replace('\\', '@')
              myid = subdir_part + '@@' + myid
          return myid
  
      @FeatureNewKwargs('build target', '0.42.0', ['rust_crate_type', 'build_rpath', 'implicit_include_directories'])
      @FeatureNewKwargs('build target', '0.41.0', ['rust_args'])
      @FeatureNewKwargs('build target', '0.40.0', ['build_by_default'])
      def process_kwargs(self, kwargs):
          if 'build_by_default' in kwargs:
              self.build_by_default = kwargs['build_by_default']
              if not isinstance(self.build_by_default, bool):
                  raise InvalidArguments('build_by_default must be a boolean value.')
          self.option_overrides = self.parse_overrides(kwargs)
  
      def parse_overrides(self, kwargs):
          result = {}
          overrides = stringlistify(kwargs.get('override_options', []))
          for o in overrides:
              if '=' not in o:
                  raise InvalidArguments('Overrides must be of form "key=value"')
              k, v = o.split('=', 1)
              k = k.strip()
              v = v.strip()
              result[k] = v
          return result
  
  
  class BuildTarget(Target):
      known_kwargs = known_build_target_kwargs
  
      def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
          super().__init__(name, subdir, subproject, True)
          self.is_cross = is_cross
          unity_opt = environment.coredata.get_builtin_option('unity')
          self.is_unity = unity_opt == 'on' or (unity_opt == 'subprojects' and subproject != '')
          self.environment = environment
          self.sources = []
          self.compilers = OrderedDict()
          self.objects = []
          self.external_deps = []
          self.include_dirs = []
          self.link_targets = []
          self.link_whole_targets = []
          self.link_depends = []
          self.name_prefix_set = False
          self.name_suffix_set = False
          self.filename = 'no_name'
          # The list of all files outputted by this target. Useful in cases such
          # as Vala which generates .vapi and .h besides the compiled output.
          self.outputs = [self.filename]
          self.need_install = False
          self.pch = {}
          self.extra_args = {}
          self.generated = []
          self.extra_files = []
          self.d_features = {}
          # Sources can be:
          # 1. Pre-existing source files in the source tree
          # 2. Pre-existing sources generated by configure_file in the build tree
          # 3. Sources files generated by another target or a Generator
          self.process_sourcelist(sources)
          # Objects can be:
          # 1. Pre-existing objects provided by the user with the `objects:` kwarg
          # 2. Compiled objects created by and extracted from another target
          self.process_objectlist(objects)
          self.process_kwargs(kwargs, environment)
          self.check_unknown_kwargs(kwargs)
          self.process_compilers()
          if not any([self.sources, self.generated, self.objects, self.link_whole]):
              raise InvalidArguments('Build target %s has no sources.' % name)
          self.process_compilers_late()
          self.validate_sources()
          self.validate_cross_install(environment)
          self.check_module_linking()
  
      def __lt__(self, other):
          return self.get_id() < other.get_id()
  
      def __repr__(self):
          repr_str = "<{0} {1}: {2}>"
          return repr_str.format(self.__class__.__name__, self.get_id(), self.filename)
  
      def validate_cross_install(self, environment):
          if environment.is_cross_build() and not self.is_cross and self.install:
              raise InvalidArguments('Tried to install a natively built target in a cross build.')
  
      def check_unknown_kwargs(self, kwargs):
          # Override this method in derived classes that have more
          # keywords.
          self.check_unknown_kwargs_int(kwargs, self.known_kwargs)
  
      def check_unknown_kwargs_int(self, kwargs, known_kwargs):
          unknowns = []
          for k in kwargs:
              if k not in known_kwargs:
                  unknowns.append(k)
          if len(unknowns) > 0:
              mlog.warning('Unknown keyword argument(s) in target %s: %s.' %
                           (self.name, ', '.join(unknowns)))
  
      def process_objectlist(self, objects):
          assert(isinstance(objects, list))
          for s in objects:
              if hasattr(s, 'held_object'):
                  s = s.held_object
              if isinstance(s, (str, File, ExtractedObjects)):
                  self.objects.append(s)
              elif isinstance(s, (GeneratedList, CustomTarget)):
                  msg = 'Generated files are not allowed in the \'objects\' kwarg ' + \
                      'for target {!r}.\nIt is meant only for '.format(self.name) + \
                      'pre-built object files that are shipped with the\nsource ' + \
                      'tree. Try adding it in the list of sources.'
                  raise InvalidArguments(msg)
              else:
                  msg = 'Bad object of type {!r} in target {!r}.'.format(type(s).__name__, self.name)
                  raise InvalidArguments(msg)
  
      def process_sourcelist(self, sources):
          sources = listify(sources)
          added_sources = {} # If the same source is defined multiple times, use it only once.
          for s in sources:
              # Holder unpacking. Ugly.
              if hasattr(s, 'held_object'):
                  s = s.held_object
              if isinstance(s, File):
                  if s not in added_sources:
                      self.sources.append(s)
                      added_sources[s] = True
              elif isinstance(s, (GeneratedList, CustomTarget, CustomTargetIndex)):
                  self.generated.append(s)
              else:
                  msg = 'Bad source of type {!r} in target {!r}.'.format(type(s).__name__, self.name)
                  raise InvalidArguments(msg)
  
      @staticmethod
      def can_compile_remove_sources(compiler, sources):
          removed = False
          for s in sources[:]:
              if compiler.can_compile(s):
                  sources.remove(s)
                  removed = True
          return removed
  
      def process_compilers_late(self):
          """Processes additional compilers after kwargs have been evaluated.
  
          This can add extra compilers that might be required by keyword
          arguments, such as link_with or dependencies. It will also try to guess
          which compiler to use if one hasn't been selected already.
          """
          # Populate list of compilers
          if self.is_cross:
              compilers = self.environment.coredata.cross_compilers
          else:
              compilers = self.environment.coredata.compilers
  
          # If this library is linked against another library we need to consider
          # the languages of those libraries as well.
          if self.link_targets or self.link_whole_targets:
              extra = set()
              for t in itertools.chain(self.link_targets, self.link_whole_targets):
                  for name, compiler in t.compilers.items():
                      if name in clink_langs:
                          extra.add((name, compiler))
              for name, compiler in sorted(extra, key=lambda p: sort_clink(p[0])):
                  self.compilers[name] = compiler
  
          if not self.compilers:
              # No source files or parent targets, target consists of only object
              # files of unknown origin. Just add the first clink compiler
              # that we have and hope that it can link these objects
              for lang in clink_langs:
                  if lang in compilers:
                      self.compilers[lang] = compilers[lang]
                      break
  
      def process_compilers(self):
          '''
          Populate self.compilers, which is the list of compilers that this
          target will use for compiling all its sources.
          We also add compilers that were used by extracted objects to simplify
          dynamic linker determination.
          '''
          if not self.sources and not self.generated and not self.objects:
              return
          # Populate list of compilers
          if self.is_cross:
              compilers = self.environment.coredata.cross_compilers
  
  [... the rest is omitted ...]
files.new_path: mesonbuild/build.py
files.old_contents: # Copyright 2012-2017 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 copy, os, re
  from collections import OrderedDict
  import itertools, pathlib
  import pickle
  
  from . import environment
  from . import dependencies
  from . import mlog
  from .mesonlib import File, MesonException, listify, extract_as_list
  from .mesonlib import typeslistify, stringlistify, classify_unity_sources
  from .mesonlib import get_filenames_templates_dict, substitute_values
  from .mesonlib import for_windows, for_darwin, for_cygwin, for_android, has_path_sep
  from .compilers import is_object, clike_langs, sort_clike, lang_suffixes
  from .interpreterbase import FeatureNew, FeatureNewKwargs
  
  pch_kwargs = set(['c_pch', 'cpp_pch'])
  
  lang_arg_kwargs = set([
      'c_args',
      'cpp_args',
      'd_args',
      'd_import_dirs',
      'd_unittest',
      'd_module_versions',
      'fortran_args',
      'java_args',
      'objc_args',
      'objcpp_args',
      'rust_args',
      'vala_args',
      'cs_args',
  ])
  
  vala_kwargs = set(['vala_header', 'vala_gir', 'vala_vapi'])
  rust_kwargs = set(['rust_crate_type'])
  cs_kwargs = set(['resources', 'cs_args'])
  
  buildtarget_kwargs = set([
      'build_by_default',
      'build_rpath',
      'dependencies',
      'extra_files',
      'gui_app',
      'link_with',
      'link_whole',
      'link_args',
      'link_depends',
      'implicit_include_directories',
      'include_directories',
      'install',
      'install_rpath',
      'install_dir',
      'install_mode',
      'name_prefix',
      'name_suffix',
      'native',
      'objects',
      'override_options',
      'sources',
  ])
  
  known_build_target_kwargs = (
      buildtarget_kwargs |
      lang_arg_kwargs |
      pch_kwargs |
      vala_kwargs |
      rust_kwargs |
      cs_kwargs)
  
  known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic'}
  known_shlib_kwargs = known_build_target_kwargs | {'version', 'soversion', 'vs_module_defs'}
  known_shmod_kwargs = known_build_target_kwargs
  known_stlib_kwargs = known_build_target_kwargs | {'pic'}
  known_jar_kwargs = known_exe_kwargs | {'main_class'}
  
  class InvalidArguments(MesonException):
      pass
  
  class Build:
      """A class that holds the status of one build including
      all dependencies and so on.
      """
  
      def __init__(self, environment):
          self.project_name = 'name of master project'
          self.project_version = None
          self.environment = environment
          self.projects = {}
          self.targets = OrderedDict()
          self.compilers = OrderedDict()
          self.cross_compilers = OrderedDict()
          self.global_args = {}
          self.projects_args = {}
          self.global_link_args = {}
          self.projects_link_args = {}
          self.tests = []
          self.benchmarks = []
          self.headers = []
          self.man = []
          self.data = []
          self.static_linker = None
          self.static_cross_linker = None
          self.subprojects = {}
          self.subproject_dir = ''
          self.install_scripts = []
          self.postconf_scripts = []
          self.install_dirs = []
          self.dep_manifest_name = None
          self.dep_manifest = {}
          self.cross_stdlibs = {}
          self.test_setups = {}
          self.find_overrides = {}
          self.searched_programs = set() # The list of all programs that have been searched for.
  
      def add_compiler(self, compiler):
          if self.static_linker is None and compiler.needs_static_linker():
              self.static_linker = self.environment.detect_static_linker(compiler)
          lang = compiler.get_language()
          if lang not in self.compilers:
              self.compilers[lang] = compiler
  
      def add_cross_compiler(self, compiler):
          if not self.cross_compilers:
              self.static_cross_linker = self.environment.detect_static_linker(compiler)
          lang = compiler.get_language()
          if lang not in self.cross_compilers:
              self.cross_compilers[lang] = compiler
  
      def get_project(self):
          return self.projects['']
  
      def get_subproject_dir(self):
          return self.subproject_dir
  
      def get_targets(self):
          return self.targets
  
      def get_tests(self):
          return self.tests
  
      def get_benchmarks(self):
          return self.benchmarks
  
      def get_headers(self):
          return self.headers
  
      def get_man(self):
          return self.man
  
      def get_data(self):
          return self.data
  
      def get_install_subdirs(self):
          return self.install_dirs
  
      def get_global_args(self, compiler):
          return self.global_args.get(compiler.get_language(), [])
  
      def get_project_args(self, compiler, project):
          args = self.projects_args.get(project)
          if not args:
              return []
          return args.get(compiler.get_language(), [])
  
      def get_global_link_args(self, compiler):
          return self.global_link_args.get(compiler.get_language(), [])
  
      def get_project_link_args(self, compiler, project):
          link_args = self.projects_link_args.get(project)
          if not link_args:
              return []
  
          return link_args.get(compiler.get_language(), [])
  
  class IncludeDirs:
      def __init__(self, curdir, dirs, is_system, extra_build_dirs=None):
          self.curdir = curdir
          self.incdirs = dirs
          self.is_system = is_system
          # Interpreter has validated that all given directories
          # actually exist.
          if extra_build_dirs is None:
              self.extra_build_dirs = []
          else:
              self.extra_build_dirs = extra_build_dirs
  
      def __repr__(self):
          r = '<{} {}/{}>'
          return r.format(self.__class__.__name__, self.curdir, self.incdirs)
  
      def get_curdir(self):
          return self.curdir
  
      def get_incdirs(self):
          return self.incdirs
  
      def get_extra_build_dirs(self):
          return self.extra_build_dirs
  
  class ExtractedObjects:
      '''
      Holds a list of sources for which the objects must be extracted
      '''
      def __init__(self, target, srclist=[], genlist=[], objlist=[], recursive=True):
          self.target = target
          self.recursive = recursive
          self.srclist = srclist
          self.genlist = genlist
          self.objlist = objlist
          if self.target.is_unity:
              self.check_unity_compatible()
  
      def __repr__(self):
          r = '<{0} {1!r}: {2}>'
          return r.format(self.__class__.__name__, self.target.name, self.srclist)
  
      def classify_all_sources(self, sources, generated_sources):
          # Merge sources and generated sources
          sources = list(sources)
          for gensrc in generated_sources:
              for s in gensrc.get_outputs():
                  # We cannot know the path where this source will be generated,
                  # but all we need here is the file extension to determine the
                  # compiler.
                  sources.append(s)
  
          # Filter out headers and all non-source files
          sources = [s for s in sources if environment.is_source(s) and not environment.is_header(s)]
  
          return classify_unity_sources(self.target.compilers.values(), sources)
  
      def check_unity_compatible(self):
          # Figure out if the extracted object list is compatible with a Unity
          # build. When we're doing a Unified build, we go through the sources,
          # and create a single source file from each subset of the sources that
          # can be compiled with a specific compiler. Then we create one object
          # from each unified source file. So for each compiler we can either
          # extra all its sources or none.
          cmpsrcs = self.classify_all_sources(self.target.sources, self.target.generated)
          extracted_cmpsrcs = self.classify_all_sources(self.srclist, self.genlist)
  
          for comp, srcs in extracted_cmpsrcs.items():
              if set(srcs) != set(cmpsrcs[comp]):
                  raise MesonException('Single object files can not be extracted '
                                       'in Unity builds. You can only extract all '
                                       'the object files for each compiler at once.')
  
  class EnvironmentVariables:
      def __init__(self):
          self.envvars = []
  
      def __repr__(self):
          repr_str = "<{0}: {1}>"
          return repr_str.format(self.__class__.__name__, self.envvars)
  
      def get_value(self, values, kwargs):
          separator = kwargs.get('separator', os.pathsep)
  
          value = ''
          for var in values:
              value += separator + var
          return separator, value.strip(separator)
  
      def set(self, env, name, values, kwargs):
          return self.get_value(values, kwargs)[1]
  
      def append(self, env, name, values, kwargs):
          sep, value = self.get_value(values, kwargs)
          if name in env:
              return env[name] + sep + value
          return value
  
      def prepend(self, env, name, values, kwargs):
          sep, value = self.get_value(values, kwargs)
          if name in env:
              return value + sep + env[name]
  
          return value
  
      def get_env(self, full_env):
          env = full_env.copy()
          for method, name, values, kwargs in self.envvars:
              env[name] = method(full_env, name, values, kwargs)
          return env
  
  class Target:
      def __init__(self, name, subdir, subproject, build_by_default):
          if has_path_sep(name):
              # Fix failing test 53 when this becomes an error.
              mlog.warning('''Target "%s" has a path separator in its name.
  This is not supported, it can cause unexpected failures and will become
  a hard error in the future.''' % name)
          self.name = name
          self.subdir = subdir
          self.subproject = subproject
          self.build_by_default = build_by_default
          self.install = False
          self.build_always_stale = False
          self.option_overrides = {}
  
      def get_basename(self):
          return self.name
  
      def get_subdir(self):
          return self.subdir
  
      def get_id(self):
          # This ID must also be a valid file name on all OSs.
          # It should also avoid shell metacharacters for obvious
          # reasons. '@' is not used as often as '_' in source code names.
          # In case of collisions consider using checksums.
          # FIXME replace with assert when slash in names is prohibited
          name_part = self.name.replace('/', '@').replace('\\', '@')
          assert not has_path_sep(self.type_suffix())
          myid = name_part + self.type_suffix()
          if self.subdir:
              subdir_part = self.subdir.replace('/', '@').replace('\\', '@')
              myid = subdir_part + '@@' + myid
          return myid
  
      @FeatureNewKwargs('build target', '0.42.0', ['rust_crate_type', 'build_rpath', 'implicit_include_directories'])
      @FeatureNewKwargs('build target', '0.41.0', ['rust_args'])
      @FeatureNewKwargs('build target', '0.40.0', ['build_by_default'])
      def process_kwargs(self, kwargs):
          if 'build_by_default' in kwargs:
              self.build_by_default = kwargs['build_by_default']
              if not isinstance(self.build_by_default, bool):
                  raise InvalidArguments('build_by_default must be a boolean value.')
          self.option_overrides = self.parse_overrides(kwargs)
  
      def parse_overrides(self, kwargs):
          result = {}
          overrides = stringlistify(kwargs.get('override_options', []))
          for o in overrides:
              if '=' not in o:
                  raise InvalidArguments('Overrides must be of form "key=value"')
              k, v = o.split('=', 1)
              k = k.strip()
              v = v.strip()
              result[k] = v
          return result
  
  
  class BuildTarget(Target):
      known_kwargs = known_build_target_kwargs
  
      def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
          super().__init__(name, subdir, subproject, True)
          self.is_cross = is_cross
          unity_opt = environment.coredata.get_builtin_option('unity')
          self.is_unity = unity_opt == 'on' or (unity_opt == 'subprojects' and subproject != '')
          self.environment = environment
          self.sources = []
          self.compilers = OrderedDict()
          self.objects = []
          self.external_deps = []
          self.include_dirs = []
          self.link_targets = []
          self.link_whole_targets = []
          self.link_depends = []
          self.name_prefix_set = False
          self.name_suffix_set = False
          self.filename = 'no_name'
          # The list of all files outputted by this target. Useful in cases such
          # as Vala which generates .vapi and .h besides the compiled output.
          self.outputs = [self.filename]
          self.need_install = False
          self.pch = {}
          self.extra_args = {}
          self.generated = []
          self.extra_files = []
          self.d_features = {}
          # Sources can be:
          # 1. Pre-existing source files in the source tree
          # 2. Pre-existing sources generated by configure_file in the build tree
          # 3. Sources files generated by another target or a Generator
          self.process_sourcelist(sources)
          # Objects can be:
          # 1. Pre-existing objects provided by the user with the `objects:` kwarg
          # 2. Compiled objects created by and extracted from another target
          self.process_objectlist(objects)
          self.process_kwargs(kwargs, environment)
          self.check_unknown_kwargs(kwargs)
          self.process_compilers()
          if not any([self.sources, self.generated, self.objects, self.link_whole]):
              raise InvalidArguments('Build target %s has no sources.' % name)
          self.process_compilers_late()
          self.validate_sources()
          self.validate_cross_install(environment)
          self.check_module_linking()
  
      def __lt__(self, other):
          return self.get_id() < other.get_id()
  
      def __repr__(self):
          repr_str = "<{0} {1}: {2}>"
          return repr_str.format(self.__class__.__name__, self.get_id(), self.filename)
  
      def validate_cross_install(self, environment):
          if environment.is_cross_build() and not self.is_cross and self.install:
              raise InvalidArguments('Tried to install a natively built target in a cross build.')
  
      def check_unknown_kwargs(self, kwargs):
          # Override this method in derived classes that have more
          # keywords.
          self.check_unknown_kwargs_int(kwargs, self.known_kwargs)
  
      def check_unknown_kwargs_int(self, kwargs, known_kwargs):
          unknowns = []
          for k in kwargs:
              if k not in known_kwargs:
                  unknowns.append(k)
          if len(unknowns) > 0:
              mlog.warning('Unknown keyword argument(s) in target %s: %s.' %
                           (self.name, ', '.join(unknowns)))
  
      def process_objectlist(self, objects):
          assert(isinstance(objects, list))
          for s in objects:
              if hasattr(s, 'held_object'):
                  s = s.held_object
              if isinstance(s, (str, File, ExtractedObjects)):
                  self.objects.append(s)
              elif isinstance(s, (GeneratedList, CustomTarget)):
                  msg = 'Generated files are not allowed in the \'objects\' kwarg ' + \
                      'for target {!r}.\nIt is meant only for '.format(self.name) + \
                      'pre-built object files that are shipped with the\nsource ' + \
                      'tree. Try adding it in the list of sources.'
                  raise InvalidArguments(msg)
              else:
                  msg = 'Bad object of type {!r} in target {!r}.'.format(type(s).__name__, self.name)
                  raise InvalidArguments(msg)
  
      def process_sourcelist(self, sources):
          sources = listify(sources)
          added_sources = {} # If the same source is defined multiple times, use it only once.
          for s in sources:
              # Holder unpacking. Ugly.
              if hasattr(s, 'held_object'):
                  s = s.held_object
              if isinstance(s, File):
                  if s not in added_sources:
                      self.sources.append(s)
                      added_sources[s] = True
              elif isinstance(s, (GeneratedList, CustomTarget, CustomTargetIndex)):
                  self.generated.append(s)
              else:
                  msg = 'Bad source of type {!r} in target {!r}.'.format(type(s).__name__, self.name)
                  raise InvalidArguments(msg)
  
      @staticmethod
      def can_compile_remove_sources(compiler, sources):
          removed = False
          for s in sources[:]:
              if compiler.can_compile(s):
                  sources.remove(s)
                  removed = True
          return removed
  
      def process_compilers_late(self):
          """Processes additional compilers after kwargs have been evaluated.
  
          This can add extra compilers that might be required by keyword
          arguments, such as link_with or dependencies. It will also try to guess
          which compiler to use if one hasn't been selected already.
          """
          # Populate list of compilers
          if self.is_cross:
              compilers = self.environment.coredata.cross_compilers
          else:
              compilers = self.environment.coredata.compilers
  
          # If this library is linked against another library we need to consider
          # the languages of those libraries as well.
          if self.link_targets or self.link_whole_targets:
              extra = set()
              for t in itertools.chain(self.link_targets, self.link_whole_targets):
                  for name, compiler in t.compilers.items():
                      if name in clike_langs:
                          extra.add((name, compiler))
              for name, compiler in sorted(extra, key=lambda p: sort_clike(p[0])):
                  self.compilers[name] = compiler
  
          if not self.compilers:
              # No source files or parent targets, target consists of only object
              # files of unknown origin. Just add the first clike compiler
              # that we have and hope that it can link these objects
              for lang in clike_langs:
                  if lang in compilers:
                      self.compilers[lang] = compilers[lang]
                      break
  
      def process_compilers(self):
          '''
          Populate self.compilers, which is the list of compilers that this
          target will use for compiling all its sources.
          We also add compilers that were used by extracted objects to simplify
          dynamic linker determination.
          '''
          if not self.sources and not self.generated and not self.objects:
              return
          # Populate list of compilers
          if self.is_cross:
              compilers = self.environment.coredata.cross_compilers
  
  [... the rest is omitted ...]
files.old_path: mesonbuild/build.py
files.new_contents: # Copyright 2017 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.
  
  # Public symbols for compilers sub-package when using 'from . import compilers'
  __all__ = [
      'CLANG_OSX',
      'CLANG_STANDARD',
      'CLANG_WIN',
      'GCC_CYGWIN',
      'GCC_MINGW',
      'GCC_OSX',
      'GCC_STANDARD',
      'ICC_OSX',
      'ICC_STANDARD',
      'ICC_WIN',
  
      'all_languages',
      'base_options',
      'clib_langs',
      'clink_langs',
      'c_suffixes',
      'cpp_suffixes',
      'get_macos_dylib_install_name',
      'get_base_compile_args',
      'get_base_link_args',
      'is_assembly',
      'is_header',
      'is_library',
      'is_llvm_ir',
      'is_object',
      'is_source',
      'lang_suffixes',
      'sanitizer_compile_args',
      'sort_clink',
  
      'ArmCCompiler',
      'ArmCPPCompiler',
      'CCompiler',
      'ClangCCompiler',
      'ClangCompiler',
      'ClangCPPCompiler',
      'ClangObjCCompiler',
      'ClangObjCPPCompiler',
      'CompilerArgs',
      'CPPCompiler',
      'DCompiler',
      'DmdDCompiler',
      'FortranCompiler',
      'G95FortranCompiler',
      'GnuCCompiler',
      'ElbrusCCompiler',
      'GnuCompiler',
      'GnuCPPCompiler',
      'ElbrusCPPCompiler',
      'GnuDCompiler',
      'GnuFortranCompiler',
      'ElbrusFortranCompiler',
      'GnuObjCCompiler',
      'GnuObjCPPCompiler',
      'IntelCompiler',
      'IntelCCompiler',
      'IntelCPPCompiler',
      'IntelFortranCompiler',
      'JavaCompiler',
      'LLVMDCompiler',
      'MonoCompiler',
      'VisualStudioCsCompiler',
      'NAGFortranCompiler',
      'ObjCCompiler',
      'ObjCPPCompiler',
      'Open64FortranCompiler',
      'PathScaleFortranCompiler',
      'PGIFortranCompiler',
      'RustCompiler',
      'SunFortranCompiler',
      'SwiftCompiler',
      'ValaCompiler',
      'VisualStudioCCompiler',
      'VisualStudioCPPCompiler',
  ]
  
  # Bring symbols from each module into compilers sub-package namespace
  from .compilers import (
      GCC_OSX,
      GCC_MINGW,
      GCC_CYGWIN,
      GCC_STANDARD,
      CLANG_OSX,
      CLANG_WIN,
      CLANG_STANDARD,
      ICC_OSX,
      ICC_WIN,
      ICC_STANDARD,
      all_languages,
      base_options,
      clib_langs,
      clink_langs,
      c_suffixes,
      cpp_suffixes,
      get_macos_dylib_install_name,
      get_base_compile_args,
      get_base_link_args,
      is_header,
      is_source,
      is_assembly,
      is_llvm_ir,
      is_object,
      is_library,
      lang_suffixes,
      sanitizer_compile_args,
      sort_clink,
      ClangCompiler,
      CompilerArgs,
      GnuCompiler,
      IntelCompiler,
  )
  from .c import (
      ArmCCompiler,
      CCompiler,
      ClangCCompiler,
      GnuCCompiler,
      ElbrusCCompiler,
      IntelCCompiler,
      VisualStudioCCompiler,
  )
  from .cpp import (
      ArmCPPCompiler,
      CPPCompiler,
      ClangCPPCompiler,
      GnuCPPCompiler,
      ElbrusCPPCompiler,
      IntelCPPCompiler,
      VisualStudioCPPCompiler,
  )
  from .cs import MonoCompiler, VisualStudioCsCompiler
  from .d import (
      DCompiler,
      DmdDCompiler,
      GnuDCompiler,
      LLVMDCompiler,
  )
  from .fortran import (
      FortranCompiler,
      G95FortranCompiler,
      GnuFortranCompiler,
      ElbrusFortranCompiler,
      IntelFortranCompiler,
      NAGFortranCompiler,
      Open64FortranCompiler,
      PathScaleFortranCompiler,
      PGIFortranCompiler,
      SunFortranCompiler,
  )
  from .java import JavaCompiler
  from .objc import (
      ObjCCompiler,
      ClangObjCCompiler,
      GnuObjCCompiler,
  )
  from .objcpp import (
      ObjCPPCompiler,
      ClangObjCPPCompiler,
      GnuObjCPPCompiler,
  )
  from .rust import RustCompiler
  from .swift import SwiftCompiler
  from .vala import ValaCompiler
  
  
  [... the rest is omitted ...]
files.new_path: mesonbuild/compilers/__init__.py
files.old_contents: # Copyright 2017 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.
  
  # Public symbols for compilers sub-package when using 'from . import compilers'
  __all__ = [
      'CLANG_OSX',
      'CLANG_STANDARD',
      'CLANG_WIN',
      'GCC_CYGWIN',
      'GCC_MINGW',
      'GCC_OSX',
      'GCC_STANDARD',
      'ICC_OSX',
      'ICC_STANDARD',
      'ICC_WIN',
  
      'all_languages',
      'base_options',
      'clib_langs',
      'clike_langs',
      'c_suffixes',
      'cpp_suffixes',
      'get_macos_dylib_install_name',
      'get_base_compile_args',
      'get_base_link_args',
      'is_assembly',
      'is_header',
      'is_library',
      'is_llvm_ir',
      'is_object',
      'is_source',
      'lang_suffixes',
      'sanitizer_compile_args',
      'sort_clike',
  
      'ArmCCompiler',
      'ArmCPPCompiler',
      'CCompiler',
      'ClangCCompiler',
      'ClangCompiler',
      'ClangCPPCompiler',
      'ClangObjCCompiler',
      'ClangObjCPPCompiler',
      'CompilerArgs',
      'CPPCompiler',
      'DCompiler',
      'DmdDCompiler',
      'FortranCompiler',
      'G95FortranCompiler',
      'GnuCCompiler',
      'ElbrusCCompiler',
      'GnuCompiler',
      'GnuCPPCompiler',
      'ElbrusCPPCompiler',
      'GnuDCompiler',
      'GnuFortranCompiler',
      'ElbrusFortranCompiler',
      'GnuObjCCompiler',
      'GnuObjCPPCompiler',
      'IntelCompiler',
      'IntelCCompiler',
      'IntelCPPCompiler',
      'IntelFortranCompiler',
      'JavaCompiler',
      'LLVMDCompiler',
      'MonoCompiler',
      'VisualStudioCsCompiler',
      'NAGFortranCompiler',
      'ObjCCompiler',
      'ObjCPPCompiler',
      'Open64FortranCompiler',
      'PathScaleFortranCompiler',
      'PGIFortranCompiler',
      'RustCompiler',
      'SunFortranCompiler',
      'SwiftCompiler',
      'ValaCompiler',
      'VisualStudioCCompiler',
      'VisualStudioCPPCompiler',
  ]
  
  # Bring symbols from each module into compilers sub-package namespace
  from .compilers import (
      GCC_OSX,
      GCC_MINGW,
      GCC_CYGWIN,
      GCC_STANDARD,
      CLANG_OSX,
      CLANG_WIN,
      CLANG_STANDARD,
      ICC_OSX,
      ICC_WIN,
      ICC_STANDARD,
      all_languages,
      base_options,
      clib_langs,
      clike_langs,
      c_suffixes,
      cpp_suffixes,
      get_macos_dylib_install_name,
      get_base_compile_args,
      get_base_link_args,
      is_header,
      is_source,
      is_assembly,
      is_llvm_ir,
      is_object,
      is_library,
      lang_suffixes,
      sanitizer_compile_args,
      sort_clike,
      ClangCompiler,
      CompilerArgs,
      GnuCompiler,
      IntelCompiler,
  )
  from .c import (
      ArmCCompiler,
      CCompiler,
      ClangCCompiler,
      GnuCCompiler,
      ElbrusCCompiler,
      IntelCCompiler,
      VisualStudioCCompiler,
  )
  from .cpp import (
      ArmCPPCompiler,
      CPPCompiler,
      ClangCPPCompiler,
      GnuCPPCompiler,
      ElbrusCPPCompiler,
      IntelCPPCompiler,
      VisualStudioCPPCompiler,
  )
  from .cs import MonoCompiler, VisualStudioCsCompiler
  from .d import (
      DCompiler,
      DmdDCompiler,
      GnuDCompiler,
      LLVMDCompiler,
  )
  from .fortran import (
      FortranCompiler,
      G95FortranCompiler,
      GnuFortranCompiler,
      ElbrusFortranCompiler,
      IntelFortranCompiler,
      NAGFortranCompiler,
      Open64FortranCompiler,
      PathScaleFortranCompiler,
      PGIFortranCompiler,
      SunFortranCompiler,
  )
  from .java import JavaCompiler
  from .objc import (
      ObjCCompiler,
      ClangObjCCompiler,
      GnuObjCCompiler,
  )
  from .objcpp import (
      ObjCPPCompiler,
      ClangObjCPPCompiler,
      GnuObjCPPCompiler,
  )
  from .rust import RustCompiler
  from .swift import SwiftCompiler
  from .vala import ValaCompiler
  
  
  [... the rest is omitted ...]
files.old_path: mesonbuild/compilers/__init__.py
files.new_contents: # Copyright 2012-2017 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 contextlib, os.path, re, tempfile, shlex
  import subprocess
  
  from ..linkers import StaticLinker
  from .. import coredata
  from .. import mlog
  from .. import mesonlib
  from ..mesonlib import EnvironmentException, MesonException, version_compare, Popen_safe
  
  """This file contains the data files of all compilers Meson knows
  about. To support a new compiler, add its information below.
  Also add corresponding autodetection code in environment.py."""
  
  header_suffixes = ('h', 'hh', 'hpp', 'hxx', 'H', 'ipp', 'moc', 'vapi', 'di')
  obj_suffixes = ('o', 'obj', 'res')
  lib_suffixes = ('a', 'lib', 'dll', 'dylib', 'so')
  # Mapping of language to suffixes of files that should always be in that language
  # This means we can't include .h headers here since they could be C, C++, ObjC, etc.
  lang_suffixes = {
      'c': ('c',),
      'cpp': ('cpp', 'cc', 'cxx', 'c++', 'hh', 'hpp', 'ipp', 'hxx'),
      # f90, f95, f03, f08 are for free-form fortran ('f90' recommended)
      # f, for, ftn, fpp are for fixed-form fortran ('f' or 'for' recommended)
      'fortran': ('f90', 'f95', 'f03', 'f08', 'f', 'for', 'ftn', 'fpp'),
      'd': ('d', 'di'),
      'objc': ('m',),
      'objcpp': ('mm',),
      'rust': ('rs',),
      'vala': ('vala', 'vapi', 'gs'),
      'cs': ('cs',),
      'swift': ('swift',),
      'java': ('java',),
  }
  all_languages = lang_suffixes.keys()
  cpp_suffixes = lang_suffixes['cpp'] + ('h',)
  c_suffixes = lang_suffixes['c'] + ('h',)
  # List of languages that by default consume and output libraries following the
  # C ABI; these can generally be used interchangebly
  clib_langs = ('objcpp', 'cpp', 'objc', 'c', 'fortran',)
  # List of languages that can be linked with C code directly by the linker
  # used in build.py:process_compilers() and build.py:get_dynamic_linker()
  # XXX: Add Rust to this?
  clink_langs = ('d',) + clib_langs
  clink_suffixes = ()
  for _l in clink_langs + ('vala',):
      clink_suffixes += lang_suffixes[_l]
  clink_suffixes += ('h', 'll', 's')
  
  soregex = re.compile(r'.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$')
  
  # Environment variables that each lang uses.
  cflags_mapping = {'c': 'CFLAGS',
                    'cpp': 'CXXFLAGS',
                    'objc': 'OBJCFLAGS',
                    'objcpp': 'OBJCXXFLAGS',
                    'fortran': 'FFLAGS',
                    'd': 'DFLAGS',
                    'vala': 'VALAFLAGS',
                    'rust': 'RUSTFLAGS'}
  
  # All these are only for C-linkable languages; see `clink_langs` above.
  
  def sort_clink(lang):
      '''
      Sorting function to sort the list of languages according to
      reversed(compilers.clink_langs) and append the unknown langs in the end.
      The purpose is to prefer C over C++ for files that can be compiled by
      both such as assembly, C, etc. Also applies to ObjC, ObjC++, etc.
      '''
      if lang not in clink_langs:
          return 1
      return -clink_langs.index(lang)
  
  def is_header(fname):
      if hasattr(fname, 'fname'):
          fname = fname.fname
      suffix = fname.split('.')[-1]
      return suffix in header_suffixes
  
  def is_source(fname):
      if hasattr(fname, 'fname'):
          fname = fname.fname
      suffix = fname.split('.')[-1].lower()
      return suffix in clink_suffixes
  
  def is_assembly(fname):
      if hasattr(fname, 'fname'):
          fname = fname.fname
      return fname.split('.')[-1].lower() == 's'
  
  def is_llvm_ir(fname):
      if hasattr(fname, 'fname'):
          fname = fname.fname
      return fname.split('.')[-1] == 'll'
  
  def is_object(fname):
      if hasattr(fname, 'fname'):
          fname = fname.fname
      suffix = fname.split('.')[-1]
      return suffix in obj_suffixes
  
  def is_library(fname):
      if hasattr(fname, 'fname'):
          fname = fname.fname
  
      if soregex.match(fname):
          return True
  
      suffix = fname.split('.')[-1]
      return suffix in lib_suffixes
  
  gnulike_buildtype_args = {'plain': [],
                            # -O0 is passed for improved debugging information with gcc
                            # See https://github.com/mesonbuild/meson/pull/509
                            'debug': ['-O0', '-g'],
                            'debugoptimized': ['-O2', '-g'],
                            'release': ['-O3'],
                            'minsize': ['-Os', '-g']}
  
  arm_buildtype_args = {'plain': [],
                        'debug': ['-O0', '--debug'],
                        'debugoptimized': ['-O1', '--debug'],
                        'release': ['-O3', '-Otime'],
                        'minsize': ['-O3', '-Ospace'],
                        }
  
  msvc_buildtype_args = {'plain': [],
                         'debug': ["/MDd", "/ZI", "/Ob0", "/Od", "/RTC1"],
                         'debugoptimized': ["/MD", "/Zi", "/O2", "/Ob1"],
                         'release': ["/MD", "/O2", "/Ob2"],
                         'minsize': ["/MD", "/Zi", "/Os", "/Ob1"],
                         }
  
  apple_buildtype_linker_args = {'plain': [],
                                 'debug': [],
                                 'debugoptimized': [],
                                 'release': [],
                                 'minsize': [],
                                 }
  
  gnulike_buildtype_linker_args = {'plain': [],
                                   'debug': [],
                                   'debugoptimized': [],
                                   'release': ['-Wl,-O1'],
                                   'minsize': [],
                                   }
  
  arm_buildtype_linker_args = {'plain': [],
                               'debug': [],
                               'debugoptimized': [],
                               'release': [],
                               'minsize': [],
                               }
  
  msvc_buildtype_linker_args = {'plain': [],
                                'debug': [],
                                'debugoptimized': [],
                                # The otherwise implicit REF and ICF linker
                                # optimisations are disabled by /DEBUG.
                                # REF implies ICF.
                                'release': ['/OPT:REF'],
                                'minsize': ['/INCREMENTAL:NO', '/OPT:REF'],
                                }
  
  java_buildtype_args = {'plain': [],
                         'debug': ['-g'],
                         'debugoptimized': ['-g'],
                         'release': [],
                         'minsize': [],
                         }
  
  rust_buildtype_args = {'plain': [],
                         'debug': ['-C', 'debuginfo=2'],
                         'debugoptimized': ['-C', 'debuginfo=2', '-C', 'opt-level=2'],
                         'release': ['-C', 'opt-level=3'],
                         'minsize': [], # In a future release: ['-C', 'opt-level=s'],
                         }
  
  d_gdc_buildtype_args = {'plain': [],
                          'debug': ['-g', '-O0'],
                          'debugoptimized': ['-g', '-O'],
                          'release': ['-O3', '-frelease'],
                          'minsize': [],
                          }
  
  d_ldc_buildtype_args = {'plain': [],
                          'debug': ['-g', '-O0'],
                          'debugoptimized': ['-g', '-O'],
                          'release': ['-O3', '-release'],
                          'minsize': [],
                          }
  
  d_dmd_buildtype_args = {'plain': [],
                          'debug': ['-g'],
                          'debugoptimized': ['-g', '-O'],
                          'release': ['-O', '-release'],
                          'minsize': [],
                          }
  
  mono_buildtype_args = {'plain': [],
                         'debug': ['-debug'],
                         'debugoptimized': ['-debug', '-optimize+'],
                         'release': ['-optimize+'],
                         'minsize': [],
                         }
  
  swift_buildtype_args = {'plain': [],
                          'debug': ['-g'],
                          'debugoptimized': ['-g', '-O'],
                          'release': ['-O'],
                          'minsize': [],
                          }
  
  gnu_winlibs = ['-lkernel32', '-luser32', '-lgdi32', '-lwinspool', '-lshell32',
                 '-lole32', '-loleaut32', '-luuid', '-lcomdlg32', '-ladvapi32']
  
  msvc_winlibs = ['kernel32.lib', 'user32.lib', 'gdi32.lib',
                  'winspool.lib', 'shell32.lib', 'ole32.lib', 'oleaut32.lib',
                  'uuid.lib', 'comdlg32.lib', 'advapi32.lib']
  
  gnu_color_args = {'auto': ['-fdiagnostics-color=auto'],
                    'always': ['-fdiagnostics-color=always'],
                    'never': ['-fdiagnostics-color=never'],
                    }
  
  clang_color_args = {'auto': ['-Xclang', '-fcolor-diagnostics'],
                      'always': ['-Xclang', '-fcolor-diagnostics'],
                      'never': ['-Xclang', '-fno-color-diagnostics'],
                      }
  
  base_options = {'b_pch': coredata.UserBooleanOption('b_pch', 'Use precompiled headers', True),
                  'b_lto': coredata.UserBooleanOption('b_lto', 'Use link time optimization', False),
                  'b_sanitize': coredata.UserComboOption('b_sanitize',
                                                         'Code sanitizer to use',
                                                         ['none', 'address', 'thread', 'undefined', 'memory', 'address,undefined'],
                                                         'none'),
                  'b_lundef': coredata.UserBooleanOption('b_lundef', 'Use -Wl,--no-undefined when linking', True),
                  'b_asneeded': coredata.UserBooleanOption('b_asneeded', 'Use -Wl,--as-needed when linking', True),
                  'b_pgo': coredata.UserComboOption('b_pgo', 'Use profile guided optimization',
                                                    ['off', 'generate', 'use'],
                                                    'off'),
                  'b_coverage': coredata.UserBooleanOption('b_coverage',
                                                           'Enable coverage tracking.',
                                                           False),
                  'b_colorout': coredata.UserComboOption('b_colorout', 'Use colored output',
                                                         ['auto', 'always', 'never'],
                                                         'always'),
                  'b_ndebug': coredata.UserComboOption('b_ndebug', 'Disable asserts',
                                                       ['true', 'false', 'if-release'], 'false'),
                  'b_staticpic': coredata.UserBooleanOption('b_staticpic',
                                                            'Build static libraries as position independent',
                                                            True),
                  'b_bitcode': coredata.UserBooleanOption('b_bitcode',
                                                          'Generate and embed bitcode (only macOS and iOS)',
                                                          False),
                  }
  
  gnulike_instruction_set_args = {'mmx': ['-mmmx'],
                                  'sse': ['-msse'],
                                  'sse2': ['-msse2'],
                                  'sse3': ['-msse3'],
                                  'ssse3': ['-mssse3'],
                                  'sse41': ['-msse4.1'],
                                  'sse42': ['-msse4.2'],
                                  'avx': ['-mavx'],
                                  'avx2': ['-mavx2'],
                                  'neon': ['-mfpu=neon'],
                                  }
  
  vs32_instruction_set_args = {'mmx': ['/arch:SSE'], # There does not seem to be a flag just for MMX
                               'sse': ['/arch:SSE'],
                               'sse2': ['/arch:SSE2'],
                               'sse3': ['/arch:AVX'], # VS leaped from SSE2 directly to AVX.
                               'sse41': ['/arch:AVX'],
                               'sse42': ['/arch:AVX'],
                               'avx': ['/arch:AVX'],
                               'avx2': ['/arch:AVX2'],
                               'neon': None,
                               }
  
  # The 64 bit compiler defaults to /arch:avx.
  vs64_instruction_set_args = {'mmx': ['/arch:AVX'],
                               'sse': ['/arch:AVX'],
                               'sse2': ['/arch:AVX'],
                               'sse3': ['/arch:AVX'],
                               'ssse3': ['/arch:AVX'],
                               'sse41': ['/arch:AVX'],
                               'sse42': ['/arch:AVX'],
                               'avx': ['/arch:AVX'],
                               'avx2': ['/arch:AVX2'],
                               'neon': None,
                               }
  
  def sanitizer_compile_args(value):
      if value == 'none':
          return []
      args = ['-fsanitize=' + value]
      if 'address' in value: # For -fsanitize=address,undefined
          args.append('-fno-omit-frame-pointer')
      return args
  
  def sanitizer_link_args(value):
      if value == 'none':
          return []
      args = ['-fsanitize=' + value]
      return args
  
  def option_enabled(boptions, options, option):
      try:
          if option not in boptions:
              return False
          return options[option].value
      except KeyError:
          return False
  
  def get_base_compile_args(options, compiler):
      args = []
      # FIXME, gcc/clang specific.
      try:
          if options['b_lto'].value:
              args.append('-flto')
      except KeyError:
          pass
      try:
          args += compiler.get_colorout_args(options['b_colorout'].value)
      except KeyError:
          pass
      try:
          args += sanitizer_compile_args(options['b_sanitize'].value)
      except KeyError:
          pass
      try:
          pgo_val = options['b_pgo'].value
          if pgo_val == 'generate':
              args.append('-fprofile-generate')
          elif pgo_val == 'use':
              args.append('-fprofile-use')
      except KeyError:
          pass
      try:
          if options['b_coverage'].value:
              args += compiler.get_coverage_args()
      except KeyError:
          pass
      try:
          if (options['b_ndebug'].value == 'true' or
                  (options['b_ndebug'].value == 'if-release' and
                   options['buildtype'].value == 'release')):
              args += ['-DNDEBUG']
      except KeyError:
          pass
      # This does not need a try...except
      if option_enabled(compiler.base_options, options, 'b_bitcode'):
          args.append('-fembed-bitcode')
      return args
  
  def get_base_link_args(options, linker, is_shared_module):
      args = []
      # FIXME, gcc/clang specific.
      try:
          if options['b_lto'].value:
              args.append('-flto')
      except KeyError:
          pass
      try:
          args += sanitizer_link_args(options['b_sanitize'].value)
      except KeyError:
          pass
      try:
          pgo_val = options['b_pgo'].value
          if pgo_val == 'generate':
              args.append('-fprofile-generate')
          elif pgo_val == 'use':
              args.append('-fprofile-use')
      except KeyError:
          pass
      try:
          if options['b_coverage'].value:
              args += linker.get_coverage_link_args()
      except KeyError:
          pass
      # These do not need a try...except
      if not is_shared_module and option_enabled(linker.base_options, options, 'b_lundef'):
          args.append('-Wl,--no-undefined')
      as_needed = option_enabled(linker.base_options, options, 'b_asneeded')
      bitcode = option_enabled(linker.base_options, options, 'b_bitcode')
      # Shared modules cannot be built with bitcode_bundle because
      # -bitcode_bundle is incompatible with -undefined and -bundle
      if bitcode and not is_shared_module:
          args.append('-Wl,-bitcode_bundle')
      elif as_needed:
          # -Wl,-dead_strip_dylibs is incompatible with bitcode
          args.append(linker.get_asneeded_args())
      return args
  
  class CrossNoRunException(MesonException):
      pass
  
  class RunResult:
      def __init__(self, compiled, returncode=999, stdout='UNDEFINED', stderr='UNDEFINED'):
          self.compiled = compiled
          self.returncode = returncode
          self.stdout = stdout
          self.stderr = stderr
  
  class CompilerArgs(list):
      '''
      Class derived from list() that manages a list of compiler arguments. Should
      be used while constructing compiler arguments from various sources. Can be
      operated with ordinary lists, so this does not need to be used everywhere.
  
      All arguments must be inserted and stored in GCC-style (-lfoo, -Idir, etc)
      and can converted to the native type of each compiler by using the
      .to_native() method to which you must pass an instance of the compiler or
      the compiler class.
  
      New arguments added to this class (either with .append(), .extend(), or +=)
      are added in a way that ensures that they override previous arguments.
      For example:
  
      >>> a = ['-Lfoo', '-lbar']
      >>> a += ['-Lpho', '-lbaz']
      >>> print(a)
      ['-Lpho', '-Lfoo', '-lbar', '-lbaz']
  
      Arguments will also be de-duped if they can be de-duped safely.
  
      Note that because of all this, this class is not commutative and does not
      preserve the order of arguments if it is safe to not. For example:
      >>> ['-Ifoo', '-Ibar'] + ['-Ifez', '-Ibaz', '-Werror']
      ['-Ifez', '-Ibaz', '-Ifoo', '-Ibar', '-Werror']
      >>> ['-Ifez', '-Ibaz', '-Werror'] + ['-Ifoo', '-Ibar']
      ['-Ifoo', '-Ibar', '-Ifez', '-Ibaz', '-Werror']
  
      '''
      # NOTE: currently this class is only for C-like compilers, but it can be
      # extended to other languages easily. Just move the following to the
      # compiler class and initialize when self.compiler is set.
  
      # Arg prefixes that override by prepending instead of appending
      prepend_prefixes = ('-I', '-L')
      # Arg prefixes and args that must be de-duped by returning 2
      dedup2_prefixes = ('-I', '-L', '-D', '-U')
      dedup2_suffixes = ()
      dedup2_args = ()
      # Arg prefixes and args that
  
  [... the rest is omitted ...]
files.new_path: mesonbuild/compilers/compilers.py
files.old_contents: # Copyright 2012-2017 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 contextlib, os.path, re, tempfile, shlex
  import subprocess
  
  from ..linkers import StaticLinker
  from .. import coredata
  from .. import mlog
  from .. import mesonlib
  from ..mesonlib import EnvironmentException, MesonException, version_compare, Popen_safe
  
  """This file contains the data files of all compilers Meson knows
  about. To support a new compiler, add its information below.
  Also add corresponding autodetection code in environment.py."""
  
  header_suffixes = ('h', 'hh', 'hpp', 'hxx', 'H', 'ipp', 'moc', 'vapi', 'di')
  obj_suffixes = ('o', 'obj', 'res')
  lib_suffixes = ('a', 'lib', 'dll', 'dylib', 'so')
  # Mapping of language to suffixes of files that should always be in that language
  # This means we can't include .h headers here since they could be C, C++, ObjC, etc.
  lang_suffixes = {
      'c': ('c',),
      'cpp': ('cpp', 'cc', 'cxx', 'c++', 'hh', 'hpp', 'ipp', 'hxx'),
      # f90, f95, f03, f08 are for free-form fortran ('f90' recommended)
      # f, for, ftn, fpp are for fixed-form fortran ('f' or 'for' recommended)
      'fortran': ('f90', 'f95', 'f03', 'f08', 'f', 'for', 'ftn', 'fpp'),
      'd': ('d', 'di'),
      'objc': ('m',),
      'objcpp': ('mm',),
      'rust': ('rs',),
      'vala': ('vala', 'vapi', 'gs'),
      'cs': ('cs',),
      'swift': ('swift',),
      'java': ('java',),
  }
  all_languages = lang_suffixes.keys()
  cpp_suffixes = lang_suffixes['cpp'] + ('h',)
  c_suffixes = lang_suffixes['c'] + ('h',)
  # List of languages that by default consume and output libraries following the
  # C ABI; these can generally be used interchangebly
  clib_langs = ('objcpp', 'cpp', 'objc', 'c', 'fortran',)
  # List of languages that can be linked with C code directly by the linker
  # used in build.py:process_compilers() and build.py:get_dynamic_linker()
  # XXX: Add Rust to this?
  clike_langs = ('d',) + clib_langs
  clike_suffixes = ()
  for _l in clike_langs + ('vala',):
      clike_suffixes += lang_suffixes[_l]
  clike_suffixes += ('h', 'll', 's')
  
  soregex = re.compile(r'.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$')
  
  # Environment variables that each lang uses.
  cflags_mapping = {'c': 'CFLAGS',
                    'cpp': 'CXXFLAGS',
                    'objc': 'OBJCFLAGS',
                    'objcpp': 'OBJCXXFLAGS',
                    'fortran': 'FFLAGS',
                    'd': 'DFLAGS',
                    'vala': 'VALAFLAGS',
                    'rust': 'RUSTFLAGS'}
  
  # All these are only for C-like languages; see `clike_langs` above.
  
  def sort_clike(lang):
      '''
      Sorting function to sort the list of languages according to
      reversed(compilers.clike_langs) and append the unknown langs in the end.
      The purpose is to prefer C over C++ for files that can be compiled by
      both such as assembly, C, etc. Also applies to ObjC, ObjC++, etc.
      '''
      if lang not in clike_langs:
          return 1
      return -clike_langs.index(lang)
  
  def is_header(fname):
      if hasattr(fname, 'fname'):
          fname = fname.fname
      suffix = fname.split('.')[-1]
      return suffix in header_suffixes
  
  def is_source(fname):
      if hasattr(fname, 'fname'):
          fname = fname.fname
      suffix = fname.split('.')[-1].lower()
      return suffix in clike_suffixes
  
  def is_assembly(fname):
      if hasattr(fname, 'fname'):
          fname = fname.fname
      return fname.split('.')[-1].lower() == 's'
  
  def is_llvm_ir(fname):
      if hasattr(fname, 'fname'):
          fname = fname.fname
      return fname.split('.')[-1] == 'll'
  
  def is_object(fname):
      if hasattr(fname, 'fname'):
          fname = fname.fname
      suffix = fname.split('.')[-1]
      return suffix in obj_suffixes
  
  def is_library(fname):
      if hasattr(fname, 'fname'):
          fname = fname.fname
  
      if soregex.match(fname):
          return True
  
      suffix = fname.split('.')[-1]
      return suffix in lib_suffixes
  
  gnulike_buildtype_args = {'plain': [],
                            # -O0 is passed for improved debugging information with gcc
                            # See https://github.com/mesonbuild/meson/pull/509
                            'debug': ['-O0', '-g'],
                            'debugoptimized': ['-O2', '-g'],
                            'release': ['-O3'],
                            'minsize': ['-Os', '-g']}
  
  arm_buildtype_args = {'plain': [],
                        'debug': ['-O0', '--debug'],
                        'debugoptimized': ['-O1', '--debug'],
                        'release': ['-O3', '-Otime'],
                        'minsize': ['-O3', '-Ospace'],
                        }
  
  msvc_buildtype_args = {'plain': [],
                         'debug': ["/MDd", "/ZI", "/Ob0", "/Od", "/RTC1"],
                         'debugoptimized': ["/MD", "/Zi", "/O2", "/Ob1"],
                         'release': ["/MD", "/O2", "/Ob2"],
                         'minsize': ["/MD", "/Zi", "/Os", "/Ob1"],
                         }
  
  apple_buildtype_linker_args = {'plain': [],
                                 'debug': [],
                                 'debugoptimized': [],
                                 'release': [],
                                 'minsize': [],
                                 }
  
  gnulike_buildtype_linker_args = {'plain': [],
                                   'debug': [],
                                   'debugoptimized': [],
                                   'release': ['-Wl,-O1'],
                                   'minsize': [],
                                   }
  
  arm_buildtype_linker_args = {'plain': [],
                               'debug': [],
                               'debugoptimized': [],
                               'release': [],
                               'minsize': [],
                               }
  
  msvc_buildtype_linker_args = {'plain': [],
                                'debug': [],
                                'debugoptimized': [],
                                # The otherwise implicit REF and ICF linker
                                # optimisations are disabled by /DEBUG.
                                # REF implies ICF.
                                'release': ['/OPT:REF'],
                                'minsize': ['/INCREMENTAL:NO', '/OPT:REF'],
                                }
  
  java_buildtype_args = {'plain': [],
                         'debug': ['-g'],
                         'debugoptimized': ['-g'],
                         'release': [],
                         'minsize': [],
                         }
  
  rust_buildtype_args = {'plain': [],
                         'debug': ['-C', 'debuginfo=2'],
                         'debugoptimized': ['-C', 'debuginfo=2', '-C', 'opt-level=2'],
                         'release': ['-C', 'opt-level=3'],
                         'minsize': [], # In a future release: ['-C', 'opt-level=s'],
                         }
  
  d_gdc_buildtype_args = {'plain': [],
                          'debug': ['-g', '-O0'],
                          'debugoptimized': ['-g', '-O'],
                          'release': ['-O3', '-frelease'],
                          'minsize': [],
                          }
  
  d_ldc_buildtype_args = {'plain': [],
                          'debug': ['-g', '-O0'],
                          'debugoptimized': ['-g', '-O'],
                          'release': ['-O3', '-release'],
                          'minsize': [],
                          }
  
  d_dmd_buildtype_args = {'plain': [],
                          'debug': ['-g'],
                          'debugoptimized': ['-g', '-O'],
                          'release': ['-O', '-release'],
                          'minsize': [],
                          }
  
  mono_buildtype_args = {'plain': [],
                         'debug': ['-debug'],
                         'debugoptimized': ['-debug', '-optimize+'],
                         'release': ['-optimize+'],
                         'minsize': [],
                         }
  
  swift_buildtype_args = {'plain': [],
                          'debug': ['-g'],
                          'debugoptimized': ['-g', '-O'],
                          'release': ['-O'],
                          'minsize': [],
                          }
  
  gnu_winlibs = ['-lkernel32', '-luser32', '-lgdi32', '-lwinspool', '-lshell32',
                 '-lole32', '-loleaut32', '-luuid', '-lcomdlg32', '-ladvapi32']
  
  msvc_winlibs = ['kernel32.lib', 'user32.lib', 'gdi32.lib',
                  'winspool.lib', 'shell32.lib', 'ole32.lib', 'oleaut32.lib',
                  'uuid.lib', 'comdlg32.lib', 'advapi32.lib']
  
  gnu_color_args = {'auto': ['-fdiagnostics-color=auto'],
                    'always': ['-fdiagnostics-color=always'],
                    'never': ['-fdiagnostics-color=never'],
                    }
  
  clang_color_args = {'auto': ['-Xclang', '-fcolor-diagnostics'],
                      'always': ['-Xclang', '-fcolor-diagnostics'],
                      'never': ['-Xclang', '-fno-color-diagnostics'],
                      }
  
  base_options = {'b_pch': coredata.UserBooleanOption('b_pch', 'Use precompiled headers', True),
                  'b_lto': coredata.UserBooleanOption('b_lto', 'Use link time optimization', False),
                  'b_sanitize': coredata.UserComboOption('b_sanitize',
                                                         'Code sanitizer to use',
                                                         ['none', 'address', 'thread', 'undefined', 'memory', 'address,undefined'],
                                                         'none'),
                  'b_lundef': coredata.UserBooleanOption('b_lundef', 'Use -Wl,--no-undefined when linking', True),
                  'b_asneeded': coredata.UserBooleanOption('b_asneeded', 'Use -Wl,--as-needed when linking', True),
                  'b_pgo': coredata.UserComboOption('b_pgo', 'Use profile guided optimization',
                                                    ['off', 'generate', 'use'],
                                                    'off'),
                  'b_coverage': coredata.UserBooleanOption('b_coverage',
                                                           'Enable coverage tracking.',
                                                           False),
                  'b_colorout': coredata.UserComboOption('b_colorout', 'Use colored output',
                                                         ['auto', 'always', 'never'],
                                                         'always'),
                  'b_ndebug': coredata.UserComboOption('b_ndebug', 'Disable asserts',
                                                       ['true', 'false', 'if-release'], 'false'),
                  'b_staticpic': coredata.UserBooleanOption('b_staticpic',
                                                            'Build static libraries as position independent',
                                                            True),
                  'b_bitcode': coredata.UserBooleanOption('b_bitcode',
                                                          'Generate and embed bitcode (only macOS and iOS)',
                                                          False),
                  }
  
  gnulike_instruction_set_args = {'mmx': ['-mmmx'],
                                  'sse': ['-msse'],
                                  'sse2': ['-msse2'],
                                  'sse3': ['-msse3'],
                                  'ssse3': ['-mssse3'],
                                  'sse41': ['-msse4.1'],
                                  'sse42': ['-msse4.2'],
                                  'avx': ['-mavx'],
                                  'avx2': ['-mavx2'],
                                  'neon': ['-mfpu=neon'],
                                  }
  
  vs32_instruction_set_args = {'mmx': ['/arch:SSE'], # There does not seem to be a flag just for MMX
                               'sse': ['/arch:SSE'],
                               'sse2': ['/arch:SSE2'],
                               'sse3': ['/arch:AVX'], # VS leaped from SSE2 directly to AVX.
                               'sse41': ['/arch:AVX'],
                               'sse42': ['/arch:AVX'],
                               'avx': ['/arch:AVX'],
                               'avx2': ['/arch:AVX2'],
                               'neon': None,
                               }
  
  # The 64 bit compiler defaults to /arch:avx.
  vs64_instruction_set_args = {'mmx': ['/arch:AVX'],
                               'sse': ['/arch:AVX'],
                               'sse2': ['/arch:AVX'],
                               'sse3': ['/arch:AVX'],
                               'ssse3': ['/arch:AVX'],
                               'sse41': ['/arch:AVX'],
                               'sse42': ['/arch:AVX'],
                               'avx': ['/arch:AVX'],
                               'avx2': ['/arch:AVX2'],
                               'neon': None,
                               }
  
  def sanitizer_compile_args(value):
      if value == 'none':
          return []
      args = ['-fsanitize=' + value]
      if 'address' in value: # For -fsanitize=address,undefined
          args.append('-fno-omit-frame-pointer')
      return args
  
  def sanitizer_link_args(value):
      if value == 'none':
          return []
      args = ['-fsanitize=' + value]
      return args
  
  def option_enabled(boptions, options, option):
      try:
          if option not in boptions:
              return False
          return options[option].value
      except KeyError:
          return False
  
  def get_base_compile_args(options, compiler):
      args = []
      # FIXME, gcc/clang specific.
      try:
          if options['b_lto'].value:
              args.append('-flto')
      except KeyError:
          pass
      try:
          args += compiler.get_colorout_args(options['b_colorout'].value)
      except KeyError:
          pass
      try:
          args += sanitizer_compile_args(options['b_sanitize'].value)
      except KeyError:
          pass
      try:
          pgo_val = options['b_pgo'].value
          if pgo_val == 'generate':
              args.append('-fprofile-generate')
          elif pgo_val == 'use':
              args.append('-fprofile-use')
      except KeyError:
          pass
      try:
          if options['b_coverage'].value:
              args += compiler.get_coverage_args()
      except KeyError:
          pass
      try:
          if (options['b_ndebug'].value == 'true' or
                  (options['b_ndebug'].value == 'if-release' and
                   options['buildtype'].value == 'release')):
              args += ['-DNDEBUG']
      except KeyError:
          pass
      # This does not need a try...except
      if option_enabled(compiler.base_options, options, 'b_bitcode'):
          args.append('-fembed-bitcode')
      return args
  
  def get_base_link_args(options, linker, is_shared_module):
      args = []
      # FIXME, gcc/clang specific.
      try:
          if options['b_lto'].value:
              args.append('-flto')
      except KeyError:
          pass
      try:
          args += sanitizer_link_args(options['b_sanitize'].value)
      except KeyError:
          pass
      try:
          pgo_val = options['b_pgo'].value
          if pgo_val == 'generate':
              args.append('-fprofile-generate')
          elif pgo_val == 'use':
              args.append('-fprofile-use')
      except KeyError:
          pass
      try:
          if options['b_coverage'].value:
              args += linker.get_coverage_link_args()
      except KeyError:
          pass
      # These do not need a try...except
      if not is_shared_module and option_enabled(linker.base_options, options, 'b_lundef'):
          args.append('-Wl,--no-undefined')
      as_needed = option_enabled(linker.base_options, options, 'b_asneeded')
      bitcode = option_enabled(linker.base_options, options, 'b_bitcode')
      # Shared modules cannot be built with bitcode_bundle because
      # -bitcode_bundle is incompatible with -undefined and -bundle
      if bitcode and not is_shared_module:
          args.append('-Wl,-bitcode_bundle')
      elif as_needed:
          # -Wl,-dead_strip_dylibs is incompatible with bitcode
          args.append(linker.get_asneeded_args())
      return args
  
  class CrossNoRunException(MesonException):
      pass
  
  class RunResult:
      def __init__(self, compiled, returncode=999, stdout='UNDEFINED', stderr='UNDEFINED'):
          self.compiled = compiled
          self.returncode = returncode
          self.stdout = stdout
          self.stderr = stderr
  
  class CompilerArgs(list):
      '''
      Class derived from list() that manages a list of compiler arguments. Should
      be used while constructing compiler arguments from various sources. Can be
      operated with ordinary lists, so this does not need to be used everywhere.
  
      All arguments must be inserted and stored in GCC-style (-lfoo, -Idir, etc)
      and can converted to the native type of each compiler by using the
      .to_native() method to which you must pass an instance of the compiler or
      the compiler class.
  
      New arguments added to this class (either with .append(), .extend(), or +=)
      are added in a way that ensures that they override previous arguments.
      For example:
  
      >>> a = ['-Lfoo', '-lbar']
      >>> a += ['-Lpho', '-lbaz']
      >>> print(a)
      ['-Lpho', '-Lfoo', '-lbar', '-lbaz']
  
      Arguments will also be de-duped if they can be de-duped safely.
  
      Note that because of all this, this class is not commutative and does not
      preserve the order of arguments if it is safe to not. For example:
      >>> ['-Ifoo', '-Ibar'] + ['-Ifez', '-Ibaz', '-Werror']
      ['-Ifez', '-Ibaz', '-Ifoo', '-Ibar', '-Werror']
      >>> ['-Ifez', '-Ibaz', '-Werror'] + ['-Ifoo', '-Ibar']
      ['-Ifoo', '-Ibar', '-Ifez', '-Ibaz', '-Werror']
  
      '''
      # NOTE: currently this class is only for C-like compilers, but it can be
      # extended to other languages easily. Just move the following to the
      # compiler class and initialize when self.compiler is set.
  
      # Arg prefixes that override by prepending instead of appending
      prepend_prefixes = ('-I', '-L')
      # Arg prefixes and args that must be de-duped by returning 2
      dedup2_prefixes = ('-I', '-L', '-D', '-U')
      dedup2_suffixes = ()
      dedup2_args = ()
      # Arg prefixes and args that must
  
  [... the rest is omitted ...]
files.old_path: mesonbuild/compilers/compilers.py
files.new_contents: # Copyright 2013-2018 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.
  # Custom logic for several other packages are in separate files.
  
  import copy
  import os
  import re
  import stat
  import shlex
  import shutil
  import textwrap
  from enum import Enum
  from pathlib import PurePath
  
  from .. import mlog
  from .. import mesonlib
  from ..compilers import clib_langs
  from ..mesonlib import MesonException, OrderedSet
  from ..mesonlib import Popen_safe, version_compare_many, version_compare, listify
  
  
  # These must be defined in this file to avoid cyclical references.
  packages = {}
  _packages_accept_language = set()
  
  
  class DependencyException(MesonException):
      '''Exceptions raised while trying to find dependencies'''
  
  
  class DependencyMethods(Enum):
      # Auto means to use whatever dependency checking mechanisms in whatever order meson thinks is best.
      AUTO = 'auto'
      PKGCONFIG = 'pkg-config'
      QMAKE = 'qmake'
      # Just specify the standard link arguments, assuming the operating system provides the library.
      SYSTEM = 'system'
      # This is only supported on OSX - search the frameworks directory by name.
      EXTRAFRAMEWORK = 'extraframework'
      # Detect using the sysconfig module.
      SYSCONFIG = 'sysconfig'
      # Specify using a "program"-config style tool
      CONFIG_TOOL = 'config-tool'
      # For backewards compatibility
      SDLCONFIG = 'sdlconfig'
      CUPSCONFIG = 'cups-config'
      PCAPCONFIG = 'pcap-config'
      LIBWMFCONFIG = 'libwmf-config'
  
  
  class Dependency:
      @classmethod
      def _process_method_kw(cls, kwargs):
          method = kwargs.get('method', 'auto')
          if method not in [e.value for e in DependencyMethods]:
              raise DependencyException('method {!r} is invalid'.format(method))
          method = DependencyMethods(method)
  
          # This sets per-tool config methods which are deprecated to to the new
          # generic CONFIG_TOOL value.
          if method in [DependencyMethods.SDLCONFIG, DependencyMethods.CUPSCONFIG,
                        DependencyMethods.PCAPCONFIG, DependencyMethods.LIBWMFCONFIG]:
              mlog.warning(textwrap.dedent("""\
                  Configuration method {} has been deprecated in favor of
                  'config-tool'. This will be removed in a future version of
                  meson.""".format(method)))
              method = DependencyMethods.CONFIG_TOOL
  
          # Set the detection method. If the method is set to auto, use any available method.
          # If method is set to a specific string, allow only that detection method.
          if method == DependencyMethods.AUTO:
              methods = cls.get_methods()
          elif method in cls.get_methods():
              methods = [method]
          else:
              raise DependencyException(
                  'Unsupported detection method: {}, allowed methods are {}'.format(
                      method.value,
                      mlog.format_list([x.value for x in [DependencyMethods.AUTO] + cls.get_methods()])))
  
          return methods
  
      def __init__(self, type_name, kwargs):
          self.name = "null"
          self.version = 'none'
          self.language = None # None means C-like
          self.is_found = False
          self.type_name = type_name
          self.compile_args = []
          self.link_args = []
          self.sources = []
          self.methods = self._process_method_kw(kwargs)
  
      def __repr__(self):
          s = '<{0} {1}: {2}>'
          return s.format(self.__class__.__name__, self.name, self.is_found)
  
      def get_compile_args(self):
          return self.compile_args
  
      def get_link_args(self):
          return self.link_args
  
      def found(self):
          return self.is_found
  
      def get_sources(self):
          """Source files that need to be added to the target.
          As an example, gtest-all.cc when using GTest."""
          return self.sources
  
      @staticmethod
      def get_methods():
          return [DependencyMethods.AUTO]
  
      def get_name(self):
          return self.name
  
      def get_version(self):
          return self.version
  
      def get_exe_args(self, compiler):
          return []
  
      def need_openmp(self):
          return False
  
      def need_threads(self):
          return False
  
      def get_pkgconfig_variable(self, variable_name, kwargs):
          raise DependencyException('{!r} is not a pkgconfig dependency'.format(self.name))
  
      def get_configtool_variable(self, variable_name):
          raise DependencyException('{!r} is not a config-tool dependency'.format(self.name))
  
      def get_partial_dependency(self, *, compile_args=False, link_args=False,
                                 links=False, includes=False, sources=False):
          """Create a new dependency that contains part of the parent dependency.
  
          The following options can be inherited:
              links -- all link_with arguemnts
              includes -- all include_directory and -I/-isystem calls
              sources -- any source, header, or generated sources
              compile_args -- any compile args
              link_args -- any link args
  
          Additionally the new dependency will have the version parameter of it's
          parent (if any) and the requested values of any dependencies will be
          added as well.
          """
          RuntimeError('Unreachable code in partial_dependency called')
  
  
  class InternalDependency(Dependency):
      def __init__(self, version, incdirs, compile_args, link_args, libraries, whole_libraries, sources, ext_deps):
          super().__init__('internal', {})
          self.version = version
          self.is_found = True
          self.include_directories = incdirs
          self.compile_args = compile_args
          self.link_args = link_args
          self.libraries = libraries
          self.whole_libraries = whole_libraries
          self.sources = sources
          self.ext_deps = ext_deps
  
      def get_pkgconfig_variable(self, variable_name, kwargs):
          raise DependencyException('Method "get_pkgconfig_variable()" is '
                                    'invalid for an internal dependency')
  
      def get_configtool_variable(self, variable_name):
          raise DependencyException('Method "get_configtool_variable()" is '
                                    'invalid for an internal dependency')
  
      def get_partial_dependency(self, *, compile_args=False, link_args=False,
                                 links=False, includes=False, sources=False):
          compile_args = self.compile_args.copy() if compile_args else []
          link_args = self.link_args.copy() if link_args else []
          libraries = self.libraries.copy() if links else []
          whole_libraries = self.whole_libraries.copy() if links else []
          sources = self.sources.copy() if sources else []
          includes = self.include_directories.copy() if includes else []
          deps = [d.get_partial_dependency(
              compile_args=compile_args, link_args=link_args, links=links,
              includes=includes, sources=sources) for d in self.ext_deps]
          return InternalDependency(
              self.version, includes, compile_args, link_args, libraries,
              whole_libraries, sources, deps)
  
  
  class ExternalDependency(Dependency):
      def __init__(self, type_name, environment, language, kwargs):
          super().__init__(type_name, kwargs)
          self.env = environment
          self.name = type_name # default
          self.is_found = False
          self.language = language
          self.version_reqs = kwargs.get('version', None)
          self.required = kwargs.get('required', True)
          self.silent = kwargs.get('silent', False)
          self.static = kwargs.get('static', False)
          if not isinstance(self.static, bool):
              raise DependencyException('Static keyword must be boolean')
          # Is this dependency for cross-compilation?
          if 'native' in kwargs and self.env.is_cross_build():
              self.want_cross = not kwargs['native']
          else:
              self.want_cross = self.env.is_cross_build()
          self.clib_compiler = None
          # Set the compiler that will be used by this dependency
          # This is only used for configuration checks
          if self.want_cross:
              compilers = self.env.coredata.cross_compilers
          else:
              compilers = self.env.coredata.compilers
          # Set the compiler for this dependency if a language is specified,
          # else try to pick something that looks usable.
          if self.language:
              if self.language not in compilers:
                  m = self.name.capitalize() + ' requires a {0} compiler, but ' \
                      '{0} is not in the list of project languages'
                  raise DependencyException(m.format(self.language.capitalize()))
              self.clib_compiler = compilers[self.language]
          else:
              # Try to find a compiler that can find C libraries for
              # running compiler.find_library()
              for lang in clib_langs:
                  self.clib_compiler = compilers.get(lang, None)
                  if self.clib_compiler:
                      break
  
      def get_compiler(self):
          return self.clib_compiler
  
      def get_partial_dependency(self, *, compile_args=False, link_args=False,
                                 links=False, includes=False, sources=False):
          new = copy.copy(self)
          if not compile_args:
              new.compile_args = []
          if not link_args:
              new.link_args = []
          if not sources:
              new.sources = []
  
          return new
  
  
  class NotFoundDependency(Dependency):
      def __init__(self, environment):
          super().__init__('not-found', {})
          self.env = environment
          self.name = 'not-found'
          self.is_found = False
  
  
  class ConfigToolDependency(ExternalDependency):
  
      """Class representing dependencies found using a config tool."""
  
      tools = None
      tool_name = None
      __strip_version = re.compile(r'^[0-9.]*')
  
      def __init__(self, name, environment, language, kwargs):
          super().__init__('config-tool', environment, language, kwargs)
          self.name = name
          self.native = kwargs.get('native', False)
          self.tools = listify(kwargs.get('tools', self.tools))
  
          req_version = kwargs.get('version', None)
          tool, version = self.find_config(req_version)
          self.config = tool
          self.is_found = self.report_config(version, req_version)
          if not self.is_found:
              self.config = None
              return
          self.version = version
  
      def _sanitize_version(self, version):
          """Remove any non-numeric, non-point version suffixes."""
          m = self.__strip_version.match(version)
          if m:
              # Ensure that there isn't a trailing '.', such as an input like
              # `1.2.3.git-1234`
              return m.group(0).rstrip('.')
          return version
  
      @classmethod
      def factory(cls, name, environment, language, kwargs, tools, tool_name):
          """Constructor for use in dependencies that can be found multiple ways.
  
          In addition to the standard constructor values, this constructor sets
          the tool_name and tools values of the instance.
          """
          # This deserves some explanation, because metaprogramming is hard.
          # This uses type() to create a dynamic subclass of ConfigToolDependency
          # with the tools and tool_name class attributes set, this class is then
          # instantiated and returned. The reduce function (method) is also
          # attached, since python's pickle module won't be able to do anything
          # with this dynamically generated class otherwise.
          def reduce(self):
              return (cls._unpickle, (), self.__dict__)
          sub = type('{}Dependency'.format(name.capitalize()), (cls, ),
                     {'tools': tools, 'tool_name': tool_name, '__reduce__': reduce})
  
          return sub(name, environment, language, kwargs)
  
      @classmethod
      def _unpickle(cls):
          return cls.__new__(cls)
  
      def find_config(self, versions=None):
          """Helper method that searchs for config tool binaries in PATH and
          returns the one that best matches the given version requirements.
          """
          if not isinstance(versions, list) and versions is not None:
              versions = listify(versions)
  
          if self.env.is_cross_build() and not self.native:
              cross_file = self.env.cross_info.config['binaries']
              try:
                  tools = [cross_file[self.tool_name]]
              except KeyError:
                  mlog.warning('No entry for {0} specified in your cross file. '
                               'Falling back to searching PATH. This may find a '
                               'native version of {0}!'.format(self.tool_name))
                  tools = self.tools
          else:
              tools = self.tools
  
          best_match = (None, None)
          for tool in tools:
              try:
                  p, out = Popen_safe([tool, '--version'])[:2]
              except (FileNotFoundError, PermissionError):
                  continue
              if p.returncode != 0:
                  continue
  
              out = self._sanitize_version(out.strip())
              # Some tools, like pcap-config don't supply a version, but also
              # don't fail with --version, in that case just assume that there is
              # only one version and return it.
              if not out:
                  return (tool, 'none')
              if versions:
                  is_found = version_compare_many(out, versions)[0]
                  # This allows returning a found version without a config tool,
                  # which is useful to inform the user that you found version x,
                  # but y was required.
                  if not is_found:
                      tool = None
              if best_match[1]:
                  if version_compare(out, '> {}'.format(best_match[1])):
                      best_match = (tool, out)
              else:
                  best_match = (tool, out)
  
          return best_match
  
      def report_config(self, version, req_version):
          """Helper method to print messages about the tool."""
          if self.config is None:
              if version is not None:
                  mlog.log('Found', mlog.bold(self.tool_name), repr(version),
                           mlog.red('NO'), '(needed', req_version, ')')
              else:
                  mlog.log('Found', mlog.bold(self.tool_name), repr(req_version),
                           mlog.red('NO'))
              mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.red('NO'))
              if self.required:
                  raise DependencyException('Dependency {} not found'.format(self.name))
              return False
          mlog.log('Found {}:'.format(self.tool_name), mlog.bold(shutil.which(self.config)),
                   '({})'.format(version))
          mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'))
          return True
  
      def get_config_value(self, args, stage):
          p, out, err = Popen_safe([self.config] + args)
          if p.returncode != 0:
              if self.required:
                  raise DependencyException(
                      'Could not generate {} for {}.\n{}'.format(
                          stage, self.name, err))
              return []
          return shlex.split(out)
  
      @staticmethod
      def get_methods():
          return [DependencyMethods.AUTO, DependencyMethods.CONFIG_TOOL]
  
      def get_configtool_variable(self, variable_name):
          p, out, _ = Popen_safe([self.config, '--{}'.format(variable_name)])
          if p.returncode != 0:
              if self.required:
                  raise DependencyException(
                      'Could not get variable "{}" for dependency {}'.format(
                          variable_name, self.name))
          variable = out.strip()
          mlog.debug('Got config-tool variable {} : {}'.format(variable_name, variable))
          return variable
  
  
  class PkgConfigDependency(ExternalDependency):
      # The class's copy of the pkg-config path. Avoids having to search for it
      # multiple times in the same Meson invocation.
      class_pkgbin = None
      # We cache all pkg-config subprocess invocations to avoid redundant calls
      pkgbin_cache = {}
  
      def __init__(self, name, environment, kwargs, language=None):
          super().__init__('pkgconfig', environment, language, kwargs)
          self.name = name
          self.is_libtool = False
          # Store a copy of the pkg-config path on the object itself so it is
          # stored in the pickled coredata and recovered.
          self.pkgbin = None
  
          # When finding dependencies for cross-compiling, we don't care about
          # the 'native' pkg-config
          if self.want_cross:
              if 'pkgconfig' not in environment.cross_info.config['binaries']:
                  if self.required:
                      raise DependencyException('Pkg-config binary missing from cross file')
              else:
                  pkgname = environment.cross_info.config['binaries']['pkgconfig']
                  potential_pkgbin = ExternalProgram(pkgname, silent=True)
                  if potential_pkgbin.found():
                      self.pkgbin = potential_pkgbin
                      PkgConfigDependency.class_pkgbin = self.pkgbin
                  else:
                      mlog.debug('Cross pkg-config %s not found.' % potential_pkgbin.name)
          # Only search for the native pkg-config the first time and
          # store the result in the class definition
          elif PkgConfigDependency.class_pkgbin is None:
              self.pkgbin = self.check_pkgconfig()
              PkgConfigDependency.class_pkgbin = self.pkgbin
          else:
              self.pkgbin = PkgConfigDependency.class_pkgbin
  
          if not self.pkgbin:
              if self.required:
                  raise DependencyException('Pkg-config not found.')
              return
          if self.want_cross:
              self.type_string = 'Cross'
          else:
              self.type_string = 'Native'
  
          mlog.debug('Determining dependency {!r} with pkg-config executable '
                     '{!r}'.format(name, self.pkgbin.get_path()))
          ret, self.version = self._call_pkgbin(['--modversion', name])
          if ret != 0:
              if self.required:
                  raise DependencyException('{} dependency {!r} not found'
                                            ''.format(self.type_string, name))
              return
          found_msg = [self.type_string + ' dependency', mlog.bold(name), 'found:']
          if self.version_reqs is None:
              self.is_found = True
          else:
              if not isinstance(self.version_reqs, (str, list)):
                  raise DependencyException('Version argument must be string or list.')
              if isinstance(self.version_reqs, str):
                  self.version_reqs = [self.version_reqs]
              (self.is_found, not_found, found) = \
                  version_compare_many(self.version, self.version_reqs)
              if not self.is_found:
                  found_msg += [mlog.red('NO'),
                                'found {!r} but need:'.format(self.version),
                                ', '.join(["'{}'".format(e) for e in not_found])]
                  if found:
                      found_msg += ['; matched:',
                                    ', '.join(["'{}'".format(e) for e in found])]
                  if not self.silent:
                      mlog.log(*found_msg)
                  if self.required:
                      m = 'Invalid version of dependency, need {!r} {!r} found {!r}.'
                      raise DependencyException(m.format(name, not_found, self.version))
                  return
  
          try:
              # Fetch cargs to be used while using this dependency
              self._set_cargs()
              # Fetch the libraries and library paths needed for using this
              self._set_libs()
              found_msg += [mlog.green('YES'), self.version]
          except DependencyException as e:
              if self.required:
                  raise
              else:
                  self.compile_args = []
                  self.link_args = []
                  self
  
  [... the rest is omitted ...]
files.new_path: mesonbuild/dependencies/base.py
files.old_contents: # Copyright 2013-2018 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.
  # Custom logic for several other packages are in separate files.
  
  import copy
  import os
  import re
  import stat
  import shlex
  import shutil
  import textwrap
  from enum import Enum
  from pathlib import PurePath
  
  from .. import mlog
  from .. import mesonlib
  from ..compilers import clib_langs, clike_langs
  from ..mesonlib import MesonException, OrderedSet
  from ..mesonlib import Popen_safe, version_compare_many, version_compare, listify
  
  
  # These must be defined in this file to avoid cyclical references.
  packages = {}
  _packages_accept_language = set()
  
  
  class DependencyException(MesonException):
      '''Exceptions raised while trying to find dependencies'''
  
  
  class DependencyMethods(Enum):
      # Auto means to use whatever dependency checking mechanisms in whatever order meson thinks is best.
      AUTO = 'auto'
      PKGCONFIG = 'pkg-config'
      QMAKE = 'qmake'
      # Just specify the standard link arguments, assuming the operating system provides the library.
      SYSTEM = 'system'
      # This is only supported on OSX - search the frameworks directory by name.
      EXTRAFRAMEWORK = 'extraframework'
      # Detect using the sysconfig module.
      SYSCONFIG = 'sysconfig'
      # Specify using a "program"-config style tool
      CONFIG_TOOL = 'config-tool'
      # For backewards compatibility
      SDLCONFIG = 'sdlconfig'
      CUPSCONFIG = 'cups-config'
      PCAPCONFIG = 'pcap-config'
      LIBWMFCONFIG = 'libwmf-config'
  
  
  class Dependency:
      @classmethod
      def _process_method_kw(cls, kwargs):
          method = kwargs.get('method', 'auto')
          if method not in [e.value for e in DependencyMethods]:
              raise DependencyException('method {!r} is invalid'.format(method))
          method = DependencyMethods(method)
  
          # This sets per-tool config methods which are deprecated to to the new
          # generic CONFIG_TOOL value.
          if method in [DependencyMethods.SDLCONFIG, DependencyMethods.CUPSCONFIG,
                        DependencyMethods.PCAPCONFIG, DependencyMethods.LIBWMFCONFIG]:
              mlog.warning(textwrap.dedent("""\
                  Configuration method {} has been deprecated in favor of
                  'config-tool'. This will be removed in a future version of
                  meson.""".format(method)))
              method = DependencyMethods.CONFIG_TOOL
  
          # Set the detection method. If the method is set to auto, use any available method.
          # If method is set to a specific string, allow only that detection method.
          if method == DependencyMethods.AUTO:
              methods = cls.get_methods()
          elif method in cls.get_methods():
              methods = [method]
          else:
              raise DependencyException(
                  'Unsupported detection method: {}, allowed methods are {}'.format(
                      method.value,
                      mlog.format_list([x.value for x in [DependencyMethods.AUTO] + cls.get_methods()])))
  
          return methods
  
      def __init__(self, type_name, kwargs):
          self.name = "null"
          self.version = 'none'
          self.language = None # None means C-like
          self.is_found = False
          self.type_name = type_name
          self.compile_args = []
          self.link_args = []
          self.sources = []
          self.methods = self._process_method_kw(kwargs)
  
      def __repr__(self):
          s = '<{0} {1}: {2}>'
          return s.format(self.__class__.__name__, self.name, self.is_found)
  
      def get_compile_args(self):
          return self.compile_args
  
      def get_link_args(self):
          return self.link_args
  
      def found(self):
          return self.is_found
  
      def get_sources(self):
          """Source files that need to be added to the target.
          As an example, gtest-all.cc when using GTest."""
          return self.sources
  
      @staticmethod
      def get_methods():
          return [DependencyMethods.AUTO]
  
      def get_name(self):
          return self.name
  
      def get_version(self):
          return self.version
  
      def get_exe_args(self, compiler):
          return []
  
      def need_openmp(self):
          return False
  
      def need_threads(self):
          return False
  
      def get_pkgconfig_variable(self, variable_name, kwargs):
          raise DependencyException('{!r} is not a pkgconfig dependency'.format(self.name))
  
      def get_configtool_variable(self, variable_name):
          raise DependencyException('{!r} is not a config-tool dependency'.format(self.name))
  
      def get_partial_dependency(self, *, compile_args=False, link_args=False,
                                 links=False, includes=False, sources=False):
          """Create a new dependency that contains part of the parent dependency.
  
          The following options can be inherited:
              links -- all link_with arguemnts
              includes -- all include_directory and -I/-isystem calls
              sources -- any source, header, or generated sources
              compile_args -- any compile args
              link_args -- any link args
  
          Additionally the new dependency will have the version parameter of it's
          parent (if any) and the requested values of any dependencies will be
          added as well.
          """
          RuntimeError('Unreachable code in partial_dependency called')
  
  
  class InternalDependency(Dependency):
      def __init__(self, version, incdirs, compile_args, link_args, libraries, whole_libraries, sources, ext_deps):
          super().__init__('internal', {})
          self.version = version
          self.is_found = True
          self.include_directories = incdirs
          self.compile_args = compile_args
          self.link_args = link_args
          self.libraries = libraries
          self.whole_libraries = whole_libraries
          self.sources = sources
          self.ext_deps = ext_deps
  
      def get_pkgconfig_variable(self, variable_name, kwargs):
          raise DependencyException('Method "get_pkgconfig_variable()" is '
                                    'invalid for an internal dependency')
  
      def get_configtool_variable(self, variable_name):
          raise DependencyException('Method "get_configtool_variable()" is '
                                    'invalid for an internal dependency')
  
      def get_partial_dependency(self, *, compile_args=False, link_args=False,
                                 links=False, includes=False, sources=False):
          compile_args = self.compile_args.copy() if compile_args else []
          link_args = self.link_args.copy() if link_args else []
          libraries = self.libraries.copy() if links else []
          whole_libraries = self.whole_libraries.copy() if links else []
          sources = self.sources.copy() if sources else []
          includes = self.include_directories.copy() if includes else []
          deps = [d.get_partial_dependency(
              compile_args=compile_args, link_args=link_args, links=links,
              includes=includes, sources=sources) for d in self.ext_deps]
          return InternalDependency(
              self.version, includes, compile_args, link_args, libraries,
              whole_libraries, sources, deps)
  
  
  class ExternalDependency(Dependency):
      def __init__(self, type_name, environment, language, kwargs):
          super().__init__(type_name, kwargs)
          self.env = environment
          self.name = type_name # default
          self.is_found = False
          self.language = language
          self.version_reqs = kwargs.get('version', None)
          self.required = kwargs.get('required', True)
          self.silent = kwargs.get('silent', False)
          self.static = kwargs.get('static', False)
          if not isinstance(self.static, bool):
              raise DependencyException('Static keyword must be boolean')
          # Is this dependency for cross-compilation?
          if 'native' in kwargs and self.env.is_cross_build():
              self.want_cross = not kwargs['native']
          else:
              self.want_cross = self.env.is_cross_build()
          self.clib_compiler = None
          # Set the compiler that will be used by this dependency
          # This is only used for configuration checks
          if self.want_cross:
              compilers = self.env.coredata.cross_compilers
          else:
              compilers = self.env.coredata.compilers
          # Set the compiler for this dependency if a language is specified,
          # else try to pick something that looks usable.
          if self.language:
              if self.language not in compilers:
                  m = self.name.capitalize() + ' requires a {0} compiler, but ' \
                      '{0} is not in the list of project languages'
                  raise DependencyException(m.format(self.language.capitalize()))
              self.clib_compiler = compilers[self.language]
          else:
              # Try to find a compiler that can find C libraries for
              # running compiler.find_library()
              for lang in clib_langs:
                  self.clib_compiler = compilers.get(lang, None)
                  if self.clib_compiler:
                      break
  
      def get_compiler(self):
          return self.clib_compiler
  
      def get_partial_dependency(self, *, compile_args=False, link_args=False,
                                 links=False, includes=False, sources=False):
          new = copy.copy(self)
          if not compile_args:
              new.compile_args = []
          if not link_args:
              new.link_args = []
          if not sources:
              new.sources = []
  
          return new
  
  
  class NotFoundDependency(Dependency):
      def __init__(self, environment):
          super().__init__('not-found', {})
          self.env = environment
          self.name = 'not-found'
          self.is_found = False
  
  
  class ConfigToolDependency(ExternalDependency):
  
      """Class representing dependencies found using a config tool."""
  
      tools = None
      tool_name = None
      __strip_version = re.compile(r'^[0-9.]*')
  
      def __init__(self, name, environment, language, kwargs):
          super().__init__('config-tool', environment, language, kwargs)
          self.name = name
          self.native = kwargs.get('native', False)
          self.tools = listify(kwargs.get('tools', self.tools))
  
          req_version = kwargs.get('version', None)
          tool, version = self.find_config(req_version)
          self.config = tool
          self.is_found = self.report_config(version, req_version)
          if not self.is_found:
              self.config = None
              return
          self.version = version
  
      def _sanitize_version(self, version):
          """Remove any non-numeric, non-point version suffixes."""
          m = self.__strip_version.match(version)
          if m:
              # Ensure that there isn't a trailing '.', such as an input like
              # `1.2.3.git-1234`
              return m.group(0).rstrip('.')
          return version
  
      @classmethod
      def factory(cls, name, environment, language, kwargs, tools, tool_name):
          """Constructor for use in dependencies that can be found multiple ways.
  
          In addition to the standard constructor values, this constructor sets
          the tool_name and tools values of the instance.
          """
          # This deserves some explanation, because metaprogramming is hard.
          # This uses type() to create a dynamic subclass of ConfigToolDependency
          # with the tools and tool_name class attributes set, this class is then
          # instantiated and returned. The reduce function (method) is also
          # attached, since python's pickle module won't be able to do anything
          # with this dynamically generated class otherwise.
          def reduce(self):
              return (cls._unpickle, (), self.__dict__)
          sub = type('{}Dependency'.format(name.capitalize()), (cls, ),
                     {'tools': tools, 'tool_name': tool_name, '__reduce__': reduce})
  
          return sub(name, environment, language, kwargs)
  
      @classmethod
      def _unpickle(cls):
          return cls.__new__(cls)
  
      def find_config(self, versions=None):
          """Helper method that searchs for config tool binaries in PATH and
          returns the one that best matches the given version requirements.
          """
          if not isinstance(versions, list) and versions is not None:
              versions = listify(versions)
  
          if self.env.is_cross_build() and not self.native:
              cross_file = self.env.cross_info.config['binaries']
              try:
                  tools = [cross_file[self.tool_name]]
              except KeyError:
                  mlog.warning('No entry for {0} specified in your cross file. '
                               'Falling back to searching PATH. This may find a '
                               'native version of {0}!'.format(self.tool_name))
                  tools = self.tools
          else:
              tools = self.tools
  
          best_match = (None, None)
          for tool in tools:
              try:
                  p, out = Popen_safe([tool, '--version'])[:2]
              except (FileNotFoundError, PermissionError):
                  continue
              if p.returncode != 0:
                  continue
  
              out = self._sanitize_version(out.strip())
              # Some tools, like pcap-config don't supply a version, but also
              # don't fail with --version, in that case just assume that there is
              # only one version and return it.
              if not out:
                  return (tool, 'none')
              if versions:
                  is_found = version_compare_many(out, versions)[0]
                  # This allows returning a found version without a config tool,
                  # which is useful to inform the user that you found version x,
                  # but y was required.
                  if not is_found:
                      tool = None
              if best_match[1]:
                  if version_compare(out, '> {}'.format(best_match[1])):
                      best_match = (tool, out)
              else:
                  best_match = (tool, out)
  
          return best_match
  
      def report_config(self, version, req_version):
          """Helper method to print messages about the tool."""
          if self.config is None:
              if version is not None:
                  mlog.log('Found', mlog.bold(self.tool_name), repr(version),
                           mlog.red('NO'), '(needed', req_version, ')')
              else:
                  mlog.log('Found', mlog.bold(self.tool_name), repr(req_version),
                           mlog.red('NO'))
              mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.red('NO'))
              if self.required:
                  raise DependencyException('Dependency {} not found'.format(self.name))
              return False
          mlog.log('Found {}:'.format(self.tool_name), mlog.bold(shutil.which(self.config)),
                   '({})'.format(version))
          mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'))
          return True
  
      def get_config_value(self, args, stage):
          p, out, err = Popen_safe([self.config] + args)
          if p.returncode != 0:
              if self.required:
                  raise DependencyException(
                      'Could not generate {} for {}.\n{}'.format(
                          stage, self.name, err))
              return []
          return shlex.split(out)
  
      @staticmethod
      def get_methods():
          return [DependencyMethods.AUTO, DependencyMethods.CONFIG_TOOL]
  
      def get_configtool_variable(self, variable_name):
          p, out, _ = Popen_safe([self.config, '--{}'.format(variable_name)])
          if p.returncode != 0:
              if self.required:
                  raise DependencyException(
                      'Could not get variable "{}" for dependency {}'.format(
                          variable_name, self.name))
          variable = out.strip()
          mlog.debug('Got config-tool variable {} : {}'.format(variable_name, variable))
          return variable
  
  
  class PkgConfigDependency(ExternalDependency):
      # The class's copy of the pkg-config path. Avoids having to search for it
      # multiple times in the same Meson invocation.
      class_pkgbin = None
      # We cache all pkg-config subprocess invocations to avoid redundant calls
      pkgbin_cache = {}
  
      def __init__(self, name, environment, kwargs, language=None):
          super().__init__('pkgconfig', environment, language, kwargs)
          self.name = name
          self.is_libtool = False
          # Store a copy of the pkg-config path on the object itself so it is
          # stored in the pickled coredata and recovered.
          self.pkgbin = None
  
          # When finding dependencies for cross-compiling, we don't care about
          # the 'native' pkg-config
          if self.want_cross:
              if 'pkgconfig' not in environment.cross_info.config['binaries']:
                  if self.required:
                      raise DependencyException('Pkg-config binary missing from cross file')
              else:
                  pkgname = environment.cross_info.config['binaries']['pkgconfig']
                  potential_pkgbin = ExternalProgram(pkgname, silent=True)
                  if potential_pkgbin.found():
                      self.pkgbin = potential_pkgbin
                      PkgConfigDependency.class_pkgbin = self.pkgbin
                  else:
                      mlog.debug('Cross pkg-config %s not found.' % potential_pkgbin.name)
          # Only search for the native pkg-config the first time and
          # store the result in the class definition
          elif PkgConfigDependency.class_pkgbin is None:
              self.pkgbin = self.check_pkgconfig()
              PkgConfigDependency.class_pkgbin = self.pkgbin
          else:
              self.pkgbin = PkgConfigDependency.class_pkgbin
  
          if not self.pkgbin:
              if self.required:
                  raise DependencyException('Pkg-config not found.')
              return
          if self.want_cross:
              self.type_string = 'Cross'
          else:
              self.type_string = 'Native'
  
          mlog.debug('Determining dependency {!r} with pkg-config executable '
                     '{!r}'.format(name, self.pkgbin.get_path()))
          ret, self.version = self._call_pkgbin(['--modversion', name])
          if ret != 0:
              if self.required:
                  raise DependencyException('{} dependency {!r} not found'
                                            ''.format(self.type_string, name))
              return
          found_msg = [self.type_string + ' dependency', mlog.bold(name), 'found:']
          if self.version_reqs is None:
              self.is_found = True
          else:
              if not isinstance(self.version_reqs, (str, list)):
                  raise DependencyException('Version argument must be string or list.')
              if isinstance(self.version_reqs, str):
                  self.version_reqs = [self.version_reqs]
              (self.is_found, not_found, found) = \
                  version_compare_many(self.version, self.version_reqs)
              if not self.is_found:
                  found_msg += [mlog.red('NO'),
                                'found {!r} but need:'.format(self.version),
                                ', '.join(["'{}'".format(e) for e in not_found])]
                  if found:
                      found_msg += ['; matched:',
                                    ', '.join(["'{}'".format(e) for e in found])]
                  if not self.silent:
                      mlog.log(*found_msg)
                  if self.required:
                      m = 'Invalid version of dependency, need {!r} {!r} found {!r}.'
                      raise DependencyException(m.format(name, not_found, self.version))
                  return
  
          try:
              # Fetch cargs to be used while using this dependency
              self._set_cargs()
              # Fetch the libraries and library paths needed for using this
              self._set_libs()
              found_msg += [mlog.green('YES'), self.version]
          except DependencyException as e:
              if self.required:
                  raise
              else:
                  self.compile_args = []
                  self.link
  
  [... the rest is omitted ...]
files.old_path: mesonbuild/dependencies/base.py
files.new_contents: # Copyright 2013-2017 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 miscellaneous external dependencies.
  
  import os
  import re
  import shlex
  import sysconfig
  
  from pathlib import Path
  
  from .. import mlog
  from .. import mesonlib
  from ..environment import detect_cpu_family
  
  from .base import (
      DependencyException, DependencyMethods, ExternalDependency,
      ExternalProgram, ExtraFrameworkDependency, PkgConfigDependency,
      ConfigToolDependency,
  )
  
  from ..interpreterbase import FeatureNew
  
  class MPIDependency(ExternalDependency):
  
      @FeatureNew('MPI Dependency', '0.42.0')
      def __init__(self, environment, kwargs):
          language = kwargs.get('language', 'c')
          super().__init__('mpi', environment, language, kwargs)
          required = kwargs.pop('required', True)
          kwargs['required'] = False
          kwargs['silent'] = True
          self.is_found = False
  
          # NOTE: Only OpenMPI supplies a pkg-config file at the moment.
          if language == 'c':
              env_vars = ['MPICC']
              pkgconfig_files = ['ompi-c']
              default_wrappers = ['mpicc']
          elif language == 'cpp':
              env_vars = ['MPICXX']
              pkgconfig_files = ['ompi-cxx']
              default_wrappers = ['mpic++', 'mpicxx', 'mpiCC']
          elif language == 'fortran':
              env_vars = ['MPIFC', 'MPIF90', 'MPIF77']
              pkgconfig_files = ['ompi-fort']
              default_wrappers = ['mpifort', 'mpif90', 'mpif77']
          else:
              raise DependencyException('Language {} is not supported with MPI.'.format(language))
  
          for pkg in pkgconfig_files:
              try:
                  pkgdep = PkgConfigDependency(pkg, environment, kwargs, language=self.language)
                  if pkgdep.found():
                      self.compile_args = pkgdep.get_compile_args()
                      self.link_args = pkgdep.get_link_args()
                      self.version = pkgdep.get_version()
                      self.is_found = True
                      self.pcdep = pkgdep
                      break
              except Exception:
                  pass
  
          if not self.is_found:
              # Prefer environment.
              for var in env_vars:
                  if var in os.environ:
                      wrappers = [os.environ[var]]
                      break
              else:
                  # Or search for default wrappers.
                  wrappers = default_wrappers
  
              for prog in wrappers:
                  result = self._try_openmpi_wrapper(prog)
                  if result is not None:
                      self.is_found = True
                      self.version = result[0]
                      self.compile_args = self._filter_compile_args(result[1])
                      self.link_args = self._filter_link_args(result[2])
                      break
                  result = self._try_other_wrapper(prog)
                  if result is not None:
                      self.is_found = True
                      self.version = result[0]
                      self.compile_args = self._filter_compile_args(result[1])
                      self.link_args = self._filter_link_args(result[2])
                      break
  
          if not self.is_found and mesonlib.is_windows():
              result = self._try_msmpi()
              if result is not None:
                  self.is_found = True
                  self.version, self.compile_args, self.link_args = result
  
          if self.is_found:
              mlog.log('Dependency', mlog.bold(self.name), 'for', self.language, 'found:', mlog.green('YES'), self.version)
          else:
              mlog.log('Dependency', mlog.bold(self.name), 'for', self.language, 'found:', mlog.red('NO'))
              if required:
                  raise DependencyException('MPI dependency {!r} not found'.format(self.name))
  
      def _filter_compile_args(self, args):
          """
          MPI wrappers return a bunch of garbage args.
          Drop -O2 and everything that is not needed.
          """
          result = []
          multi_args = ('-I', )
          if self.language == 'fortran':
              fc = self.env.coredata.compilers['fortran']
              multi_args += fc.get_module_incdir_args()
  
          include_next = False
          for f in args:
              if f.startswith(('-D', '-f') + multi_args) or f == '-pthread' \
                      or (f.startswith('-W') and f != '-Wall' and not f.startswith('-Werror')):
                  result.append(f)
                  if f in multi_args:
                      # Path is a separate argument.
                      include_next = True
              elif include_next:
                  include_next = False
                  result.append(f)
          return result
  
      def _filter_link_args(self, args):
          """
          MPI wrappers return a bunch of garbage args.
          Drop -O2 and everything that is not needed.
          """
          result = []
          include_next = False
          for f in args:
              if f.startswith(('-L', '-l', '-Xlinker')) or f == '-pthread' \
                      or (f.startswith('-W') and f != '-Wall' and not f.startswith('-Werror')):
                  result.append(f)
                  if f in ('-L', '-Xlinker'):
                      include_next = True
              elif include_next:
                  include_next = False
                  result.append(f)
          return result
  
      def _try_openmpi_wrapper(self, prog):
          prog = ExternalProgram(prog, silent=True)
          if prog.found():
              cmd = prog.get_command() + ['--showme:compile']
              p, o, e = mesonlib.Popen_safe(cmd)
              p.wait()
              if p.returncode != 0:
                  mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
                  mlog.debug(mlog.bold('Standard output\n'), o)
                  mlog.debug(mlog.bold('Standard error\n'), e)
                  return
              cargs = shlex.split(o)
  
              cmd = prog.get_command() + ['--showme:link']
              p, o, e = mesonlib.Popen_safe(cmd)
              p.wait()
              if p.returncode != 0:
                  mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
                  mlog.debug(mlog.bold('Standard output\n'), o)
                  mlog.debug(mlog.bold('Standard error\n'), e)
                  return
              libs = shlex.split(o)
  
              cmd = prog.get_command() + ['--showme:version']
              p, o, e = mesonlib.Popen_safe(cmd)
              p.wait()
              if p.returncode != 0:
                  mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
                  mlog.debug(mlog.bold('Standard output\n'), o)
                  mlog.debug(mlog.bold('Standard error\n'), e)
                  return
              version = re.search('\d+.\d+.\d+', o)
              if version:
                  version = version.group(0)
              else:
                  version = 'none'
  
              return version, cargs, libs
  
      def _try_other_wrapper(self, prog):
          prog = ExternalProgram(prog, silent=True)
          if prog.found():
              cmd = prog.get_command() + ['-show']
              p, o, e = mesonlib.Popen_safe(cmd)
              p.wait()
              if p.returncode != 0:
                  mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
                  mlog.debug(mlog.bold('Standard output\n'), o)
                  mlog.debug(mlog.bold('Standard error\n'), e)
                  return
              args = shlex.split(o)
  
              version = 'none'
  
              return version, args, args
  
      def _try_msmpi(self):
          if self.language == 'cpp':
              # MS-MPI does not support the C++ version of MPI, only the standard C API.
              return
          if 'MSMPI_INC' not in os.environ:
              return
          incdir = os.environ['MSMPI_INC']
          arch = detect_cpu_family(self.env.coredata.compilers)
          if arch == 'x86':
              if 'MSMPI_LIB32' not in os.environ:
                  return
              libdir = os.environ['MSMPI_LIB32']
              post = 'x86'
          elif arch == 'x86_64':
              if 'MSMPI_LIB64' not in os.environ:
                  return
              libdir = os.environ['MSMPI_LIB64']
              post = 'x64'
          else:
              return
          if self.language == 'fortran':
              return ('none',
                      ['-I' + incdir, '-I' + os.path.join(incdir, post)],
                      [os.path.join(libdir, 'msmpi.lib'), os.path.join(libdir, 'msmpifec.lib')])
          else:
              return ('none',
                      ['-I' + incdir, '-I' + os.path.join(incdir, post)],
                      [os.path.join(libdir, 'msmpi.lib')])
  
  
  class OpenMPDependency(ExternalDependency):
      # Map date of specification release (which is the macro value) to a version.
      VERSIONS = {
          '201511': '4.5',
          '201307': '4.0',
          '201107': '3.1',
          '200805': '3.0',
          '200505': '2.5',
          '200203': '2.0',
          '199810': '1.0',
      }
  
      @FeatureNew('OpenMP Dependency', '0.46.0')
      def __init__(self, environment, kwargs):
          language = kwargs.get('language')
          super().__init__('openmp', environment, language, kwargs)
          self.is_found = False
          try:
              openmp_date = self.clib_compiler.get_define('_OPENMP', '', self.env, [], [self])
          except mesonlib.EnvironmentException as e:
              mlog.debug('OpenMP support not available in the compiler')
              mlog.debug(e)
              openmp_date = False
  
          if openmp_date:
              self.version = self.VERSIONS[openmp_date]
              if self.clib_compiler.has_header('omp.h', '', self.env, dependencies=[self]):
                  self.is_found = True
              else:
                  mlog.log(mlog.yellow('WARNING:'), 'OpenMP found but omp.h missing.')
          if self.is_found:
              mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'), self.version)
          else:
              mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.red('NO'))
  
      def need_openmp(self):
          return True
  
  
  class ThreadDependency(ExternalDependency):
      def __init__(self, environment, kwargs):
          super().__init__('threads', environment, None, {})
          self.name = 'threads'
          self.is_found = True
          mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'))
  
      def need_threads(self):
          return True
  
      def get_version(self):
          return 'unknown'
  
  
  class Python3Dependency(ExternalDependency):
      def __init__(self, environment, kwargs):
          super().__init__('python3', environment, None, kwargs)
          self.name = 'python3'
          self.static = kwargs.get('static', False)
          # We can only be sure that it is Python 3 at this point
          self.version = '3'
          self.pkgdep = None
          if DependencyMethods.PKGCONFIG in self.methods:
              try:
                  self.pkgdep = PkgConfigDependency('python3', environment, kwargs)
                  if self.pkgdep.found():
                      self.compile_args = self.pkgdep.get_compile_args()
                      self.link_args = self.pkgdep.get_link_args()
                      self.version = self.pkgdep.get_version()
                      self.is_found = True
                      self.pcdep = self.pkgdep
                      return
                  else:
                      self.pkgdep = None
              except Exception:
                  pass
          if not self.is_found:
              if mesonlib.is_windows() and DependencyMethods.SYSCONFIG in self.methods:
                  self._find_libpy3_windows(environment)
              elif mesonlib.is_osx() and DependencyMethods.EXTRAFRAMEWORK in self.methods:
                  # In OSX the Python 3 framework does not have a version
                  # number in its name.
                  # There is a python in /System/Library/Frameworks, but that's
                  # python 2, Python 3 will always bin in /Library
                  fw = ExtraFrameworkDependency(
                      'python', False, '/Library/Frameworks', self.env, self.language, kwargs)
                  if fw.found():
                      self.compile_args = fw.get_compile_args()
                      self.link_args = fw.get_link_args()
                      self.is_found = True
          if self.is_found:
              mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'))
          else:
              mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.red('NO'))
  
      @staticmethod
      def get_windows_python_arch():
          pyplat = sysconfig.get_platform()
          if pyplat == 'mingw':
              pycc = sysconfig.get_config_var('CC')
              if pycc.startswith('x86_64'):
                  return '64'
              elif pycc.startswith(('i686', 'i386')):
                  return '32'
              else:
                  mlog.log('MinGW Python built with unknown CC {!r}, please file'
                           'a bug'.format(pycc))
                  return None
          elif pyplat == 'win32':
              return '32'
          elif pyplat in ('win64', 'win-amd64'):
              return '64'
          mlog.log('Unknown Windows Python platform {!r}'.format(pyplat))
          return None
  
      def get_windows_link_args(self):
          pyplat = sysconfig.get_platform()
          if pyplat.startswith('win'):
              vernum = sysconfig.get_config_var('py_version_nodot')
              if self.static:
                  libname = 'libpython{}.a'.format(vernum)
              else:
                  libname = 'python{}.lib'.format(vernum)
              lib = Path(sysconfig.get_config_var('base')) / 'libs' / libname
          elif pyplat == 'mingw':
              if self.static:
                  libname = sysconfig.get_config_var('LIBRARY')
              else:
                  libname = sysconfig.get_config_var('LDLIBRARY')
              lib = Path(sysconfig.get_config_var('LIBDIR')) / libname
          if not lib.exists():
              mlog.log('Could not find Python3 library {!r}'.format(str(lib)))
              return None
          return [str(lib)]
  
      def _find_libpy3_windows(self, env):
          '''
          Find python3 libraries on Windows and also verify that the arch matches
          what we are building for.
          '''
          pyarch = self.get_windows_python_arch()
          if pyarch is None:
              self.is_found = False
              return
          arch = detect_cpu_family(env.coredata.compilers)
          if arch == 'x86':
              arch = '32'
          elif arch == 'x86_64':
              arch = '64'
          else:
              # We can't cross-compile Python 3 dependencies on Windows yet
              mlog.log('Unknown architecture {!r} for'.format(arch),
                       mlog.bold(self.name))
              self.is_found = False
              return
          # Pyarch ends in '32' or '64'
          if arch != pyarch:
              mlog.log('Need', mlog.bold(self.name), 'for {}-bit, but '
                       'found {}-bit'.format(arch, pyarch))
              self.is_found = False
              return
          # This can fail if the library is not found
          largs = self.get_windows_link_args()
          if largs is None:
              self.is_found = False
              return
          self.link_args = largs
          # Compile args
          inc = sysconfig.get_path('include')
          platinc = sysconfig.get_path('platinclude')
          self.compile_args = ['-I' + inc]
          if inc != platinc:
              self.compile_args.append('-I' + platinc)
          self.version = sysconfig.get_config_var('py_version')
          self.is_found = True
  
      @staticmethod
      def get_methods():
          if mesonlib.is_windows():
              return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSCONFIG]
          elif mesonlib.is_osx():
              return [DependencyMethods.PKGCONFIG, DependencyMethods.EXTRAFRAMEWORK]
          else:
              return [DependencyMethods.PKGCONFIG]
  
      def get_pkgconfig_variable(self, variable_name, kwargs):
          if self.pkgdep:
              return self.pkgdep.get_pkgconfig_variable(variable_name, kwargs)
          else:
              return super().get_pkgconfig_variable(variable_name, kwargs)
  
  
  class PcapDependency(ExternalDependency):
  
      @FeatureNew('Pcap Dependency', '0.42.0')
      def __init__(self, environment, kwargs):
          super().__init__('pcap', environment, None, kwargs)
  
      @classmethod
      def _factory(cls, environment, kwargs):
          methods = cls._process_method_kw(kwargs)
          if DependencyMethods.PKGCONFIG in methods:
              try:
                  pcdep = PkgConfigDependency('pcap', environment, kwargs)
                  if pcdep.found():
                      return pcdep
              except Exception as e:
                  mlog.debug('Pcap not found via pkgconfig. Trying next, error was:', str(e))
          if DependencyMethods.CONFIG_TOOL in methods:
              try:
                  ctdep = ConfigToolDependency.factory(
                      'pcap', environment, None, kwargs, ['pcap-config'], 'pcap-config')
                  if ctdep.found():
                      ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
                      ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args')
                      ctdep.version = cls.get_pcap_lib_version(ctdep)
                      return ctdep
              except Exception as e:
                  mlog.debug('Pcap not found via pcap-config. Trying next, error was:', str(e))
  
          return PcapDependency(environment, kwargs)
  
      @staticmethod
      def get_methods():
          if mesonlib.is_osx():
              return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK]
          else:
              return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]
  
      @staticmethod
      def get_pcap_lib_version(ctdep):
          return ctdep.clib_compiler.get_return_value('pcap_lib_version', 'string',
                                                      '#include <pcap.h>', ctdep.env, [], [ctdep])
  
  
  class CupsDependency(ExternalDependency):
      def __init__(self, environment, kwargs):
          super().__init__('cups', environment, None, kwargs)
  
      @classmethod
      def _factory(cls, environment, kwargs):
          methods = cls._process_method_kw(kwargs)
          if DependencyMethods.PKGCONFIG in methods:
              try:
                  pcdep = PkgConfigDependency('cups
  
  [... the rest is omitted ...]
files.new_path: mesonbuild/dependencies/misc.py
files.old_contents: # Copyright 2013-2017 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 miscellaneous external dependencies.
  
  import os
  import re
  import shlex
  import sysconfig
  
  from pathlib import Path
  
  from .. import mlog
  from .. import mesonlib
  from ..environment import detect_cpu_family
  
  from .base import (
      DependencyException, DependencyMethods, ExternalDependency,
      ExternalProgram, ExtraFrameworkDependency, PkgConfigDependency,
      ConfigToolDependency,
  )
  
  from ..interpreterbase import FeatureNew
  
  class MPIDependency(ExternalDependency):
  
      @FeatureNew('MPI Dependency', '0.42.0')
      def __init__(self, environment, kwargs):
          language = kwargs.get('language', 'c')
          super().__init__('mpi', environment, language, kwargs)
          required = kwargs.pop('required', True)
          kwargs['required'] = False
          kwargs['silent'] = True
          self.is_found = False
  
          # NOTE: Only OpenMPI supplies a pkg-config file at the moment.
          if language == 'c':
              env_vars = ['MPICC']
              pkgconfig_files = ['ompi-c']
              default_wrappers = ['mpicc']
          elif language == 'cpp':
              env_vars = ['MPICXX']
              pkgconfig_files = ['ompi-cxx']
              default_wrappers = ['mpic++', 'mpicxx', 'mpiCC']
          elif language == 'fortran':
              env_vars = ['MPIFC', 'MPIF90', 'MPIF77']
              pkgconfig_files = ['ompi-fort']
              default_wrappers = ['mpifort', 'mpif90', 'mpif77']
          else:
              raise DependencyException('Language {} is not supported with MPI.'.format(language))
  
          for pkg in pkgconfig_files:
              try:
                  pkgdep = PkgConfigDependency(pkg, environment, kwargs, language=self.language)
                  if pkgdep.found():
                      self.compile_args = pkgdep.get_compile_args()
                      self.link_args = pkgdep.get_link_args()
                      self.version = pkgdep.get_version()
                      self.is_found = True
                      self.pcdep = pkgdep
                      break
              except Exception:
                  pass
  
          if not self.is_found:
              # Prefer environment.
              for var in env_vars:
                  if var in os.environ:
                      wrappers = [os.environ[var]]
                      break
              else:
                  # Or search for default wrappers.
                  wrappers = default_wrappers
  
              for prog in wrappers:
                  result = self._try_openmpi_wrapper(prog)
                  if result is not None:
                      self.is_found = True
                      self.version = result[0]
                      self.compile_args = self._filter_compile_args(result[1])
                      self.link_args = self._filter_link_args(result[2])
                      break
                  result = self._try_other_wrapper(prog)
                  if result is not None:
                      self.is_found = True
                      self.version = result[0]
                      self.compile_args = self._filter_compile_args(result[1])
                      self.link_args = self._filter_link_args(result[2])
                      break
  
          if not self.is_found and mesonlib.is_windows():
              result = self._try_msmpi()
              if result is not None:
                  self.is_found = True
                  self.version, self.compile_args, self.link_args = result
  
          if self.is_found:
              mlog.log('Dependency', mlog.bold(self.name), 'for', self.language, 'found:', mlog.green('YES'), self.version)
          else:
              mlog.log('Dependency', mlog.bold(self.name), 'for', self.language, 'found:', mlog.red('NO'))
              if required:
                  raise DependencyException('MPI dependency {!r} not found'.format(self.name))
  
      def _filter_compile_args(self, args):
          """
          MPI wrappers return a bunch of garbage args.
          Drop -O2 and everything that is not needed.
          """
          result = []
          multi_args = ('-I', )
          if self.language == 'fortran':
              fc = self.env.coredata.compilers['fortran']
              multi_args += fc.get_module_incdir_args()
  
          include_next = False
          for f in args:
              if f.startswith(('-D', '-f') + multi_args) or f == '-pthread' \
                      or (f.startswith('-W') and f != '-Wall' and not f.startswith('-Werror')):
                  result.append(f)
                  if f in multi_args:
                      # Path is a separate argument.
                      include_next = True
              elif include_next:
                  include_next = False
                  result.append(f)
          return result
  
      def _filter_link_args(self, args):
          """
          MPI wrappers return a bunch of garbage args.
          Drop -O2 and everything that is not needed.
          """
          result = []
          include_next = False
          for f in args:
              if f.startswith(('-L', '-l', '-Xlinker')) or f == '-pthread' \
                      or (f.startswith('-W') and f != '-Wall' and not f.startswith('-Werror')):
                  result.append(f)
                  if f in ('-L', '-Xlinker'):
                      include_next = True
              elif include_next:
                  include_next = False
                  result.append(f)
          return result
  
      def _try_openmpi_wrapper(self, prog):
          prog = ExternalProgram(prog, silent=True)
          if prog.found():
              cmd = prog.get_command() + ['--showme:compile']
              p, o, e = mesonlib.Popen_safe(cmd)
              p.wait()
              if p.returncode != 0:
                  mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
                  mlog.debug(mlog.bold('Standard output\n'), o)
                  mlog.debug(mlog.bold('Standard error\n'), e)
                  return
              cargs = shlex.split(o)
  
              cmd = prog.get_command() + ['--showme:link']
              p, o, e = mesonlib.Popen_safe(cmd)
              p.wait()
              if p.returncode != 0:
                  mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
                  mlog.debug(mlog.bold('Standard output\n'), o)
                  mlog.debug(mlog.bold('Standard error\n'), e)
                  return
              libs = shlex.split(o)
  
              cmd = prog.get_command() + ['--showme:version']
              p, o, e = mesonlib.Popen_safe(cmd)
              p.wait()
              if p.returncode != 0:
                  mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
                  mlog.debug(mlog.bold('Standard output\n'), o)
                  mlog.debug(mlog.bold('Standard error\n'), e)
                  return
              version = re.search('\d+.\d+.\d+', o)
              if version:
                  version = version.group(0)
              else:
                  version = 'none'
  
              return version, cargs, libs
  
      def _try_other_wrapper(self, prog):
          prog = ExternalProgram(prog, silent=True)
          if prog.found():
              cmd = prog.get_command() + ['-show']
              p, o, e = mesonlib.Popen_safe(cmd)
              p.wait()
              if p.returncode != 0:
                  mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
                  mlog.debug(mlog.bold('Standard output\n'), o)
                  mlog.debug(mlog.bold('Standard error\n'), e)
                  return
              args = shlex.split(o)
  
              version = 'none'
  
              return version, args, args
  
      def _try_msmpi(self):
          if self.language == 'cpp':
              # MS-MPI does not support the C++ version of MPI, only the standard C API.
              return
          if 'MSMPI_INC' not in os.environ:
              return
          incdir = os.environ['MSMPI_INC']
          arch = detect_cpu_family(self.env.coredata.compilers)
          if arch == 'x86':
              if 'MSMPI_LIB32' not in os.environ:
                  return
              libdir = os.environ['MSMPI_LIB32']
              post = 'x86'
          elif arch == 'x86_64':
              if 'MSMPI_LIB64' not in os.environ:
                  return
              libdir = os.environ['MSMPI_LIB64']
              post = 'x64'
          else:
              return
          if self.language == 'fortran':
              return ('none',
                      ['-I' + incdir, '-I' + os.path.join(incdir, post)],
                      [os.path.join(libdir, 'msmpi.lib'), os.path.join(libdir, 'msmpifec.lib')])
          else:
              return ('none',
                      ['-I' + incdir, '-I' + os.path.join(incdir, post)],
                      [os.path.join(libdir, 'msmpi.lib')])
  
  
  class OpenMPDependency(ExternalDependency):
      # Map date of specification release (which is the macro value) to a version.
      VERSIONS = {
          '201511': '4.5',
          '201307': '4.0',
          '201107': '3.1',
          '200805': '3.0',
          '200505': '2.5',
          '200203': '2.0',
          '199810': '1.0',
      }
  
      @FeatureNew('OpenMP Dependency', '0.46.0')
      def __init__(self, environment, kwargs):
          language = kwargs.get('language')
          super().__init__('openmp', environment, language, kwargs)
          self.is_found = False
          try:
              openmp_date = self.clib_compiler.get_define('_OPENMP', '', self.env, [], [self])
          except mesonlib.EnvironmentException as e:
              mlog.debug('OpenMP support not available in the compiler')
              mlog.debug(e)
              openmp_date = False
  
          if openmp_date:
              self.version = self.VERSIONS[openmp_date]
              if self.clib_compiler.has_header('omp.h', '', self.env, dependencies=[self]):
                  self.is_found = True
              else:
                  mlog.log(mlog.yellow('WARNING:'), 'OpenMP found but omp.h missing.')
          if self.is_found:
              mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'), self.version)
          else:
              mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.red('NO'))
  
      def need_openmp(self):
          return True
  
  
  class ThreadDependency(ExternalDependency):
      def __init__(self, environment, kwargs):
          super().__init__('threads', environment, None, {})
          self.name = 'threads'
          self.is_found = True
          mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'))
  
      def need_threads(self):
          return True
  
      def get_version(self):
          return 'unknown'
  
  
  class Python3Dependency(ExternalDependency):
      def __init__(self, environment, kwargs):
          super().__init__('python3', environment, None, kwargs)
          self.name = 'python3'
          self.static = kwargs.get('static', False)
          # We can only be sure that it is Python 3 at this point
          self.version = '3'
          self.pkgdep = None
          if DependencyMethods.PKGCONFIG in self.methods:
              try:
                  self.pkgdep = PkgConfigDependency('python3', environment, kwargs)
                  if self.pkgdep.found():
                      self.compile_args = self.pkgdep.get_compile_args()
                      self.link_args = self.pkgdep.get_link_args()
                      self.version = self.pkgdep.get_version()
                      self.is_found = True
                      self.pcdep = self.pkgdep
                      return
                  else:
                      self.pkgdep = None
              except Exception:
                  pass
          if not self.is_found:
              if mesonlib.is_windows() and DependencyMethods.SYSCONFIG in self.methods:
                  self._find_libpy3_windows(environment)
              elif mesonlib.is_osx() and DependencyMethods.EXTRAFRAMEWORK in self.methods:
                  # In OSX the Python 3 framework does not have a version
                  # number in its name.
                  # There is a python in /System/Library/Frameworks, but that's
                  # python 2, Python 3 will always bin in /Library
                  fw = ExtraFrameworkDependency(
                      'python', False, '/Library/Frameworks', self.env, self.language, kwargs)
                  if fw.found():
                      self.compile_args = fw.get_compile_args()
                      self.link_args = fw.get_link_args()
                      self.is_found = True
          if self.is_found:
              mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'))
          else:
              mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.red('NO'))
  
      @staticmethod
      def get_windows_python_arch():
          pyplat = sysconfig.get_platform()
          if pyplat == 'mingw':
              pycc = sysconfig.get_config_var('CC')
              if pycc.startswith('x86_64'):
                  return '64'
              elif pycc.startswith(('i686', 'i386')):
                  return '32'
              else:
                  mlog.log('MinGW Python built with unknown CC {!r}, please file'
                           'a bug'.format(pycc))
                  return None
          elif pyplat == 'win32':
              return '32'
          elif pyplat in ('win64', 'win-amd64'):
              return '64'
          mlog.log('Unknown Windows Python platform {!r}'.format(pyplat))
          return None
  
      def get_windows_link_args(self):
          pyplat = sysconfig.get_platform()
          if pyplat.startswith('win'):
              vernum = sysconfig.get_config_var('py_version_nodot')
              if self.static:
                  libname = 'libpython{}.a'.format(vernum)
              else:
                  libname = 'python{}.lib'.format(vernum)
              lib = Path(sysconfig.get_config_var('base')) / 'libs' / libname
          elif pyplat == 'mingw':
              if self.static:
                  libname = sysconfig.get_config_var('LIBRARY')
              else:
                  libname = sysconfig.get_config_var('LDLIBRARY')
              lib = Path(sysconfig.get_config_var('LIBDIR')) / libname
          if not lib.exists():
              mlog.log('Could not find Python3 library {!r}'.format(str(lib)))
              return None
          return [str(lib)]
  
      def _find_libpy3_windows(self, env):
          '''
          Find python3 libraries on Windows and also verify that the arch matches
          what we are building for.
          '''
          pyarch = self.get_windows_python_arch()
          if pyarch is None:
              self.is_found = False
              return
          arch = detect_cpu_family(env.coredata.compilers)
          if arch == 'x86':
              arch = '32'
          elif arch == 'x86_64':
              arch = '64'
          else:
              # We can't cross-compile Python 3 dependencies on Windows yet
              mlog.log('Unknown architecture {!r} for'.format(arch),
                       mlog.bold(self.name))
              self.is_found = False
              return
          # Pyarch ends in '32' or '64'
          if arch != pyarch:
              mlog.log('Need', mlog.bold(self.name), 'for {}-bit, but '
                       'found {}-bit'.format(arch, pyarch))
              self.is_found = False
              return
          # This can fail if the library is not found
          largs = self.get_windows_link_args()
          if largs is None:
              self.is_found = False
              return
          self.link_args = largs
          # Compile args
          inc = sysconfig.get_path('include')
          platinc = sysconfig.get_path('platinclude')
          self.compile_args = ['-I' + inc]
          if inc != platinc:
              self.compile_args.append('-I' + platinc)
          self.version = sysconfig.get_config_var('py_version')
          self.is_found = True
  
      @staticmethod
      def get_methods():
          if mesonlib.is_windows():
              return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSCONFIG]
          elif mesonlib.is_osx():
              return [DependencyMethods.PKGCONFIG, DependencyMethods.EXTRAFRAMEWORK]
          else:
              return [DependencyMethods.PKGCONFIG]
  
      def get_pkgconfig_variable(self, variable_name, kwargs):
          if self.pkgdep:
              return self.pkgdep.get_pkgconfig_variable(variable_name, kwargs)
          else:
              return super().get_pkgconfig_variable(variable_name, kwargs)
  
  
  class PcapDependency(ExternalDependency):
  
      @FeatureNew('Pcap Dependency', '0.42.0')
      def __init__(self, environment, kwargs):
          super().__init__('pcap', environment, None, kwargs)
  
      @classmethod
      def _factory(cls, environment, kwargs):
          methods = cls._process_method_kw(kwargs)
          if DependencyMethods.PKGCONFIG in methods:
              try:
                  pcdep = PkgConfigDependency('pcap', environment, kwargs)
                  if pcdep.found():
                      return pcdep
              except Exception as e:
                  mlog.debug('Pcap not found via pkgconfig. Trying next, error was:', str(e))
          if DependencyMethods.CONFIG_TOOL in methods:
              try:
                  ctdep = ConfigToolDependency.factory(
                      'pcap', environment, None, kwargs, ['pcap-config'], 'pcap-config')
                  if ctdep.found():
                      ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
                      ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args')
                      ctdep.version = cls.get_pcap_lib_version(ctdep)
                      return ctdep
              except Exception as e:
                  mlog.debug('Pcap not found via pcap-config. Trying next, error was:', str(e))
  
          return PcapDependency(environment, kwargs)
  
      @staticmethod
      def get_methods():
          if mesonlib.is_osx():
              return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK]
          else:
              return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]
  
      @staticmethod
      def get_pcap_lib_version(ctdep):
          return ctdep.compiler.get_return_value('pcap_lib_version', 'string',
                                                 '#include <pcap.h>', ctdep.env, [], [ctdep])
  
  
  class CupsDependency(ExternalDependency):
      def __init__(self, environment, kwargs):
          super().__init__('cups', environment, None, kwargs)
  
      @classmethod
      def _factory(cls, environment, kwargs):
          methods = cls._process_method_kw(kwargs)
          if DependencyMethods.PKGCONFIG in methods:
              try:
                  pcdep = PkgConfigDependency('cups', environment,
  
  [... the rest is omitted ...]
files.old_path: mesonbuild/dependencies/misc.py
files.new_contents: # Copyright 2012-2018 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 . import mparser
  from . import environment
  from . import coredata
  from . import dependencies
  from . import mlog
  from . import build
  from . import optinterpreter
  from . import compilers
  from .wrap import wrap, WrapMode
  from . import mesonlib
  from .mesonlib import FileMode, Popen_safe, listify, extract_as_list, has_path_sep
  from .dependencies import ExternalProgram
  from .dependencies import InternalDependency, Dependency, NotFoundDependency, DependencyException
  from .interpreterbase import InterpreterBase
  from .interpreterbase import check_stringlist, flatten, noPosargs, noKwargs, stringArgs, permittedKwargs, noArgsFlattening
  from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode, SubdirDoneRequest
  from .interpreterbase import InterpreterObject, MutableInterpreterObject, Disabler
  from .interpreterbase import FeatureNew, FeatureDeprecated, FeatureNewKwargs
  from .modules import ModuleReturnValue
  
  import os, sys, shutil, uuid
  import re, shlex
  import subprocess
  from collections import namedtuple
  from pathlib import PurePath
  
  import importlib
  
  permitted_method_kwargs = {
      'partial_dependency': {'compile_args', 'link_args', 'links', 'includes',
                             'sources'},
  }
  
  def stringifyUserArguments(args):
      if isinstance(args, list):
          return '[%s]' % ', '.join([stringifyUserArguments(x) for x in args])
      elif isinstance(args, dict):
          return '{%s}' % ', '.join(['%s : %s' % (stringifyUserArguments(k), stringifyUserArguments(v)) for k, v in args.items()])
      elif isinstance(args, int):
          return str(args)
      elif isinstance(args, str):
          return "'%s'" % args
      raise InvalidArguments('Function accepts only strings, integers, lists and lists thereof.')
  
  
  class ObjectHolder:
      def __init__(self, obj):
          self.held_object = obj
  
      def __repr__(self):
          return '<Holder: {!r}>'.format(self.held_object)
  
  class FeatureOptionHolder(InterpreterObject, ObjectHolder):
      def __init__(self, env, option):
          InterpreterObject.__init__(self)
          ObjectHolder.__init__(self, option)
          if option.is_auto():
              self.held_object = env.coredata.builtins['auto_features']
          self.name = option.name
          self.methods.update({'enabled': self.enabled_method,
                               'disabled': self.disabled_method,
                               'auto': self.auto_method,
                               })
  
      @noPosargs
      @permittedKwargs({})
      def enabled_method(self, args, kwargs):
          return self.held_object.is_enabled()
  
      @noPosargs
      @permittedKwargs({})
      def disabled_method(self, args, kwargs):
          return self.held_object.is_disabled()
  
      @noPosargs
      @permittedKwargs({})
      def auto_method(self, args, kwargs):
          return self.held_object.is_auto()
  
  def extract_required_kwarg(kwargs):
      val = kwargs.get('required', True)
      disabled = False
      required = False
      feature = None
      if isinstance(val, FeatureOptionHolder):
          option = val.held_object
          feature = val.name
          if option.is_disabled():
              disabled = True
          elif option.is_enabled():
              required = True
      elif isinstance(required, bool):
          required = val
      else:
          raise InterpreterException('required keyword argument must be boolean or a feature option')
  
      # Keep boolean value in kwargs to simplify other places where this kwarg is
      # checked.
      kwargs['required'] = required
  
      return disabled, required, feature
  
  class TryRunResultHolder(InterpreterObject):
      def __init__(self, res):
          super().__init__()
          self.res = res
          self.methods.update({'returncode': self.returncode_method,
                               'compiled': self.compiled_method,
                               'stdout': self.stdout_method,
                               'stderr': self.stderr_method,
                               })
  
      @noPosargs
      @permittedKwargs({})
      def returncode_method(self, args, kwargs):
          return self.res.returncode
  
      @noPosargs
      @permittedKwargs({})
      def compiled_method(self, args, kwargs):
          return self.res.compiled
  
      @noPosargs
      @permittedKwargs({})
      def stdout_method(self, args, kwargs):
          return self.res.stdout
  
      @noPosargs
      @permittedKwargs({})
      def stderr_method(self, args, kwargs):
          return self.res.stderr
  
  class RunProcess(InterpreterObject):
  
      def __init__(self, cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir=False, check=False, capture=True):
          super().__init__()
          if not isinstance(cmd, ExternalProgram):
              raise AssertionError('BUG: RunProcess must be passed an ExternalProgram')
          self.capture = capture
          pc, self.stdout, self.stderr = self.run_command(cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir, check)
          self.returncode = pc.returncode
          self.methods.update({'returncode': self.returncode_method,
                               'stdout': self.stdout_method,
                               'stderr': self.stderr_method,
                               })
  
      def run_command(self, cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir, check=False):
          command_array = cmd.get_command() + args
          env = {'MESON_SOURCE_ROOT': source_dir,
                 'MESON_BUILD_ROOT': build_dir,
                 'MESON_SUBDIR': subdir,
                 'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in mesonintrospect]),
                 }
          if in_builddir:
              cwd = os.path.join(build_dir, subdir)
          else:
              cwd = os.path.join(source_dir, subdir)
          child_env = os.environ.copy()
          child_env.update(env)
          stdout = subprocess.PIPE if self.capture else subprocess.DEVNULL
          mlog.debug('Running command:', ' '.join(command_array))
          try:
              p, o, e = Popen_safe(command_array, stdout=stdout, env=child_env, cwd=cwd)
              if self.capture:
                  mlog.debug('--- stdout ---')
                  mlog.debug(o)
              else:
                  o = ''
                  mlog.debug('--- stdout disabled ---')
              mlog.debug('--- stderr ---')
              mlog.debug(e)
              mlog.debug('')
  
              if check and p.returncode != 0:
                  raise InterpreterException('Command "{}" failed with status {}.'.format(' '.join(command_array), p.returncode))
  
              return p, o, e
          except FileNotFoundError:
              raise InterpreterException('Could not execute command "%s".' % ' '.join(command_array))
  
      @noPosargs
      @permittedKwargs({})
      def returncode_method(self, args, kwargs):
          return self.returncode
  
      @noPosargs
      @permittedKwargs({})
      def stdout_method(self, args, kwargs):
          return self.stdout
  
      @noPosargs
      @permittedKwargs({})
      def stderr_method(self, args, kwargs):
          return self.stderr
  
  class ConfigureFileHolder(InterpreterObject, ObjectHolder):
  
      def __init__(self, subdir, sourcename, targetname, configuration_data):
          InterpreterObject.__init__(self)
          ObjectHolder.__init__(self, build.ConfigureFile(subdir, sourcename,
                                                          targetname, configuration_data))
  
  
  class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder):
      def __init__(self):
          MutableInterpreterObject.__init__(self)
          ObjectHolder.__init__(self, build.EnvironmentVariables())
          self.methods.update({'set': self.set_method,
                               'append': self.append_method,
                               'prepend': self.prepend_method,
                               })
  
      def __repr__(self):
          repr_str = "<{0}: {1}>"
          return repr_str.format(self.__class__.__name__, self.held_object.envvars)
  
      def add_var(self, method, args, kwargs):
          if not isinstance(kwargs.get("separator", ""), str):
              raise InterpreterException("EnvironmentVariablesHolder methods 'separator'"
                                         " argument needs to be a string.")
          if len(args) < 2:
              raise InterpreterException("EnvironmentVariablesHolder methods require at least"
                                         "2 arguments, first is the name of the variable and"
                                         " following one are values")
          self.held_object.envvars.append((method, args[0], args[1:], kwargs))
  
      @stringArgs
      @permittedKwargs({'separator'})
      def set_method(self, args, kwargs):
          self.add_var(self.held_object.set, args, kwargs)
  
      @stringArgs
      @permittedKwargs({'separator'})
      def append_method(self, args, kwargs):
          self.add_var(self.held_object.append, args, kwargs)
  
      @stringArgs
      @permittedKwargs({'separator'})
      def prepend_method(self, args, kwargs):
          self.add_var(self.held_object.prepend, args, kwargs)
  
  
  class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder):
      def __init__(self):
          MutableInterpreterObject.__init__(self)
          self.used = False # These objects become immutable after use in configure_file.
          ObjectHolder.__init__(self, build.ConfigurationData())
          self.methods.update({'set': self.set_method,
                               'set10': self.set10_method,
                               'set_quoted': self.set_quoted_method,
                               'has': self.has_method,
                               'get': self.get_method,
                               'get_unquoted': self.get_unquoted_method,
                               'merge_from': self.merge_from_method,
                               })
  
      def is_used(self):
          return self.used
  
      def mark_used(self):
          self.used = True
  
      def validate_args(self, args, kwargs):
          if len(args) == 1 and isinstance(args[0], list) and len(args[0]) == 2:
              mlog.log(mlog.red('DEPRECATION:'),
                       '''Passing a list as the single argument to configuration_data.set is deprecated.
  This will become a hard error in the future''')
              args = args[0]
  
          if len(args) != 2:
              raise InterpreterException("Configuration set requires 2 arguments.")
          if self.used:
              raise InterpreterException("Can not set values on configuration object that has been used.")
          name = args[0]
          val = args[1]
          desc = kwargs.get('description', None)
          if not isinstance(name, str):
              raise InterpreterException("First argument to set must be a string.")
          if desc is not None and not isinstance(desc, str):
              raise InterpreterException('Description must be a string.')
  
          return name, val, desc
  
      @noArgsFlattening
      def set_method(self, args, kwargs):
          (name, val, desc) = self.validate_args(args, kwargs)
          self.held_object.values[name] = (val, desc)
  
      def set_quoted_method(self, args, kwargs):
          (name, val, desc) = self.validate_args(args, kwargs)
          if not isinstance(val, str):
              raise InterpreterException("Second argument to set_quoted must be a string.")
          escaped_val = '\\"'.join(val.split('"'))
          self.held_object.values[name] = ('"' + escaped_val + '"', desc)
  
      def set10_method(self, args, kwargs):
          (name, val, desc) = self.validate_args(args, kwargs)
          if val:
              self.held_object.values[name] = (1, desc)
          else:
              self.held_object.values[name] = (0, desc)
  
      def has_method(self, args, kwargs):
          return args[0] in self.held_object.values
  
      @FeatureNew('configuration_data.get()', '0.38.0')
      @noArgsFlattening
      def get_method(self, args, kwargs):
          if len(args) < 1 or len(args) > 2:
              raise InterpreterException('Get method takes one or two arguments.')
          name = args[0]
          if name in self.held_object:
              return self.held_object.get(name)[0]
          if len(args) > 1:
              return args[1]
          raise InterpreterException('Entry %s not in configuration data.' % name)
  
      @FeatureNew('get_unquoted', '0.44.0')
      def get_unquoted_method(self, args, kwargs):
          if len(args) < 1 or len(args) > 2:
              raise InterpreterException('Get method takes one or two arguments.')
          name = args[0]
          if name in self.held_object:
              val = self.held_object.get(name)[0]
          elif len(args) > 1:
              val = args[1]
          else:
              raise InterpreterException('Entry %s not in configuration data.' % name)
          if val[0] == '"' and val[-1] == '"':
              return val[1:-1]
          return val
  
      def get(self, name):
          return self.held_object.values[name] # (val, desc)
  
      def keys(self):
          return self.held_object.values.keys()
  
      def merge_from_method(self, args, kwargs):
          if len(args) != 1:
              raise InterpreterException('Merge_from takes one positional argument.')
          from_object = args[0]
          if not isinstance(from_object, ConfigurationDataHolder):
              raise InterpreterException('Merge_from argument must be a configuration data object.')
          from_object = from_object.held_object
          for k, v in from_object.values.items():
              self.held_object.values[k] = v
  
  # Interpreter objects can not be pickled so we must have
  # these wrappers.
  
  class DependencyHolder(InterpreterObject, ObjectHolder):
      def __init__(self, dep):
          InterpreterObject.__init__(self)
          ObjectHolder.__init__(self, dep)
          self.methods.update({'found': self.found_method,
                               'type_name': self.type_name_method,
                               'version': self.version_method,
                               'get_pkgconfig_variable': self.pkgconfig_method,
                               'get_configtool_variable': self.configtool_method,
                               'partial_dependency': self.partial_dependency_method,
                               })
  
      @noPosargs
      @permittedKwargs({})
      def type_name_method(self, args, kwargs):
          return self.held_object.type_name
  
      @noPosargs
      @permittedKwargs({})
      def found_method(self, args, kwargs):
          if self.held_object.type_name == 'internal':
              return True
          return self.held_object.found()
  
      @noPosargs
      @permittedKwargs({})
      def version_method(self, args, kwargs):
          return self.held_object.get_version()
  
      @permittedKwargs({'define_variable'})
      def pkgconfig_method(self, args, kwargs):
          args = listify(args)
          if len(args) != 1:
              raise InterpreterException('get_pkgconfig_variable takes exactly one argument.')
          varname = args[0]
          if not isinstance(varname, str):
              raise InterpreterException('Variable name must be a string.')
          return self.held_object.get_pkgconfig_variable(varname, kwargs)
  
      @FeatureNew('get_configtool_variable', '0.44.0')
      @permittedKwargs({})
      def configtool_method(self, args, kwargs):
          args = listify(args)
          if len(args) != 1:
              raise InterpreterException('get_configtool_variable takes exactly one argument.')
          varname = args[0]
          if not isinstance(varname, str):
              raise InterpreterException('Variable name must be a string.')
          return self.held_object.get_configtool_variable(varname)
  
      @FeatureNew('dep.partial_dependency', '0.46.0')
      @noPosargs
      @permittedKwargs(permitted_method_kwargs['partial_dependency'])
      def partial_dependency_method(self, args, kwargs):
          return DependencyHolder(self.held_object.get_partial_dependency(**kwargs))
  
  class InternalDependencyHolder(InterpreterObject, ObjectHolder):
      def __init__(self, dep):
          InterpreterObject.__init__(self)
          ObjectHolder.__init__(self, dep)
          self.methods.update({'found': self.found_method,
                               'version': self.version_method,
                               'partial_dependency': self.partial_dependency_method,
                               })
  
      @noPosargs
      @permittedKwargs({})
      def found_method(self, args, kwargs):
          return True
  
      @noPosargs
      @permittedKwargs({})
      def version_method(self, args, kwargs):
          return self.held_object.get_version()
  
      @FeatureNew('dep.partial_dependency', '0.46.0')
      @noPosargs
      @permittedKwargs(permitted_method_kwargs['partial_dependency'])
      def partial_dependency_method(self, args, kwargs):
          return DependencyHolder(self.held_object.get_partial_dependency(**kwargs))
  
  class ExternalProgramHolder(InterpreterObject, ObjectHolder):
      def __init__(self, ep):
          InterpreterObject.__init__(self)
          ObjectHolder.__init__(self, ep)
          self.methods.update({'found': self.found_method,
                               'path': self.path_method})
  
      @noPosargs
      @permittedKwargs({})
      def found_method(self, args, kwargs):
          return self.found()
  
      @noPosargs
      @permittedKwargs({})
      def path_method(self, args, kwargs):
          return self.held_object.get_path()
  
      def found(self):
          return self.held_object.found()
  
      def get_command(self):
          return self.held_object.get_command()
  
      def get_name(self):
          return self.held_object.get_name()
  
  class ExternalLibraryHolder(InterpreterObject, ObjectHolder):
      def __init__(self, el):
          InterpreterObject.__init__(self)
          ObjectHolder.__init__(self, el)
          self.methods.update({'found': self.found_method,
                               'partial_dependency': self.partial_dependency_method,
                               })
  
      def found(self):
          return self.held_object.found()
  
      @noPosargs
      @permittedKwargs({})
      def found_method(self, args, kwargs):
          return self.found()
  
      def get_name(self):
          return self.held_object.name
  
      def get_compile_args(self):
          return self.held_object.get_compile_args()
  
      def get_link_args(self):
          return self.held_object.get_link_args()
  
      def get_exe_args(self):
          return self.held_object.get_exe_args()
  
      @FeatureNew('dep.partial_dependency', '0.46.0')
      @noPosargs
      @permittedKwargs(permitted_method_kwargs['partial_dependency'])
      def partial_dependency_method(self, args, kwargs):
          return DependencyHolder(self.held_object.get_partial_dependency(**kwargs))
  
  class GeneratorHolder(InterpreterObject, ObjectHolder):
      def __init__(self, interpreter, args, kwargs):
          InterpreterObject.__init__(self)
          self.interpreter = interpreter
          ObjectHolder.__init__(self, build.Generator(args, kwargs))
          self.methods.update({'process': self.process_method})
  
      @FeatureNewKwargs('generator.process', '0.45.0', ['preserve_path_from'])
      @permittedKwargs({'extra_args', 'preserve_path_from'})
      def process_method(self, args, kwargs):
          extras = mesonlib.stringlistify(kwargs.get('extra_args', []))
          if 'preserve_path_from' in kwargs:
              preserve_path_from = kwargs['preserve_path_from']
              if not isinstance(preserve_path_from
  
  [... the rest is omitted ...]
files.new_path: mesonbuild/interpreter.py
files.old_contents: # Copyright 2012-2018 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 . import mparser
  from . import environment
  from . import coredata
  from . import dependencies
  from . import mlog
  from . import build
  from . import optinterpreter
  from . import compilers
  from .wrap import wrap, WrapMode
  from . import mesonlib
  from .mesonlib import FileMode, Popen_safe, listify, extract_as_list, has_path_sep
  from .dependencies import ExternalProgram
  from .dependencies import InternalDependency, Dependency, NotFoundDependency, DependencyException
  from .interpreterbase import InterpreterBase
  from .interpreterbase import check_stringlist, flatten, noPosargs, noKwargs, stringArgs, permittedKwargs, noArgsFlattening
  from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode, SubdirDoneRequest
  from .interpreterbase import InterpreterObject, MutableInterpreterObject, Disabler
  from .interpreterbase import FeatureNew, FeatureDeprecated, FeatureNewKwargs
  from .modules import ModuleReturnValue
  
  import os, sys, shutil, uuid
  import re, shlex
  import subprocess
  from collections import namedtuple
  from pathlib import PurePath
  
  import importlib
  
  permitted_method_kwargs = {
      'partial_dependency': {'compile_args', 'link_args', 'links', 'includes',
                             'sources'},
  }
  
  def stringifyUserArguments(args):
      if isinstance(args, list):
          return '[%s]' % ', '.join([stringifyUserArguments(x) for x in args])
      elif isinstance(args, dict):
          return '{%s}' % ', '.join(['%s : %s' % (stringifyUserArguments(k), stringifyUserArguments(v)) for k, v in args.items()])
      elif isinstance(args, int):
          return str(args)
      elif isinstance(args, str):
          return "'%s'" % args
      raise InvalidArguments('Function accepts only strings, integers, lists and lists thereof.')
  
  
  class ObjectHolder:
      def __init__(self, obj):
          self.held_object = obj
  
      def __repr__(self):
          return '<Holder: {!r}>'.format(self.held_object)
  
  class FeatureOptionHolder(InterpreterObject, ObjectHolder):
      def __init__(self, env, option):
          InterpreterObject.__init__(self)
          ObjectHolder.__init__(self, option)
          if option.is_auto():
              self.held_object = env.coredata.builtins['auto_features']
          self.name = option.name
          self.methods.update({'enabled': self.enabled_method,
                               'disabled': self.disabled_method,
                               'auto': self.auto_method,
                               })
  
      @noPosargs
      @permittedKwargs({})
      def enabled_method(self, args, kwargs):
          return self.held_object.is_enabled()
  
      @noPosargs
      @permittedKwargs({})
      def disabled_method(self, args, kwargs):
          return self.held_object.is_disabled()
  
      @noPosargs
      @permittedKwargs({})
      def auto_method(self, args, kwargs):
          return self.held_object.is_auto()
  
  def extract_required_kwarg(kwargs):
      val = kwargs.get('required', True)
      disabled = False
      required = False
      feature = None
      if isinstance(val, FeatureOptionHolder):
          option = val.held_object
          feature = val.name
          if option.is_disabled():
              disabled = True
          elif option.is_enabled():
              required = True
      elif isinstance(required, bool):
          required = val
      else:
          raise InterpreterException('required keyword argument must be boolean or a feature option')
  
      # Keep boolean value in kwargs to simplify other places where this kwarg is
      # checked.
      kwargs['required'] = required
  
      return disabled, required, feature
  
  class TryRunResultHolder(InterpreterObject):
      def __init__(self, res):
          super().__init__()
          self.res = res
          self.methods.update({'returncode': self.returncode_method,
                               'compiled': self.compiled_method,
                               'stdout': self.stdout_method,
                               'stderr': self.stderr_method,
                               })
  
      @noPosargs
      @permittedKwargs({})
      def returncode_method(self, args, kwargs):
          return self.res.returncode
  
      @noPosargs
      @permittedKwargs({})
      def compiled_method(self, args, kwargs):
          return self.res.compiled
  
      @noPosargs
      @permittedKwargs({})
      def stdout_method(self, args, kwargs):
          return self.res.stdout
  
      @noPosargs
      @permittedKwargs({})
      def stderr_method(self, args, kwargs):
          return self.res.stderr
  
  class RunProcess(InterpreterObject):
  
      def __init__(self, cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir=False, check=False, capture=True):
          super().__init__()
          if not isinstance(cmd, ExternalProgram):
              raise AssertionError('BUG: RunProcess must be passed an ExternalProgram')
          self.capture = capture
          pc, self.stdout, self.stderr = self.run_command(cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir, check)
          self.returncode = pc.returncode
          self.methods.update({'returncode': self.returncode_method,
                               'stdout': self.stdout_method,
                               'stderr': self.stderr_method,
                               })
  
      def run_command(self, cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir, check=False):
          command_array = cmd.get_command() + args
          env = {'MESON_SOURCE_ROOT': source_dir,
                 'MESON_BUILD_ROOT': build_dir,
                 'MESON_SUBDIR': subdir,
                 'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in mesonintrospect]),
                 }
          if in_builddir:
              cwd = os.path.join(build_dir, subdir)
          else:
              cwd = os.path.join(source_dir, subdir)
          child_env = os.environ.copy()
          child_env.update(env)
          stdout = subprocess.PIPE if self.capture else subprocess.DEVNULL
          mlog.debug('Running command:', ' '.join(command_array))
          try:
              p, o, e = Popen_safe(command_array, stdout=stdout, env=child_env, cwd=cwd)
              if self.capture:
                  mlog.debug('--- stdout ---')
                  mlog.debug(o)
              else:
                  o = ''
                  mlog.debug('--- stdout disabled ---')
              mlog.debug('--- stderr ---')
              mlog.debug(e)
              mlog.debug('')
  
              if check and p.returncode != 0:
                  raise InterpreterException('Command "{}" failed with status {}.'.format(' '.join(command_array), p.returncode))
  
              return p, o, e
          except FileNotFoundError:
              raise InterpreterException('Could not execute command "%s".' % ' '.join(command_array))
  
      @noPosargs
      @permittedKwargs({})
      def returncode_method(self, args, kwargs):
          return self.returncode
  
      @noPosargs
      @permittedKwargs({})
      def stdout_method(self, args, kwargs):
          return self.stdout
  
      @noPosargs
      @permittedKwargs({})
      def stderr_method(self, args, kwargs):
          return self.stderr
  
  class ConfigureFileHolder(InterpreterObject, ObjectHolder):
  
      def __init__(self, subdir, sourcename, targetname, configuration_data):
          InterpreterObject.__init__(self)
          ObjectHolder.__init__(self, build.ConfigureFile(subdir, sourcename,
                                                          targetname, configuration_data))
  
  
  class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder):
      def __init__(self):
          MutableInterpreterObject.__init__(self)
          ObjectHolder.__init__(self, build.EnvironmentVariables())
          self.methods.update({'set': self.set_method,
                               'append': self.append_method,
                               'prepend': self.prepend_method,
                               })
  
      def __repr__(self):
          repr_str = "<{0}: {1}>"
          return repr_str.format(self.__class__.__name__, self.held_object.envvars)
  
      def add_var(self, method, args, kwargs):
          if not isinstance(kwargs.get("separator", ""), str):
              raise InterpreterException("EnvironmentVariablesHolder methods 'separator'"
                                         " argument needs to be a string.")
          if len(args) < 2:
              raise InterpreterException("EnvironmentVariablesHolder methods require at least"
                                         "2 arguments, first is the name of the variable and"
                                         " following one are values")
          self.held_object.envvars.append((method, args[0], args[1:], kwargs))
  
      @stringArgs
      @permittedKwargs({'separator'})
      def set_method(self, args, kwargs):
          self.add_var(self.held_object.set, args, kwargs)
  
      @stringArgs
      @permittedKwargs({'separator'})
      def append_method(self, args, kwargs):
          self.add_var(self.held_object.append, args, kwargs)
  
      @stringArgs
      @permittedKwargs({'separator'})
      def prepend_method(self, args, kwargs):
          self.add_var(self.held_object.prepend, args, kwargs)
  
  
  class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder):
      def __init__(self):
          MutableInterpreterObject.__init__(self)
          self.used = False # These objects become immutable after use in configure_file.
          ObjectHolder.__init__(self, build.ConfigurationData())
          self.methods.update({'set': self.set_method,
                               'set10': self.set10_method,
                               'set_quoted': self.set_quoted_method,
                               'has': self.has_method,
                               'get': self.get_method,
                               'get_unquoted': self.get_unquoted_method,
                               'merge_from': self.merge_from_method,
                               })
  
      def is_used(self):
          return self.used
  
      def mark_used(self):
          self.used = True
  
      def validate_args(self, args, kwargs):
          if len(args) == 1 and isinstance(args[0], list) and len(args[0]) == 2:
              mlog.log(mlog.red('DEPRECATION:'),
                       '''Passing a list as the single argument to configuration_data.set is deprecated.
  This will become a hard error in the future''')
              args = args[0]
  
          if len(args) != 2:
              raise InterpreterException("Configuration set requires 2 arguments.")
          if self.used:
              raise InterpreterException("Can not set values on configuration object that has been used.")
          name = args[0]
          val = args[1]
          desc = kwargs.get('description', None)
          if not isinstance(name, str):
              raise InterpreterException("First argument to set must be a string.")
          if desc is not None and not isinstance(desc, str):
              raise InterpreterException('Description must be a string.')
  
          return name, val, desc
  
      @noArgsFlattening
      def set_method(self, args, kwargs):
          (name, val, desc) = self.validate_args(args, kwargs)
          self.held_object.values[name] = (val, desc)
  
      def set_quoted_method(self, args, kwargs):
          (name, val, desc) = self.validate_args(args, kwargs)
          if not isinstance(val, str):
              raise InterpreterException("Second argument to set_quoted must be a string.")
          escaped_val = '\\"'.join(val.split('"'))
          self.held_object.values[name] = ('"' + escaped_val + '"', desc)
  
      def set10_method(self, args, kwargs):
          (name, val, desc) = self.validate_args(args, kwargs)
          if val:
              self.held_object.values[name] = (1, desc)
          else:
              self.held_object.values[name] = (0, desc)
  
      def has_method(self, args, kwargs):
          return args[0] in self.held_object.values
  
      @FeatureNew('configuration_data.get()', '0.38.0')
      @noArgsFlattening
      def get_method(self, args, kwargs):
          if len(args) < 1 or len(args) > 2:
              raise InterpreterException('Get method takes one or two arguments.')
          name = args[0]
          if name in self.held_object:
              return self.held_object.get(name)[0]
          if len(args) > 1:
              return args[1]
          raise InterpreterException('Entry %s not in configuration data.' % name)
  
      @FeatureNew('get_unquoted', '0.44.0')
      def get_unquoted_method(self, args, kwargs):
          if len(args) < 1 or len(args) > 2:
              raise InterpreterException('Get method takes one or two arguments.')
          name = args[0]
          if name in self.held_object:
              val = self.held_object.get(name)[0]
          elif len(args) > 1:
              val = args[1]
          else:
              raise InterpreterException('Entry %s not in configuration data.' % name)
          if val[0] == '"' and val[-1] == '"':
              return val[1:-1]
          return val
  
      def get(self, name):
          return self.held_object.values[name] # (val, desc)
  
      def keys(self):
          return self.held_object.values.keys()
  
      def merge_from_method(self, args, kwargs):
          if len(args) != 1:
              raise InterpreterException('Merge_from takes one positional argument.')
          from_object = args[0]
          if not isinstance(from_object, ConfigurationDataHolder):
              raise InterpreterException('Merge_from argument must be a configuration data object.')
          from_object = from_object.held_object
          for k, v in from_object.values.items():
              self.held_object.values[k] = v
  
  # Interpreter objects can not be pickled so we must have
  # these wrappers.
  
  class DependencyHolder(InterpreterObject, ObjectHolder):
      def __init__(self, dep):
          InterpreterObject.__init__(self)
          ObjectHolder.__init__(self, dep)
          self.methods.update({'found': self.found_method,
                               'type_name': self.type_name_method,
                               'version': self.version_method,
                               'get_pkgconfig_variable': self.pkgconfig_method,
                               'get_configtool_variable': self.configtool_method,
                               'partial_dependency': self.partial_dependency_method,
                               })
  
      @noPosargs
      @permittedKwargs({})
      def type_name_method(self, args, kwargs):
          return self.held_object.type_name
  
      @noPosargs
      @permittedKwargs({})
      def found_method(self, args, kwargs):
          if self.held_object.type_name == 'internal':
              return True
          return self.held_object.found()
  
      @noPosargs
      @permittedKwargs({})
      def version_method(self, args, kwargs):
          return self.held_object.get_version()
  
      @permittedKwargs({'define_variable'})
      def pkgconfig_method(self, args, kwargs):
          args = listify(args)
          if len(args) != 1:
              raise InterpreterException('get_pkgconfig_variable takes exactly one argument.')
          varname = args[0]
          if not isinstance(varname, str):
              raise InterpreterException('Variable name must be a string.')
          return self.held_object.get_pkgconfig_variable(varname, kwargs)
  
      @FeatureNew('get_configtool_variable', '0.44.0')
      @permittedKwargs({})
      def configtool_method(self, args, kwargs):
          args = listify(args)
          if len(args) != 1:
              raise InterpreterException('get_configtool_variable takes exactly one argument.')
          varname = args[0]
          if not isinstance(varname, str):
              raise InterpreterException('Variable name must be a string.')
          return self.held_object.get_configtool_variable(varname)
  
      @FeatureNew('dep.partial_dependency', '0.46.0')
      @noPosargs
      @permittedKwargs(permitted_method_kwargs['partial_dependency'])
      def partial_dependency_method(self, args, kwargs):
          return DependencyHolder(self.held_object.get_partial_dependency(**kwargs))
  
  class InternalDependencyHolder(InterpreterObject, ObjectHolder):
      def __init__(self, dep):
          InterpreterObject.__init__(self)
          ObjectHolder.__init__(self, dep)
          self.methods.update({'found': self.found_method,
                               'version': self.version_method,
                               'partial_dependency': self.partial_dependency_method,
                               })
  
      @noPosargs
      @permittedKwargs({})
      def found_method(self, args, kwargs):
          return True
  
      @noPosargs
      @permittedKwargs({})
      def version_method(self, args, kwargs):
          return self.held_object.get_version()
  
      @FeatureNew('dep.partial_dependency', '0.46.0')
      @noPosargs
      @permittedKwargs(permitted_method_kwargs['partial_dependency'])
      def partial_dependency_method(self, args, kwargs):
          return DependencyHolder(self.held_object.get_partial_dependency(**kwargs))
  
  class ExternalProgramHolder(InterpreterObject, ObjectHolder):
      def __init__(self, ep):
          InterpreterObject.__init__(self)
          ObjectHolder.__init__(self, ep)
          self.methods.update({'found': self.found_method,
                               'path': self.path_method})
  
      @noPosargs
      @permittedKwargs({})
      def found_method(self, args, kwargs):
          return self.found()
  
      @noPosargs
      @permittedKwargs({})
      def path_method(self, args, kwargs):
          return self.held_object.get_path()
  
      def found(self):
          return self.held_object.found()
  
      def get_command(self):
          return self.held_object.get_command()
  
      def get_name(self):
          return self.held_object.get_name()
  
  class ExternalLibraryHolder(InterpreterObject, ObjectHolder):
      def __init__(self, el):
          InterpreterObject.__init__(self)
          ObjectHolder.__init__(self, el)
          self.methods.update({'found': self.found_method,
                               'partial_dependency': self.partial_dependency_method,
                               })
  
      def found(self):
          return self.held_object.found()
  
      @noPosargs
      @permittedKwargs({})
      def found_method(self, args, kwargs):
          return self.found()
  
      def get_name(self):
          return self.held_object.name
  
      def get_compile_args(self):
          return self.held_object.get_compile_args()
  
      def get_link_args(self):
          return self.held_object.get_link_args()
  
      def get_exe_args(self):
          return self.held_object.get_exe_args()
  
      @FeatureNew('dep.partial_dependency', '0.46.0')
      @noPosargs
      @permittedKwargs(permitted_method_kwargs['partial_dependency'])
      def partial_dependency_method(self, args, kwargs):
          return DependencyHolder(self.held_object.get_partial_dependency(**kwargs))
  
  class GeneratorHolder(InterpreterObject, ObjectHolder):
      def __init__(self, interpreter, args, kwargs):
          InterpreterObject.__init__(self)
          self.interpreter = interpreter
          ObjectHolder.__init__(self, build.Generator(args, kwargs))
          self.methods.update({'process': self.process_method})
  
      @FeatureNewKwargs('generator.process', '0.45.0', ['preserve_path_from'])
      @permittedKwargs({'extra_args', 'preserve_path_from'})
      def process_method(self, args, kwargs):
          extras = mesonlib.stringlistify(kwargs.get('extra_args', []))
          if 'preserve_path_from' in kwargs:
              preserve_path_from = kwargs['preserve_path_from']
              if not isinstance(preserve_path_from
  
  [... the rest is omitted ...]
files.old_path: mesonbuild/interpreter.py