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 external
  # dependencies. Mostly just uses pkg-config but also contains
  # custom logic for packages that don't provide them.
  
  # Currently one file, should probably be split into a
  # package before this gets too big.
  
  import re
  import sys
  import os, stat, glob, shutil
  import subprocess
  import sysconfig
  from enum import Enum
  from collections import OrderedDict
  from . mesonlib import MesonException, version_compare, version_compare_many, Popen_safe
  from . import mlog
  from . import mesonlib
  from .environment import detect_cpu_family, for_windows
  
  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'
      # Detect using sdl2-config
      SDLCONFIG = 'sdlconfig'
      # This is only supported on OSX - search the frameworks directory by name.
      EXTRAFRAMEWORK = 'extraframework'
      # Detect using the sysconfig module.
      SYSCONFIG = 'sysconfig'
  
  class Dependency:
      def __init__(self, type_name, kwargs):
          self.name = "null"
          self.is_found = False
          self.type_name = type_name
          method = DependencyMethods(kwargs.get('method', 'auto'))
  
          # 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:
              self.methods = self.get_methods()
          elif method in self.get_methods():
              self.methods = [method]
          else:
              raise MesonException('Unsupported detection method: {}, allowed methods are {}'.format(method.value, mlog.format_list(map(lambda x: x.value, [DependencyMethods.AUTO] + self.get_methods()))))
  
      def __repr__(self):
          s = '<{0} {1}: {2}>'
          return s.format(self.__class__.__name__, self.name, self.is_found)
  
      def get_compile_args(self):
          return []
  
      def get_link_args(self):
          return []
  
      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 []
  
      def get_methods(self):
          return [DependencyMethods.AUTO]
  
      def get_name(self):
          return self.name
  
      def get_exe_args(self, compiler):
          return []
  
      def need_threads(self):
          return False
  
      def get_pkgconfig_variable(self, variable_name):
          raise MesonException('Tried to get a pkg-config variable from a non-pkgconfig dependency.')
  
  class InternalDependency(Dependency):
      def __init__(self, version, incdirs, compile_args, link_args, libraries, sources, ext_deps):
          super().__init__('internal', {})
          self.version = version
          self.include_directories = incdirs
          self.compile_args = compile_args
          self.link_args = link_args
          self.libraries = libraries
          self.sources = sources
          self.ext_deps = ext_deps
  
      def get_compile_args(self):
          return self.compile_args
  
      def get_link_args(self):
          return self.link_args
  
      def get_version(self):
          return self.version
  
  class PkgConfigDependency(Dependency):
      # 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
  
      def __init__(self, name, environment, kwargs):
          Dependency.__init__(self, 'pkgconfig', kwargs)
          self.is_libtool = False
          self.required = kwargs.get('required', True)
          self.static = kwargs.get('static', False)
          self.silent = kwargs.get('silent', False)
          if not isinstance(self.static, bool):
              raise DependencyException('Static keyword must be boolean')
          # 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
          self.cargs = []
          self.libs = []
          if 'native' in kwargs and environment.is_cross_build():
              self.want_cross = not kwargs['native']
          else:
              self.want_cross = environment.is_cross_build()
          self.name = name
          self.modversion = '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():
                      # FIXME, we should store all pkg-configs in ExternalPrograms.
                      # However that is too destabilizing a change to do just before release.
                      self.pkgbin = potential_pkgbin.get_command()[0]
                      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
  
          self.is_found = False
          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))
          ret, self.modversion = 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:']
          self.version_reqs = kwargs.get('version', None)
          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.modversion, self.version_reqs)
              if not self.is_found:
                  found_msg += [mlog.red('NO'),
                                'found {!r} but need:'.format(self.modversion),
                                ', '.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.modversion))
                  return
          found_msg += [mlog.green('YES'), self.modversion]
          # 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()
          # Print the found message only at the very end because
  
  [... the rest is omitted ...]
