files: # 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 mlog
  import pickle, os, uuid, shlex
  import sys
  from pathlib import PurePath
  from collections import OrderedDict
  from .mesonlib import MesonException
  from .mesonlib import default_libdir, default_libexecdir, default_prefix
  import ast
  import argparse
  
  version = '0.47.0.dev1'
  backendlist = ['ninja', 'vs', 'vs2010', 'vs2015', 'vs2017', 'xcode']
  
  default_yielding = False
  
  class UserOption:
      def __init__(self, name, description, choices, yielding):
          super().__init__()
          self.name = name
          self.choices = choices
          self.description = description
          if yielding is None:
              yielding = default_yielding
          if not isinstance(yielding, bool):
              raise MesonException('Value of "yielding" must be a boolean.')
          self.yielding = yielding
  
      # Check that the input is a valid value and return the
      # "cleaned" or "native" version. For example the Boolean
      # option could take the string "true" and return True.
      def validate_value(self, value):
          raise RuntimeError('Derived option class did not override validate_value.')
  
      def set_value(self, newvalue):
          self.value = self.validate_value(newvalue)
  
  class UserStringOption(UserOption):
      def __init__(self, name, description, value, choices=None, yielding=None):
          super().__init__(name, description, choices, yielding)
          self.set_value(value)
  
      def validate_value(self, value):
          if not isinstance(value, str):
              raise MesonException('Value "%s" for string option "%s" is not a string.' % (str(value), self.name))
          return value
  
  class UserBooleanOption(UserOption):
      def __init__(self, name, description, value, yielding=None):
          super().__init__(name, description, [True, False], yielding)
          self.set_value(value)
  
      def __bool__(self):
          return self.value
  
      def validate_value(self, value):
          if isinstance(value, bool):
              return value
          if value.lower() == 'true':
              return True
          if value.lower() == 'false':
              return False
          raise MesonException('Value %s is not boolean (true or false).' % value)
  
  class UserIntegerOption(UserOption):
      def __init__(self, name, description, min_value, max_value, value, yielding=None):
          super().__init__(name, description, [True, False], yielding)
          self.min_value = min_value
          self.max_value = max_value
          self.set_value(value)
          c = []
          if min_value is not None:
              c.append('>=' + str(min_value))
          if max_value is not None:
              c.append('<=' + str(max_value))
          self.choices = ', '.join(c)
  
      def validate_value(self, value):
          if isinstance(value, str):
              value = self.toint(value)
          if not isinstance(value, int):
              raise MesonException('New value for integer option is not an integer.')
          if self.min_value is not None and value < self.min_value:
              raise MesonException('New value %d is less than minimum value %d.' % (value, self.min_value))
          if self.max_value is not None and value > self.max_value:
              raise MesonException('New value %d is more than maximum value %d.' % (value, self.max_value))
          return value
  
      def toint(self, valuestring):
          try:
              return int(valuestring)
          except ValueError:
              raise MesonException('Value string "%s" is not convertable to an integer.' % valuestring)
  
  class UserUmaskOption(UserIntegerOption):
      def __init__(self, name, description, value, yielding=None):
          super().__init__(name, description, 0, 0o777, value, yielding)
  
      def set_value(self, newvalue):
          if newvalue is None or newvalue == 'preserve':
              self.value = None
          else:
              super().set_value(newvalue)
  
      def toint(self, valuestring):
          try:
              return int(valuestring, 8)
          except ValueError as e:
              raise MesonException('Invalid mode: {}'.format(e))
  
  class UserComboOption(UserOption):
      def __init__(self, name, description, choices, value, yielding=None):
          super().__init__(name, description, choices, yielding)
          if not isinstance(self.choices, list):
              raise MesonException('Combo choices must be an array.')
          for i in self.choices:
              if not isinstance(i, str):
                  raise MesonException('Combo choice elements must be strings.')
          self.set_value(value)
  
      def validate_value(self, value):
          if value not in self.choices:
              optionsstring = ', '.join(['"%s"' % (item,) for item in self.choices])
              raise MesonException('Value "%s" for combo option "%s" is not one of the choices. Possible choices are: %s.' % (value, self.name, optionsstring))
          return value
  
  class UserArrayOption(UserOption):
      def __init__(self, name, description, value, shlex_split=False, user_input=False, **kwargs):
          super().__init__(name, description, kwargs.get('choices', []), yielding=kwargs.get('yielding', None))
          self.shlex_split = shlex_split
          self.value = self.validate_value(value, user_input=user_input)
  
      def validate_value(self, value, user_input=True):
          # User input is for options defined on the command line (via -D
          # options). Users can put their input in as a comma separated
          # string, but for defining options in meson_options.txt the format
          # should match that of a combo
          if not user_input and isinstance(value, str) and not value.startswith('['):
              raise MesonException('Value does not define an array: ' + value)
  
          if isinstance(value, str):
              if value.startswith('['):
                  newvalue = ast.literal_eval(value)
              else:
                  if self.shlex_split:
                      newvalue = shlex.split(value)
                  else:
                      newvalue = [v.strip() for v in value.split(',')]
          elif isinstance(value, list):
              newvalue = value
          else:
              raise MesonException('"{0}" should be a string array, but it is not'.format(str(newvalue)))
  
          if len(set(newvalue)) != len(newvalue):
              msg = 'Duplicated values in array option "%s" is deprecated. ' \
                    'This will become a hard error in the future.' % (self.name)
              mlog.log(mlog.red('DEPRECATION:'), msg)
          for i in newvalue:
              if not isinstance(i, str):
                  raise MesonException('String array element "{0}" is not a string.'.format(str(newvalue)))
          if self.choices:
              bad = [x for x in newvalue if x not in self.choices]
              if bad:
                  raise MesonException('Options "{}" are not in allowed choices: "{}"'.format(
                      ', '.join(bad), ', '.join(self.choices)))
          return newvalue
  
  # This class contains all data that must persist over multiple
  # invocations of Meson. It is roughly the same thing as
  # cmakecache.
  
  class CoreData:
  
      def __init__(self, options):
          self.lang_guids = {
              'default': '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942',
              'c': '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942',
              'cpp': '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942',
              'test': '3AC096D0-A1C2-E12C-1390-A8335801FDAB',
              'directory': '2150E333-8FDC-42A3-9474-1A3956D46DE8',
          }
          self.test_guid = str(uuid.uuid4()).upper()
          self.regen_guid = str(uuid.uuid4()).upper()
          self.target_guids = {}
          self.version = version
          self.init_builtins(options)
          self.backend_options = {}
          self.user_options = {}
          self.compiler_options = {}
          self
  
  [... the rest is omitted ...]
files: mesonbuild/coredata.py
files: # 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 mlog
  import pickle, os, uuid, shlex
  import sys
  from pathlib import PurePath
  from collections import OrderedDict
  from .mesonlib import MesonException
  from .mesonlib import default_libdir, default_libexecdir, default_prefix
  import ast
  import argparse
  
  version = '0.47.0.dev1'
  backendlist = ['ninja', 'vs', 'vs2010', 'vs2015', 'vs2017', 'xcode']
  
  default_yielding = False
  
  class UserOption:
      def __init__(self, name, description, choices, yielding):
          super().__init__()
          self.name = name
          self.choices = choices
          self.description = description
          if yielding is None:
              yielding = default_yielding
          if not isinstance(yielding, bool):
              raise MesonException('Value of "yielding" must be a boolean.')
          self.yielding = yielding
  
      # Check that the input is a valid value and return the
      # "cleaned" or "native" version. For example the Boolean
      # option could take the string "true" and return True.
      def validate_value(self, value):
          raise RuntimeError('Derived option class did not override validate_value.')
  
      def set_value(self, newvalue):
          self.value = self.validate_value(newvalue)
  
  class UserStringOption(UserOption):
      def __init__(self, name, description, value, choices=None, yielding=None):
          super().__init__(name, description, choices, yielding)
          self.set_value(value)
  
      def validate_value(self, value):
          if not isinstance(value, str):
              raise MesonException('Value "%s" for string option "%s" is not a string.' % (str(value), self.name))
          return value
  
  class UserBooleanOption(UserOption):
      def __init__(self, name, description, value, yielding=None):
          super().__init__(name, description, [True, False], yielding)
          self.set_value(value)
  
      def __bool__(self):
          return self.value
  
      def validate_value(self, value):
          if isinstance(value, bool):
              return value
          if value.lower() == 'true':
              return True
          if value.lower() == 'false':
              return False
          raise MesonException('Value %s is not boolean (true or false).' % value)
  
  class UserIntegerOption(UserOption):
      def __init__(self, name, description, min_value, max_value, value, yielding=None):
          super().__init__(name, description, [True, False], yielding)
          self.min_value = min_value
          self.max_value = max_value
          self.set_value(value)
          c = []
          if min_value is not None:
              c.append('>=' + str(min_value))
          if max_value is not None:
              c.append('<=' + str(max_value))
          self.choices = ', '.join(c)
  
      def validate_value(self, value):
          if isinstance(value, str):
              value = self.toint(value)
          if not isinstance(value, int):
              raise MesonException('New value for integer option is not an integer.')
          if self.min_value is not None and value < self.min_value:
              raise MesonException('New value %d is less than minimum value %d.' % (value, self.min_value))
          if self.max_value is not None and value > self.max_value:
              raise MesonException('New value %d is more than maximum value %d.' % (value, self.max_value))
          return value
  
      def toint(self, valuestring):
          try:
              return int(valuestring)
          except ValueError:
              raise MesonException('Value string "%s" is not convertable to an integer.' % valuestring)
  
  class UserUmaskOption(UserIntegerOption):
      def __init__(self, name, description, value, yielding=None):
          super().__init__(name, description, 0, 0o777, value, yielding)
  
      def set_value(self, newvalue):
          if newvalue is None or newvalue == 'preserve':
              self.value = None
          else:
              super().set_value(newvalue)
  
      def toint(self, valuestring):
          try:
              return int(valuestring, 8)
          except ValueError as e:
              raise MesonException('Invalid mode: {}'.format(e))
  
  class UserComboOption(UserOption):
      def __init__(self, name, description, choices, value, yielding=None):
          super().__init__(name, description, choices, yielding)
          if not isinstance(self.choices, list):
              raise MesonException('Combo choices must be an array.')
          for i in self.choices:
              if not isinstance(i, str):
                  raise MesonException('Combo choice elements must be strings.')
          self.set_value(value)
  
      def validate_value(self, value):
          if value not in self.choices:
              optionsstring = ', '.join(['"%s"' % (item,) for item in self.choices])
              raise MesonException('Value "%s" for combo option "%s" is not one of the choices. Possible choices are: %s.' % (value, self.name, optionsstring))
          return value
  
  class UserArrayOption(UserOption):
      def __init__(self, name, description, value, shlex_split=False, user_input=False, **kwargs):
          super().__init__(name, description, kwargs.get('choices', []), yielding=kwargs.get('yielding', None))
          self.shlex_split = shlex_split
          self.value = self.validate_value(value, user_input=user_input)
  
      def validate_value(self, value, user_input=True):
          # User input is for options defined on the command line (via -D
          # options). Users can put their input in as a comma separated
          # string, but for defining options in meson_options.txt the format
          # should match that of a combo
          if not user_input and isinstance(value, str) and not value.startswith('['):
              raise MesonException('Value does not define an array: ' + value)
  
          if isinstance(value, str):
              if value.startswith('['):
                  newvalue = ast.literal_eval(value)
              else:
                  if self.shlex_split:
                      newvalue = shlex.split(value)
                  else:
                      newvalue = [v.strip() for v in value.split(',')]
          elif isinstance(value, list):
              newvalue = value
          else:
              raise MesonException('"{0}" should be a string array, but it is not'.format(str(newvalue)))
  
          if len(set(newvalue)) != len(newvalue):
              msg = 'Duplicated values in array option "%s" is deprecated. ' \
                    'This will become a hard error in the future.' % (self.name)
              mlog.log(mlog.red('DEPRECATION:'), msg)
          for i in newvalue:
              if not isinstance(i, str):
                  raise MesonException('String array element "{0}" is not a string.'.format(str(newvalue)))
          if self.choices:
              bad = [x for x in newvalue if x not in self.choices]
              if bad:
                  raise MesonException('Options "{}" are not in allowed choices: "{}"'.format(
                      ', '.join(bad), ', '.join(self.choices)))
          return newvalue
  
  # This class contains all data that must persist over multiple
  # invocations of Meson. It is roughly the same thing as
  # cmakecache.
  
  class CoreData:
  
      def __init__(self, options):
          self.lang_guids = {
              'default': '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942',
              'c': '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942',
              'cpp': '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942',
              'test': '3AC096D0-A1C2-E12C-1390-A8335801FDAB',
              'directory': '2150E333-8FDC-42A3-9474-1A3956D46DE8',
          }
          self.test_guid = str(uuid.uuid4()).upper()
          self.regen_guid = str(uuid.uuid4()).upper()
          self.target_guids = {}
          self.version = version
          self.init_builtins(options)
          self.backend_options = {}
          self.user_options = {}
          self.compiler_options = {}
          self
  
  [... the rest is omitted ...]