files.new_path: mesonbuild/dependencies.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 external
  # dependencies. Mostly just uses pkg-config but also contains
  # custom logic for packages that don't provide them.
  
  # Currently one file, should probably be split into a
  # package before this gets too big.
  
  import re
  import sys
  import os, stat, glob, shutil
  import subprocess
  import sysconfig
  from collections import OrderedDict
  from . mesonlib import MesonException, version_compare, version_compare_many, Popen_safe
  from . import mlog
  from . import mesonlib
  from .environment import detect_cpu_family, for_windows
  
  class DependencyException(MesonException):
      '''Exceptions raised while trying to find dependencies'''
  
  class Dependency:
      def __init__(self, type_name, kwargs):
          self.name = "null"
          self.is_found = False
          self.type_name = type_name
          method = kwargs.get('method', 'auto')
  
          # 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 == "auto":
              self.methods = self.get_methods()
          elif method in self.get_methods():
              self.methods = [method]
          else:
              raise MesonException('Unsupported detection method: {}, allowed methods are {}'.format(method, mlog.format_list(["auto"] + self.get_methods())))
  
      def __repr__(self):
          s = '<{0} {1}: {2}>'
          return s.format(self.__class__.__name__, self.name, self.is_found)
  
      def get_compile_args(self):
          return []
  
      def get_link_args(self):
          return []
  
      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 []
  
      def get_methods(self):
          return ['auto']
  
      def get_name(self):
          return self.name
  
      def get_exe_args(self, compiler):
          return []
  
      def need_threads(self):
          return False
  
      def get_pkgconfig_variable(self, variable_name):
          raise MesonException('Tried to get a pkg-config variable from a non-pkgconfig dependency.')
  
  class InternalDependency(Dependency):
      def __init__(self, version, incdirs, compile_args, link_args, libraries, sources, ext_deps):
          super().__init__('internal', {})
          self.version = version
          self.include_directories = incdirs
          self.compile_args = compile_args
          self.link_args = link_args
          self.libraries = libraries
          self.sources = sources
          self.ext_deps = ext_deps
  
      def get_compile_args(self):
          return self.compile_args
  
      def get_link_args(self):
          return self.link_args
  
      def get_version(self):
          return self.version
  
  class PkgConfigDependency(Dependency):
      # 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
  
      def __init__(self, name, environment, kwargs):
          Dependency.__init__(self, 'pkgconfig', kwargs)
          self.is_libtool = False
          self.required = kwargs.get('required', True)
          self.static = kwargs.get('static', False)
          self.silent = kwargs.get('silent', False)
          if not isinstance(self.static, bool):
              raise DependencyException('Static keyword must be boolean')
          # 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
          self.cargs = []
          self.libs = []
          if 'native' in kwargs and environment.is_cross_build():
              self.want_cross = not kwargs['native']
          else:
              self.want_cross = environment.is_cross_build()
          self.name = name
          self.modversion = '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():
                      # FIXME, we should store all pkg-configs in ExternalPrograms.
                      # However that is too destabilizing a change to do just before release.
                      self.pkgbin = potential_pkgbin.get_command()[0]
                      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
  
          self.is_found = False
          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))
          ret, self.modversion = 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:']
          self.version_reqs = kwargs.get('version', None)
          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.modversion, self.version_reqs)
              if not self.is_found:
                  found_msg += [mlog.red('NO'),
                                'found {!r} but need:'.format(self.modversion),
                                ', '.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.modversion))
                  return
          found_msg += [mlog.green('YES'), self.modversion]
          # 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()
          # Print the found message only at the very end because fetching cflags
          # and libs can also fail if other needed pkg-config files aren't found.
          if not self.silent:
              mlog.log(*found_msg)
  
      def __repr__(self):
          s = '<{0} {1}: {2} {3}>'
          return s.format(self.__class__.__name__, self.name, self.is_found,
                          self.version_reqs)
  
      def _call_pkgbin(self, args):
          p, out = Popen_safe([self.pkgbin] + args, env=os.environ)[0:2]
          return p.returncode, out.strip()
  
      def _set_cargs(self):
          ret, out = self._call_pkgbin(['--cflags', self.name])
          if ret != 0
  
  [... the rest is omitted ...]
files.old_path: mesonbuild/dependencies.py