files: mesonbuild/coredata.py
files: # Copyright 2012-2016 The Meson development team
  
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  
  #     http://www.apache.org/licenses/LICENSE-2.0
  
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  import configparser, os, platform, re, shlex, shutil, subprocess
  
  from . import coredata
  from .linkers import ArLinker, VisualStudioLinker
  from . import mesonlib
  from .mesonlib import EnvironmentException, Popen_safe
  from . import mlog
  
  from . import compilers
  from .compilers import (
      CLANG_OSX,
      CLANG_STANDARD,
      CLANG_WIN,
      GCC_CYGWIN,
      GCC_MINGW,
      GCC_OSX,
      GCC_STANDARD,
      ICC_STANDARD,
      is_assembly,
      is_header,
      is_library,
      is_llvm_ir,
      is_object,
      is_source,
  )
  from .compilers import (
      ArmCCompiler,
      ArmCPPCompiler,
      ClangCCompiler,
      ClangCPPCompiler,
      ClangObjCCompiler,
      ClangObjCPPCompiler,
      G95FortranCompiler,
      GnuCCompiler,
      GnuCPPCompiler,
      GnuFortranCompiler,
      GnuObjCCompiler,
      GnuObjCPPCompiler,
      ElbrusCCompiler,
      ElbrusCPPCompiler,
      ElbrusFortranCompiler,
      IntelCCompiler,
      IntelCPPCompiler,
      IntelFortranCompiler,
      JavaCompiler,
      MonoCompiler,
      VisualStudioCsCompiler,
      NAGFortranCompiler,
      Open64FortranCompiler,
      PathScaleFortranCompiler,
      PGIFortranCompiler,
      RustCompiler,
      SunFortranCompiler,
      ValaCompiler,
      VisualStudioCCompiler,
      VisualStudioCPPCompiler,
  )
  
  build_filename = 'meson.build'
  
  def detect_gcovr(version='3.1', log=False):
      gcovr_exe = 'gcovr'
      try:
          p, found = Popen_safe([gcovr_exe, '--version'])[0:2]
      except (FileNotFoundError, PermissionError):
          # Doesn't exist in PATH or isn't executable
          return None, None
      found = search_version(found)
      if p.returncode == 0:
          if log:
              mlog.log('Found gcovr-{} at {}'.format(found, shlex.quote(shutil.which(gcovr_exe))))
          return gcovr_exe, mesonlib.version_compare(found, '>=' + version)
      return None, None
  
  def find_coverage_tools():
      gcovr_exe, gcovr_new_rootdir = detect_gcovr()
  
      lcov_exe = 'lcov'
      genhtml_exe = 'genhtml'
  
      if not mesonlib.exe_exists([lcov_exe, '--version']):
          lcov_exe = None
      if not mesonlib.exe_exists([genhtml_exe, '--version']):
          genhtml_exe = None
  
      return gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe
  
  def detect_ninja(version='1.5', log=False):
      for n in ['ninja', 'ninja-build']:
          try:
              p, found = Popen_safe([n, '--version'])[0:2]
          except (FileNotFoundError, PermissionError):
              # Doesn't exist in PATH or isn't executable
              continue
          found = found.strip()
          # Perhaps we should add a way for the caller to know the failure mode
          # (not found or too old)
          if p.returncode == 0 and mesonlib.version_compare(found, '>=' + version):
              if log:
                  mlog.log('Found ninja-{} at {}'.format(found, shlex.quote(shutil.which(n))))
              return n
  
  def detect_native_windows_arch():
      """
      The architecture of Windows itself: x86 or amd64
      """
      # These env variables are always available. See:
      # https://msdn.microsoft.com/en-us/library/aa384274(VS.85).aspx
      # https://blogs.msdn.microsoft.com/david.wang/2006/03/27/howto-detect-process-bitness/
      arch = os.environ.get('PROCESSOR_ARCHITEW6432', '').lower()
      if not arch:
          try:
              # If this doesn't exist, something is messing with the environment
              arch = os.environ['PROCESSOR_ARCHITECTURE'].lower()
          except KeyError:
              raise EnvironmentException('Unable to detect native OS architecture')
      return arch
  
  def detect_windows_arch(compilers):
      """
      Detecting the 'native' architecture of Windows is not a trivial task. We
      cannot trust that the architecture that Python is built for is the 'native'
      one because you can run 32-bit apps on 64-bit Windows using WOW64 and
      people sometimes install 32-bit Python on 64-bit Windows.
  
      We also can't rely on the architecture of the OS itself, since it's
      perfectly normal to compile and run 32-bit applications on Windows as if
      they were native applications. It's a terrible experience to require the
      user to supply a cross-info file to compile 32-bit applications on 64-bit
      Windows. Thankfully, the only way to compile things with Visual Studio on
      Windows is by entering the 'msvc toolchain' environment, which can be
      easily detected.
  
      In the end, the sanest method is as follows:
      1. Check if we're in an MSVC toolchain environment, and if so, return the
         MSVC toolchain architecture as our 'native' architecture.
      2. If not, check environment variables that are set by Windows and WOW64 to
         find out the architecture that Windows is built for, and use that as our
         'native' architecture.
      """
      os_arch = detect_native_windows_arch()
      if os_arch != 'amd64':
          return os_arch
      # If we're on 64-bit Windows, 32-bit apps can be compiled without
      # cross-compilation. So if we're doing that, just set the native arch as
      # 32-bit and pretend like we're running under WOW64. Else, return the
      # actual Windows architecture that we deduced above.
      for compiler in compilers.values():
          # Check if we're using and inside an MSVC toolchain environment
          if compiler.id == 'msvc' and 'VCINSTALLDIR' in os.environ:
              if float(compiler.get_toolset_version()) < 10.0:
                  # On MSVC 2008 and earlier, check 'BUILD_PLAT', where
                  # 'Win32' means 'x86'
                  platform = os.environ.get('BUILD_PLAT', 'x86')
                  if platform == 'Win32':
                      return 'x86'
              else:
                  # On MSVC 2010 and later 'Platform' is only set when the
                  # target arch is not 'x86'.  It's 'x64' when targeting
                  # x86_64 and 'arm' when targeting ARM.
                  platform = os.environ.get('Platform', 'x86').lower()
              if platform == 'x86':
                  return platform
          if compiler.id == 'gcc' and compiler.has_builtin_define('__i386__'):
              return 'x86'
      return os_arch
  
  def detect_cpu_family(compilers):
      """
      Python is inconsistent in its platform module.
      It returns different values for the same cpu.
      For x86 it might return 'x86', 'i686' or somesuch.
      Do some canonicalization.
      """
      if mesonlib.is_windows():
          trial = detect_windows_arch(compilers)
      else:
          trial = platform.machine().lower()
      if trial.startswith('i') and trial.endswith('86'):
          return 'x86'
      if trial.startswith('arm'):
          return 'arm'
      if trial in ('amd64', 'x64'):
          trial = 'x86_64'
      if trial == 'x86_64':
          # On Linux (and maybe others) there can be any mixture of 32/64 bit
          # code in the kernel, Python, system etc. The only reliable way
          # to know is to check the compiler defines.
          for c in compilers.values():
              try:
                  if c.has_builtin_define('__i386__'):
                      return 'x86'
  
  
  [... the rest is omitted ...]
files: mesonbuild/environment.py
files: # Copyright 2012-2016 The Meson development team
  
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  
  #     http://www.apache.org/licenses/LICENSE-2.0
  
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  import configparser, os, platform, re, shlex, shutil, subprocess
  
  from . import coredata
  from .linkers import ArLinker, VisualStudioLinker
  from . import mesonlib
  from .mesonlib import EnvironmentException, Popen_safe
  from . import mlog
  
  from . import compilers
  from .compilers import (
      CLANG_OSX,
      CLANG_STANDARD,
      CLANG_WIN,
      GCC_CYGWIN,
      GCC_MINGW,
      GCC_OSX,
      GCC_STANDARD,
      ICC_STANDARD,
      is_assembly,
      is_header,
      is_library,
      is_llvm_ir,
      is_object,
      is_source,
  )
  from .compilers import (
      ArmCCompiler,
      ArmCPPCompiler,
      ClangCCompiler,
      ClangCPPCompiler,
      ClangObjCCompiler,
      ClangObjCPPCompiler,
      G95FortranCompiler,
      GnuCCompiler,
      GnuCPPCompiler,
      GnuFortranCompiler,
      GnuObjCCompiler,
      GnuObjCPPCompiler,
      ElbrusCCompiler,
      ElbrusCPPCompiler,
      ElbrusFortranCompiler,
      IntelCCompiler,
      IntelCPPCompiler,
      IntelFortranCompiler,
      JavaCompiler,
      MonoCompiler,
      VisualStudioCsCompiler,
      NAGFortranCompiler,
      Open64FortranCompiler,
      PathScaleFortranCompiler,
      PGIFortranCompiler,
      RustCompiler,
      SunFortranCompiler,
      ValaCompiler,
      VisualStudioCCompiler,
      VisualStudioCPPCompiler,
  )
  
  build_filename = 'meson.build'
  
  def detect_gcovr(version='3.1', log=False):
      gcovr_exe = 'gcovr'
      try:
          p, found = Popen_safe([gcovr_exe, '--version'])[0:2]
      except (FileNotFoundError, PermissionError):
          # Doesn't exist in PATH or isn't executable
          return None, None
      found = search_version(found)
      if p.returncode == 0:
          if log:
              mlog.log('Found gcovr-{} at {}'.format(found, shlex.quote(shutil.which(gcovr_exe))))
          return gcovr_exe, mesonlib.version_compare(found, '>=' + version)
      return None, None
  
  def find_coverage_tools():
      gcovr_exe, gcovr_new_rootdir = detect_gcovr()
  
      lcov_exe = 'lcov'
      genhtml_exe = 'genhtml'
  
      if not mesonlib.exe_exists([lcov_exe, '--version']):
          lcov_exe = None
      if not mesonlib.exe_exists([genhtml_exe, '--version']):
          genhtml_exe = None
  
      return gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe
  
  def detect_ninja(version='1.5', log=False):
      for n in ['ninja', 'ninja-build']:
          try:
              p, found = Popen_safe([n, '--version'])[0:2]
          except (FileNotFoundError, PermissionError):
              # Doesn't exist in PATH or isn't executable
              continue
          found = found.strip()
          # Perhaps we should add a way for the caller to know the failure mode
          # (not found or too old)
          if p.returncode == 0 and mesonlib.version_compare(found, '>=' + version):
              if log:
                  mlog.log('Found ninja-{} at {}'.format(found, shlex.quote(shutil.which(n))))
              return n
  
  def detect_native_windows_arch():
      """
      The architecture of Windows itself: x86 or amd64
      """
      # These env variables are always available. See:
      # https://msdn.microsoft.com/en-us/library/aa384274(VS.85).aspx
      # https://blogs.msdn.microsoft.com/david.wang/2006/03/27/howto-detect-process-bitness/
      arch = os.environ.get('PROCESSOR_ARCHITEW6432', '').lower()
      if not arch:
          try:
              # If this doesn't exist, something is messing with the environment
              arch = os.environ['PROCESSOR_ARCHITECTURE'].lower()
          except KeyError:
              raise EnvironmentException('Unable to detect native OS architecture')
      return arch
  
  def detect_windows_arch(compilers):
      """
      Detecting the 'native' architecture of Windows is not a trivial task. We
      cannot trust that the architecture that Python is built for is the 'native'
      one because you can run 32-bit apps on 64-bit Windows using WOW64 and
      people sometimes install 32-bit Python on 64-bit Windows.
  
      We also can't rely on the architecture of the OS itself, since it's
      perfectly normal to compile and run 32-bit applications on Windows as if
      they were native applications. It's a terrible experience to require the
      user to supply a cross-info file to compile 32-bit applications on 64-bit
      Windows. Thankfully, the only way to compile things with Visual Studio on
      Windows is by entering the 'msvc toolchain' environment, which can be
      easily detected.
  
      In the end, the sanest method is as follows:
      1. Check if we're in an MSVC toolchain environment, and if so, return the
         MSVC toolchain architecture as our 'native' architecture.
      2. If not, check environment variables that are set by Windows and WOW64 to
         find out the architecture that Windows is built for, and use that as our
         'native' architecture.
      """
      os_arch = detect_native_windows_arch()
      if os_arch != 'amd64':
          return os_arch
      # If we're on 64-bit Windows, 32-bit apps can be compiled without
      # cross-compilation. So if we're doing that, just set the native arch as
      # 32-bit and pretend like we're running under WOW64. Else, return the
      # actual Windows architecture that we deduced above.
      for compiler in compilers.values():
          # Check if we're using and inside an MSVC toolchain environment
          if compiler.id == 'msvc' and 'VCINSTALLDIR' in os.environ:
              if float(compiler.get_toolset_version()) < 10.0:
                  # On MSVC 2008 and earlier, check 'BUILD_PLAT', where
                  # 'Win32' means 'x86'
                  platform = os.environ.get('BUILD_PLAT', 'x86')
                  if platform == 'Win32':
                      return 'x86'
              else:
                  # On MSVC 2010 and later 'Platform' is only set when the
                  # target arch is not 'x86'.  It's 'x64' when targeting
                  # x86_64 and 'arm' when targeting ARM.
                  platform = os.environ.get('Platform', 'x86').lower()
              if platform == 'x86':
                  return platform
          if compiler.id == 'gcc' and compiler.has_builtin_define('__i386__'):
              return 'x86'
      return os_arch
  
  def detect_cpu_family(compilers):
      """
      Python is inconsistent in its platform module.
      It returns different values for the same cpu.
      For x86 it might return 'x86', 'i686' or somesuch.
      Do some canonicalization.
      """
      if mesonlib.is_windows():
          trial = detect_windows_arch(compilers)
      else:
          trial = platform.machine().lower()
      if trial.startswith('i') and trial.endswith('86'):
          return 'x86'
      if trial.startswith('arm'):
          return 'arm'
      if trial in ('amd64', 'x64'):
          trial = 'x86_64'
      if trial == 'x86_64':
          # On Linux (and maybe others) there can be any mixture of 32/64 bit
          # code in the kernel, Python, system etc. The only reliable way
          # to know is to check the compiler defines.
          for c in compilers.values():
              try:
                  if c.has_builtin_define('__i386__'):
                      return 'x86'
  
  
  [... the rest is omitted ...]
files: mesonbuild/environment.py
files: # 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
  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 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):
          super().__init__()
          if not isinstance(cmd, ExternalProgram):
              raise AssertionError('BUG: RunProcess must be passed an ExternalProgram')
          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)
          mlog.debug('Running command:', ' '.join(command_array))
          try:
              p, o, e = Popen_safe(command_array, env=child_env, cwd=cwd)
              mlog.debug('--- stdout----')
              mlog.debug(o)
              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(
  
  [... the rest is omitted ...]
files: mesonbuild/interpreter.py
files: # 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
  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 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):
          super().__init__()
          if not isinstance(cmd, ExternalProgram):
              raise AssertionError('BUG: RunProcess must be passed an ExternalProgram')
          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)
          mlog.debug('Running command:', ' '.join(command_array))
          try:
              p, o, e = Popen_safe(command_array, env=child_env, cwd=cwd)
              mlog.debug('--- stdout----')
              mlog.debug(o)
              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(
  
  [... the rest is omitted ...]
files: mesonbuild/interpreter.py
files: # Copyright 2014-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
  import sys
  import argparse
  from . import (coredata, mesonlib, build)
  
  def buildparser():
      parser = argparse.ArgumentParser(prog='meson configure')
      coredata.register_builtin_arguments(parser)
  
      parser.add_argument('directory', nargs='*')
      parser.add_argument('--clearcache', action='store_true', default=False,
                          help='Clear cached state (e.g. found dependencies)')
      return parser
  
  
  class ConfException(mesonlib.MesonException):
      pass
  
  
  class Conf:
      def __init__(self, build_dir):
          self.build_dir = build_dir
          if not os.path.isdir(os.path.join(build_dir, 'meson-private')):
              raise ConfException('Directory %s does not seem to be a Meson build directory.' % build_dir)
          self.build = build.load(self.build_dir)
          self.coredata = coredata.load(self.build_dir)
  
      def clear_cache(self):
          self.coredata.deps = {}
  
      def set_options(self, options):
          self.coredata.set_options(options)
  
      def save(self):
          # Only called if something has changed so overwrite unconditionally.
          coredata.save(self.coredata, self.build_dir)
          # We don't write the build file because any changes to it
          # are erased when Meson is executed the next time, i.e. when
          # Ninja is run.
  
      @staticmethod
      def print_aligned(arr):
          def make_lower_case(val):
              if isinstance(val, bool):
                  return str(val).lower()
              elif isinstance(val, list):
                  return [make_lower_case(i) for i in val]
              else:
                  return str(val)
  
          if not arr:
              return
  
          titles = {'name': 'Option', 'descr': 'Description', 'value': 'Current Value', 'choices': 'Possible Values'}
  
          name_col = [titles['name'], '-' * len(titles['name'])]
          value_col = [titles['value'], '-' * len(titles['value'])]
          choices_col = [titles['choices'], '-' * len(titles['choices'])]
          descr_col = [titles['descr'], '-' * len(titles['descr'])]
  
          choices_found = False
          for opt in arr:
              name_col.append(opt['name'])
              descr_col.append(opt['descr'])
              if isinstance(opt['value'], list):
                  value_col.append('[{0}]'.format(', '.join(make_lower_case(opt['value']))))
              else:
                  value_col.append(make_lower_case(opt['value']))
              if opt['choices']:
                  choices_found = True
                  choices_col.append('[{0}]'.format(', '.join(make_lower_case(opt['choices']))))
              else:
                  choices_col.append('')
  
          col_widths = (max([len(i) for i in name_col], default=0),
                        max([len(i) for i in value_col], default=0),
                        max([len(i) for i in choices_col], default=0),
                        max([len(i) for i in descr_col], default=0))
  
          for line in zip(name_col, value_col, choices_col, descr_col):
              if choices_found:
                  print('  {0:{width[0]}} {1:{width[1]}} {2:{width[2]}} {3:{width[3]}}'.format(*line, width=col_widths))
              else:
                  print('  {0:{width[0]}} {1:{width[1]}} {3:{width[3]}}'.format(*line, width=col_widths))
  
      def print_conf(self):
          print('Core properties:')
          print('  Source dir', self.build.environment.source_dir)
          print('  Build dir ', self.build.environment.build_dir)
          print('\nCore options:')
          carr = []
          for key in ['buildtype', 'warning_level', 'werror', 'strip', 'unity', 'default_library', 'install_umask']:
              carr.append({'name': key,
                           'descr': coredata.get_builtin_option_description(key),
                           'value': self.coredata.get_builtin_option(key),
                           'choices': coredata.get_builtin_option_choices(key)})
          self.print_aligned(carr)
          print('\nBackend options:')
          if not self.coredata.backend_options:
              print('  No backend options\n')
          else:
              bearr = []
              for k in sorted(self.coredata.backend_options):
                  o = self.coredata.backend_options[k]
                  bearr.append({'name': k, 'descr': o.description, 'value': o.value, 'choices': ''})
              self.print_aligned(bearr)
          print('\nBase options:')
          if not self.coredata.base_options:
              print('  No base options\n')
          else:
              coarr = []
              for k in sorted(self.coredata.base_options):
                  o = self.coredata.base_options[k]
                  coarr.append({'name': k, 'descr': o.description, 'value': o.value, 'choices': o.choices})
              self.print_aligned(coarr)
          print('\nCompiler options:')
          if not self.coredata.compiler_options:
              print('  No compiler options\n')
          else:
              coarr = []
              for k in self.coredata.compiler_options:
                  o = self.coredata.compiler_options[k]
                  coarr.append({'name': k, 'descr': o.description, 'value': o.value, 'choices': ''})
              self.print_aligned(coarr)
          print('\nDirectories:')
          parr = []
          for key in ['prefix',
                      'libdir',
                      'libexecdir',
                      'bindir',
                      'sbindir',
                      'includedir',
                      'datadir',
                      'mandir',
                      'infodir',
                      'localedir',
                      'sysconfdir',
                      'localstatedir',
                      'sharedstatedir',
                      ]:
              parr.append({'name': key,
                           'descr': coredata.get_builtin_option_description(key),
                           'value': self.coredata.get_builtin_option(key),
                           'choices': coredata.get_builtin_option_choices(key)})
          self.print_aligned(parr)
          print('\nProject options:')
          if not self.coredata.user_options:
              print('  This project does not have any options')
          else:
              optarr = []
              for key in sorted(self.coredata.user_options):
                  opt = self.coredata.user_options[key]
                  if (opt.choices is None) or (not opt.choices):
                      # Zero length list or string
                      choices = ''
                  else:
                      choices = opt.choices
                  optarr.append({'name': key,
                                 'descr': opt.description,
                                 'value': opt.value,
                                 'choices': choices})
              self.print_aligned(optarr)
          print('\nTesting options:')
          tarr = []
          for key in ['stdsplit', 'errorlogs']:
              tarr.append({'name': key,
                           'descr': coredata.get_builtin_option_description(key),
                           'value': self.coredata.get_builtin_option(key),
                           'choices': coredata.get_builtin_option_choices(key)})
          self.print_aligned(tarr)
  
  
  def run(args):
      args = mesonlib.expand_arguments(args)
      if not args:
          args = [os.getcwd()]
      options = buildparser().parse_args(args)
      coredata.filter_builtin_options(options, args)
      if len(options.directory) > 1:
          print('%s <build directory>' % args[0])
          print('If you omit the build directory, the current directory is substituted.')
          return 1
      if not options.directory:
          builddir = os.getcwd()
      else:
          builddir = options.directory[0]
      try:
          c = Conf(builddir)
          save = False
          if len(options.projectoptions) > 0:
              c.set_options(options.projectoptions)
              save = True
          elif options.clearcache:
              c.clear_cache()
              save = True
          else:
              c.print_conf()
          if save:
              c.save()
      except ConfException as e:
          print('Meson configurator encountered an error:')
          raise e
      return 0
  
  
  if __name__ == '__main__':
     
  
  [... the rest is omitted ...]
files: mesonbuild/mconf.py
files: # Copyright 2014-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
  import sys
  import argparse
  from . import (coredata, mesonlib, build)
  
  def buildparser():
      parser = argparse.ArgumentParser(prog='meson configure')
      coredata.register_builtin_arguments(parser)
  
      parser.add_argument('directory', nargs='*')
      parser.add_argument('--clearcache', action='store_true', default=False,
                          help='Clear cached state (e.g. found dependencies)')
      return parser
  
  
  class ConfException(mesonlib.MesonException):
      pass
  
  
  class Conf:
      def __init__(self, build_dir):
          self.build_dir = build_dir
          if not os.path.isdir(os.path.join(build_dir, 'meson-private')):
              raise ConfException('Directory %s does not seem to be a Meson build directory.' % build_dir)
          self.build = build.load(self.build_dir)
          self.coredata = coredata.load(self.build_dir)
  
      def clear_cache(self):
          self.coredata.deps = {}
  
      def save(self):
          # Only called if something has changed so overwrite unconditionally.
          coredata.save(self.coredata, self.build_dir)
          # We don't write the build file because any changes to it
          # are erased when Meson is executed the next time, i.e. when
          # Ninja is run.
  
      @staticmethod
      def print_aligned(arr):
          def make_lower_case(val):
              if isinstance(val, bool):
                  return str(val).lower()
              elif isinstance(val, list):
                  return [make_lower_case(i) for i in val]
              else:
                  return str(val)
  
          if not arr:
              return
  
          titles = {'name': 'Option', 'descr': 'Description', 'value': 'Current Value', 'choices': 'Possible Values'}
  
          name_col = [titles['name'], '-' * len(titles['name'])]
          value_col = [titles['value'], '-' * len(titles['value'])]
          choices_col = [titles['choices'], '-' * len(titles['choices'])]
          descr_col = [titles['descr'], '-' * len(titles['descr'])]
  
          choices_found = False
          for opt in arr:
              name_col.append(opt['name'])
              descr_col.append(opt['descr'])
              if isinstance(opt['value'], list):
                  value_col.append('[{0}]'.format(', '.join(make_lower_case(opt['value']))))
              else:
                  value_col.append(make_lower_case(opt['value']))
              if opt['choices']:
                  choices_found = True
                  choices_col.append('[{0}]'.format(', '.join(make_lower_case(opt['choices']))))
              else:
                  choices_col.append('')
  
          col_widths = (max([len(i) for i in name_col], default=0),
                        max([len(i) for i in value_col], default=0),
                        max([len(i) for i in choices_col], default=0),
                        max([len(i) for i in descr_col], default=0))
  
          for line in zip(name_col, value_col, choices_col, descr_col):
              if choices_found:
                  print('  {0:{width[0]}} {1:{width[1]}} {2:{width[2]}} {3:{width[3]}}'.format(*line, width=col_widths))
              else:
                  print('  {0:{width[0]}} {1:{width[1]}} {3:{width[3]}}'.format(*line, width=col_widths))
  
      def set_options(self, options):
          for o in options:
              if '=' not in o:
                  raise ConfException('Value "%s" not of type "a=b".' % o)
              (k, v) = o.split('=', 1)
              if coredata.is_builtin_option(k):
                  self.coredata.set_builtin_option(k, v)
              elif k in self.coredata.backend_options:
                  tgt = self.coredata.backend_options[k]
                  tgt.set_value(v)
              elif k in self.coredata.user_options:
                  tgt = self.coredata.user_options[k]
                  tgt.set_value(v)
              elif k in self.coredata.compiler_options:
                  tgt = self.coredata.compiler_options[k]
                  tgt.set_value(v)
              elif k in self.coredata.base_options:
                  tgt = self.coredata.base_options[k]
                  tgt.set_value(v)
              else:
                  raise ConfException('Unknown option %s.' % k)
  
      def print_conf(self):
          print('Core properties:')
          print('  Source dir', self.build.environment.source_dir)
          print('  Build dir ', self.build.environment.build_dir)
          print('\nCore options:')
          carr = []
          for key in ['buildtype', 'warning_level', 'werror', 'strip', 'unity', 'default_library', 'install_umask']:
              carr.append({'name': key,
                           'descr': coredata.get_builtin_option_description(key),
                           'value': self.coredata.get_builtin_option(key),
                           'choices': coredata.get_builtin_option_choices(key)})
          self.print_aligned(carr)
          print('\nBackend options:')
          if not self.coredata.backend_options:
              print('  No backend options\n')
          else:
              bearr = []
              for k in sorted(self.coredata.backend_options):
                  o = self.coredata.backend_options[k]
                  bearr.append({'name': k, 'descr': o.description, 'value': o.value, 'choices': ''})
              self.print_aligned(bearr)
          print('\nBase options:')
          if not self.coredata.base_options:
              print('  No base options\n')
          else:
              coarr = []
              for k in sorted(self.coredata.base_options):
                  o = self.coredata.base_options[k]
                  coarr.append({'name': k, 'descr': o.description, 'value': o.value, 'choices': o.choices})
              self.print_aligned(coarr)
          print('\nCompiler options:')
          if not self.coredata.compiler_options:
              print('  No compiler options\n')
          else:
              coarr = []
              for k in self.coredata.compiler_options:
                  o = self.coredata.compiler_options[k]
                  coarr.append({'name': k, 'descr': o.description, 'value': o.value, 'choices': ''})
              self.print_aligned(coarr)
          print('\nDirectories:')
          parr = []
          for key in ['prefix',
                      'libdir',
                      'libexecdir',
                      'bindir',
                      'sbindir',
                      'includedir',
                      'datadir',
                      'mandir',
                      'infodir',
                      'localedir',
                      'sysconfdir',
                      'localstatedir',
                      'sharedstatedir',
                      ]:
              parr.append({'name': key,
                           'descr': coredata.get_builtin_option_description(key),
                           'value': self.coredata.get_builtin_option(key),
                           'choices': coredata.get_builtin_option_choices(key)})
          self.print_aligned(parr)
          print('\nProject options:')
          if not self.coredata.user_options:
              print('  This project does not have any options')
          else:
              optarr = []
              for key in sorted(self.coredata.user_options):
                  opt = self.coredata.user_options[key]
                  if (opt.choices is None) or (not opt.choices):
                      # Zero length list or string
                      choices = ''
                  else:
                      choices = opt.choices
                  optarr.append({'name': key,
                                 'descr': opt.description,
                                 'value': opt.value,
                                 'choices': choices})
              self.print_aligned(optarr)
          print('\nTesting options:')
          tarr = []
          for key in ['stdsplit', 'errorlogs']:
              tarr.append({'name': key,
                           'descr': coredata.get_builtin_option_description(key),
                           'value': self.coredata.get_builtin_option(key),
                           'choices': coredata.get_builtin_option_choices(key)})
          self.print_aligned(tarr)
  
  
  def run(args):
      args = mesonlib.expand_arguments(args)
      if not args:
          args = [os.getcwd()]
      options = build
  
  [... the rest is omitted ...]
files: mesonbuild/mconf.py