diff options
Diffstat (limited to 'Lib/sysconfig.py')
| -rw-r--r-- | Lib/sysconfig.py | 380 | 
1 files changed, 152 insertions, 228 deletions
| diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index b2183d8..ba4024f 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -1,8 +1,8 @@ -"""Provide access to Python's configuration information. +"""Access to Python's configuration information.""" -""" -import sys  import os +import re +import sys  from os.path import pardir, realpath  __all__ = [ @@ -17,50 +17,50 @@ __all__ = [      'get_python_version',      'get_scheme_names',      'parse_config_h', -    ] +]  _INSTALL_SCHEMES = {      'posix_prefix': { -        'stdlib': '{base}/lib/python{py_version_short}', +        'stdlib': '{installed_base}/lib/python{py_version_short}',          'platstdlib': '{platbase}/lib/python{py_version_short}',          'purelib': '{base}/lib/python{py_version_short}/site-packages',          'platlib': '{platbase}/lib/python{py_version_short}/site-packages',          'include': -            '{base}/include/python{py_version_short}{abiflags}', +            '{installed_base}/include/python{py_version_short}{abiflags}',          'platinclude': -            '{platbase}/include/python{py_version_short}{abiflags}', +            '{installed_platbase}/include/python{py_version_short}{abiflags}',          'scripts': '{base}/bin',          'data': '{base}',          },      'posix_home': { -        'stdlib': '{base}/lib/python', +        'stdlib': '{installed_base}/lib/python',          'platstdlib': '{base}/lib/python',          'purelib': '{base}/lib/python',          'platlib': '{base}/lib/python', -        'include': '{base}/include/python', -        'platinclude': '{base}/include/python', +        'include': '{installed_base}/include/python', +        'platinclude': '{installed_base}/include/python',          'scripts': '{base}/bin', -        'data'   : '{base}', +        'data': '{base}',          },      'nt': { -        'stdlib': '{base}/Lib', +        'stdlib': '{installed_base}/Lib',          'platstdlib': '{base}/Lib',          'purelib': '{base}/Lib/site-packages',          'platlib': '{base}/Lib/site-packages', -        'include': '{base}/Include', -        'platinclude': '{base}/Include', +        'include': '{installed_base}/Include', +        'platinclude': '{installed_base}/Include',          'scripts': '{base}/Scripts', -        'data'   : '{base}', +        'data': '{base}',          },      'os2': { -        'stdlib': '{base}/Lib', +        'stdlib': '{installed_base}/Lib',          'platstdlib': '{base}/Lib',          'purelib': '{base}/Lib/site-packages',          'platlib': '{base}/Lib/site-packages', -        'include': '{base}/Include', -        'platinclude': '{base}/Include', +        'include': '{installed_base}/Include', +        'platinclude': '{installed_base}/Include',          'scripts': '{base}/Scripts', -        'data'   : '{base}', +        'data': '{base}',          },      'os2_home': {          'stdlib': '{userbase}/lib/python{py_version_short}', @@ -69,7 +69,7 @@ _INSTALL_SCHEMES = {          'platlib': '{userbase}/lib/python{py_version_short}/site-packages',          'include': '{userbase}/include/python{py_version_short}',          'scripts': '{userbase}/bin', -        'data'   : '{userbase}', +        'data': '{userbase}',          },      'nt_user': {          'stdlib': '{userbase}/Python{py_version_nodot}', @@ -78,7 +78,7 @@ _INSTALL_SCHEMES = {          'platlib': '{userbase}/Python{py_version_nodot}/site-packages',          'include': '{userbase}/Python{py_version_nodot}/Include',          'scripts': '{userbase}/Scripts', -        'data'   : '{userbase}', +        'data': '{userbase}',          },      'posix_user': {          'stdlib': '{userbase}/lib/python{py_version_short}', @@ -87,7 +87,7 @@ _INSTALL_SCHEMES = {          'platlib': '{userbase}/lib/python{py_version_short}/site-packages',          'include': '{userbase}/include/python{py_version_short}',          'scripts': '{userbase}/bin', -        'data'   : '{userbase}', +        'data': '{userbase}',          },      'osx_framework_user': {          'stdlib': '{userbase}/lib/python', @@ -96,20 +96,26 @@ _INSTALL_SCHEMES = {          'platlib': '{userbase}/lib/python/site-packages',          'include': '{userbase}/include',          'scripts': '{userbase}/bin', -        'data'   : '{userbase}', +        'data': '{userbase}',          },      }  _SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include',                  'scripts', 'data') + + # FIXME don't rely on sys.version here, its format is an implementation detail + # of CPython, use sys.version_info or sys.hexversion  _PY_VERSION = sys.version.split()[0]  _PY_VERSION_SHORT = sys.version[:3]  _PY_VERSION_SHORT_NO_DOT = _PY_VERSION[0] + _PY_VERSION[2]  _PREFIX = os.path.normpath(sys.prefix) +_BASE_PREFIX = os.path.normpath(sys.base_prefix)  _EXEC_PREFIX = os.path.normpath(sys.exec_prefix) +_BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix)  _CONFIG_VARS = None  _USER_BASE = None +  def _safe_realpath(path):      try:          return realpath(path) @@ -132,19 +138,35 @@ if os.name == "nt" and "\\pc\\v" in _PROJECT_BASE[-10:].lower():  if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower():      _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir)) -def is_python_build(): +# set for cross builds +if "_PYTHON_PROJECT_BASE" in os.environ: +    _PROJECT_BASE = _safe_realpath(os.environ["_PYTHON_PROJECT_BASE"]) + +def _is_python_source_dir(d):      for fn in ("Setup.dist", "Setup.local"): -        if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)): +        if os.path.isfile(os.path.join(d, "Modules", fn)):              return True      return False -_PYTHON_BUILD = is_python_build() +_sys_home = getattr(sys, '_home', None) +if _sys_home and os.name == 'nt' and \ +    _sys_home.lower().endswith(('pcbuild', 'pcbuild\\amd64')): +    _sys_home = os.path.dirname(_sys_home) +    if _sys_home.endswith('pcbuild'):   # must be amd64 +        _sys_home = os.path.dirname(_sys_home) +def is_python_build(check_home=False): +    if check_home and _sys_home: +        return _is_python_source_dir(_sys_home) +    return _is_python_source_dir(_PROJECT_BASE) + +_PYTHON_BUILD = is_python_build(True)  if _PYTHON_BUILD:      for scheme in ('posix_prefix', 'posix_home'):          _INSTALL_SCHEMES[scheme]['include'] = '{srcdir}/Include'          _INSTALL_SCHEMES[scheme]['platinclude'] = '{projectbase}/.' +  def _subst_vars(s, local_vars):      try:          return s.format(**local_vars) @@ -161,6 +183,7 @@ def _extend_dict(target_dict, other_dict):              continue          target_dict[key] = value +  def _expand_vars(scheme, vars):      res = {}      if vars is None: @@ -173,29 +196,41 @@ def _expand_vars(scheme, vars):          res[key] = os.path.normpath(_subst_vars(value, vars))      return res +  def _get_default_scheme():      if os.name == 'posix':          # the default scheme for posix is posix_prefix          return 'posix_prefix'      return os.name +  def _getuserbase():      env_base = os.environ.get("PYTHONUSERBASE", None) +      def joinuser(*args):          return os.path.expanduser(os.path.join(*args))      # what about 'os2emx', 'riscos' ?      if os.name == "nt":          base = os.environ.get("APPDATA") or "~" -        return env_base if env_base else joinuser(base, "Python") +        if env_base: +            return env_base +        else: +            return joinuser(base, "Python")      if sys.platform == "darwin":          framework = get_config_var("PYTHONFRAMEWORK")          if framework: -            return env_base if env_base else joinuser("~", "Library", framework, "%d.%d"%( -                sys.version_info[:2])) +            if env_base: +                return env_base +            else: +                return joinuser("~", "Library", framework, "%d.%d" % +                                sys.version_info[:2]) -    return env_base if env_base else joinuser("~", ".local") +    if env_base: +        return env_base +    else: +        return joinuser("~", ".local")  def _parse_makefile(filename, vars=None): @@ -205,7 +240,6 @@ def _parse_makefile(filename, vars=None):      optional dictionary is passed in as the second argument, it is      used instead of a new dictionary.      """ -    import re      # Regexes needed for parsing Makefile (and similar syntaxes,      # like old-style Setup files).      _variable_rx = re.compile("([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") @@ -267,7 +301,8 @@ def _parse_makefile(filename, vars=None):                      item = os.environ[n]                  elif n in renamed_variables: -                    if name.startswith('PY_') and name[3:] in renamed_variables: +                    if (name.startswith('PY_') and +                        name[3:] in renamed_variables):                          item = ""                      elif 'PY_' + n in notdone: @@ -300,7 +335,6 @@ def _parse_makefile(filename, vars=None):                              if name not in done:                                  done[name] = value -              else:                  # bogus variable reference (e.g. "prefix=$/opt/python");                  # just drop it since we can't deal @@ -320,14 +354,17 @@ def _parse_makefile(filename, vars=None):  def get_makefile_filename():      """Return the path of the Makefile."""      if _PYTHON_BUILD: -        return os.path.join(_PROJECT_BASE, "Makefile") -    return os.path.join(get_path('stdlib'), -                        'config-{}{}'.format(_PY_VERSION_SHORT, sys.abiflags), -                        'Makefile') - +        return os.path.join(_sys_home or _PROJECT_BASE, "Makefile") +    if hasattr(sys, 'abiflags'): +        config_dir_name = 'config-%s%s' % (_PY_VERSION_SHORT, sys.abiflags) +    else: +        config_dir_name = 'config' +    return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile') -def _init_posix(vars): -    """Initialize the module as appropriate for POSIX systems.""" +def _generate_posix_vars(): +    """Generate the Python module containing build-time variables.""" +    import pprint +    vars = {}      # load the installed Makefile:      makefile = get_makefile_filename()      try: @@ -353,6 +390,19 @@ def _init_posix(vars):      if _PYTHON_BUILD:          vars['LDSHARED'] = vars['BLDSHARED'] +    destfile = os.path.join(os.path.dirname(__file__), '_sysconfigdata.py') +    with open(destfile, 'w', encoding='utf8') as f: +        f.write('# system configuration generated and used by' +                ' the sysconfig module\n') +        f.write('build_time_vars = ') +        pprint.pprint(vars, stream=f) + +def _init_posix(vars): +    """Initialize the module as appropriate for POSIX systems.""" +    # _sysconfigdata is generated at build time, see _generate_posix_vars() +    from _sysconfigdata import build_time_vars +    vars.update(build_time_vars) +  def _init_non_posix(vars):      """Initialize the module as appropriate for NT"""      # set basic install directories @@ -376,7 +426,6 @@ def parse_config_h(fp, vars=None):      optional dictionary is passed in as the second argument, it is      used instead of a new dictionary.      """ -    import re      if vars is None:          vars = {}      define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n") @@ -389,8 +438,10 @@ def parse_config_h(fp, vars=None):          m = define_rx.match(line)          if m:              n, v = m.group(1, 2) -            try: v = int(v) -            except ValueError: pass +            try: +                v = int(v) +            except ValueError: +                pass              vars[n] = v          else:              m = undef_rx.match(line) @@ -398,27 +449,29 @@ def parse_config_h(fp, vars=None):                  vars[m.group(1)] = 0      return vars +  def get_config_h_filename():      """Return the path of pyconfig.h."""      if _PYTHON_BUILD:          if os.name == "nt": -            inc_dir = os.path.join(_PROJECT_BASE, "PC") +            inc_dir = os.path.join(_sys_home or _PROJECT_BASE, "PC")          else: -            inc_dir = _PROJECT_BASE +            inc_dir = _sys_home or _PROJECT_BASE      else:          inc_dir = get_path('platinclude')      return os.path.join(inc_dir, 'pyconfig.h') +  def get_scheme_names():      """Return a tuple containing the schemes names.""" -    schemes = list(_INSTALL_SCHEMES.keys()) -    schemes.sort() -    return tuple(schemes) +    return tuple(sorted(_INSTALL_SCHEMES)) +  def get_path_names():      """Return a tuple containing the paths names."""      return _SCHEME_KEYS +  def get_paths(scheme=_get_default_scheme(), vars=None, expand=True):      """Return a mapping containing an install scheme. @@ -430,6 +483,7 @@ def get_paths(scheme=_get_default_scheme(), vars=None, expand=True):      else:          return _INSTALL_SCHEMES[scheme] +  def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True):      """Return a path corresponding to the scheme. @@ -437,17 +491,17 @@ def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True):      """      return get_paths(scheme, vars, expand)[name] +  def get_config_vars(*args):      """With no arguments, return a dictionary of all configuration      variables relevant for the current platform.      On Unix, this means every variable defined in Python's installed Makefile; -    On Windows and Mac OS it's a much smaller set. +    On Windows it's a much smaller set.      With arguments, return a list of values that result from looking up      each argument in the configuration variable dictionary.      """ -    import re      global _CONFIG_VARS      if _CONFIG_VARS is None:          _CONFIG_VARS = {} @@ -459,7 +513,9 @@ def get_config_vars(*args):          _CONFIG_VARS['py_version'] = _PY_VERSION          _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT          _CONFIG_VARS['py_version_nodot'] = _PY_VERSION[0] + _PY_VERSION[2] +        _CONFIG_VARS['installed_base'] = _BASE_PREFIX          _CONFIG_VARS['base'] = _PREFIX +        _CONFIG_VARS['installed_platbase'] = _BASE_EXEC_PREFIX          _CONFIG_VARS['platbase'] = _EXEC_PREFIX          _CONFIG_VARS['projectbase'] = _PROJECT_BASE          try: @@ -477,88 +533,28 @@ def get_config_vars(*args):          # the init-function.          _CONFIG_VARS['userbase'] = _getuserbase() -        if 'srcdir' not in _CONFIG_VARS: -            _CONFIG_VARS['srcdir'] = _PROJECT_BASE -        else: -            _CONFIG_VARS['srcdir'] = _safe_realpath(_CONFIG_VARS['srcdir']) - - -        # Convert srcdir into an absolute path if it appears necessary. -        # Normally it is relative to the build directory.  However, during -        # testing, for example, we might be running a non-installed python -        # from a different directory. -        if _PYTHON_BUILD and os.name == "posix": -            base = _PROJECT_BASE -            try: -                cwd = os.getcwd() -            except OSError: -                cwd = None -            if (not os.path.isabs(_CONFIG_VARS['srcdir']) and -                base != cwd): -                # srcdir is relative and we are not in the same directory -                # as the executable. Assume executable is in the build -                # directory and make srcdir absolute. -                srcdir = os.path.join(base, _CONFIG_VARS['srcdir']) -                _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir) - -        if sys.platform == 'darwin': -            kernel_version = os.uname()[2] # Kernel version (8.4.3) -            major_version = int(kernel_version.split('.')[0]) - -            if major_version < 8: -                # On Mac OS X before 10.4, check if -arch and -isysroot -                # are in CFLAGS or LDFLAGS and remove them if they are. -                # This is needed when building extensions on a 10.3 system -                # using a universal build of python. -                for key in ('LDFLAGS', 'BASECFLAGS', -                        # a number of derived variables. These need to be -                        # patched up as well. -                        'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): -                    flags = _CONFIG_VARS[key] -                    flags = re.sub('-arch\s+\w+\s', ' ', flags) -                    flags = re.sub('-isysroot [^ \t]*', ' ', flags) -                    _CONFIG_VARS[key] = flags +        # Always convert srcdir to an absolute path +        srcdir = _CONFIG_VARS.get('srcdir', _PROJECT_BASE) +        if os.name == 'posix': +            if _PYTHON_BUILD: +                # If srcdir is a relative path (typically '.' or '..') +                # then it should be interpreted relative to the directory +                # containing Makefile. +                base = os.path.dirname(get_makefile_filename()) +                srcdir = os.path.join(base, srcdir)              else: -                # Allow the user to override the architecture flags using -                # an environment variable. -                # NOTE: This name was introduced by Apple in OSX 10.5 and -                # is used by several scripting languages distributed with -                # that OS release. -                if 'ARCHFLAGS' in os.environ: -                    arch = os.environ['ARCHFLAGS'] -                    for key in ('LDFLAGS', 'BASECFLAGS', -                        # a number of derived variables. These need to be -                        # patched up as well. -                        'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - -                        flags = _CONFIG_VARS[key] -                        flags = re.sub('-arch\s+\w+\s', ' ', flags) -                        flags = flags + ' ' + arch -                        _CONFIG_VARS[key] = flags - -                # If we're on OSX 10.5 or later and the user tries to -                # compiles an extension using an SDK that is not present -                # on the current machine it is better to not use an SDK -                # than to fail. -                # -                # The major usecase for this is users using a Python.org -                # binary installer  on OSX 10.6: that installer uses -                # the 10.4u SDK, but that SDK is not installed by default -                # when you install Xcode. -                # -                CFLAGS = _CONFIG_VARS.get('CFLAGS', '') -                m = re.search('-isysroot\s+(\S+)', CFLAGS) -                if m is not None: -                    sdk = m.group(1) -                    if not os.path.exists(sdk): -                        for key in ('LDFLAGS', 'BASECFLAGS', -                             # a number of derived variables. These need to be -                             # patched up as well. -                            'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - -                            flags = _CONFIG_VARS[key] -                            flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags) -                            _CONFIG_VARS[key] = flags +                # srcdir is not meaningful since the installation is +                # spread about the filesystem.  We choose the +                # directory containing the Makefile since we know it +                # exists. +                srcdir = os.path.dirname(get_makefile_filename()) +        _CONFIG_VARS['srcdir'] = _safe_realpath(srcdir) + +        # OS X platforms require special customization to handle +        # multi-architecture, multi-os-version installers +        if sys.platform == 'darwin': +            import _osx_support +            _osx_support.customize_config_vars(_CONFIG_VARS)      if args:          vals = [] @@ -568,6 +564,7 @@ def get_config_vars(*args):      else:          return _CONFIG_VARS +  def get_config_var(name):      """Return the value of a single variable using the dictionary returned by      'get_config_vars()'. @@ -576,6 +573,7 @@ def get_config_var(name):      """      return get_config_vars().get(name) +  def get_platform():      """Return a string that identifies the current platform. @@ -601,7 +599,6 @@ def get_platform():      For other non-POSIX platforms, currently just returns 'sys.platform'.      """ -    import re      if os.name == 'nt':          # sniff sys.version for architecture.          prefix = " bit (" @@ -617,10 +614,13 @@ def get_platform():          return sys.platform      if os.name != "posix" or not hasattr(os, 'uname'): -        # XXX what about the architecture? NT is Intel or Alpha, -        # Mac OS is M68k or PPC, etc. +        # XXX what about the architecture? NT is Intel or Alpha          return sys.platform +    # Set for cross builds explicitly +    if "_PYTHON_HOST_PLATFORM" in os.environ: +        return os.environ["_PYTHON_HOST_PLATFORM"] +      # Try to distinguish various flavours of Unix      osname, host, release, version, machine = os.uname() @@ -651,97 +651,15 @@ def get_platform():          return "%s-%s.%s" % (osname, version, release)      elif osname[:6] == "cygwin":          osname = "cygwin" -        rel_re = re.compile (r'[\d.]+') +        rel_re = re.compile(r'[\d.]+')          m = rel_re.match(release)          if m:              release = m.group()      elif osname[:6] == "darwin": -        # -        # For our purposes, we'll assume that the system version from -        # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set -        # to. This makes the compatibility story a bit more sane because the -        # machine is going to compile and link as if it were -        # MACOSX_DEPLOYMENT_TARGET. -        # -        cfgvars = get_config_vars() -        macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') - -        if 1: -            # Always calculate the release of the running machine, -            # needed to determine if we can build fat binaries or not. - -            macrelease = macver -            # Get the system version. Reading this plist is a documented -            # way to get the system version (see the documentation for -            # the Gestalt Manager) -            try: -                f = open('/System/Library/CoreServices/SystemVersion.plist') -            except IOError: -                # We're on a plain darwin box, fall back to the default -                # behaviour. -                pass -            else: -                try: -                    m = re.search( -                            r'<key>ProductUserVisibleVersion</key>\s*' + -                            r'<string>(.*?)</string>', f.read()) -                    if m is not None: -                        macrelease = '.'.join(m.group(1).split('.')[:2]) -                    # else: fall back to the default behaviour -                finally: -                    f.close() - -        if not macver: -            macver = macrelease - -        if macver: -            release = macver -            osname = "macosx" - -            if (macrelease + '.') >= '10.4.' and \ -                    '-arch' in get_config_vars().get('CFLAGS', '').strip(): -                # The universal build will build fat binaries, but not on -                # systems before 10.4 -                # -                # Try to detect 4-way universal builds, those have machine-type -                # 'universal' instead of 'fat'. - -                machine = 'fat' -                cflags = get_config_vars().get('CFLAGS') - -                archs = re.findall('-arch\s+(\S+)', cflags) -                archs = tuple(sorted(set(archs))) - -                if len(archs) == 1: -                    machine = archs[0] -                elif archs == ('i386', 'ppc'): -                    machine = 'fat' -                elif archs == ('i386', 'x86_64'): -                    machine = 'intel' -                elif archs == ('i386', 'ppc', 'x86_64'): -                    machine = 'fat3' -                elif archs == ('ppc64', 'x86_64'): -                    machine = 'fat64' -                elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'): -                    machine = 'universal' -                else: -                    raise ValueError( -                       "Don't know machine value for archs=%r"%(archs,)) - -            elif machine == 'i386': -                # On OSX the machine type returned by uname is always the -                # 32-bit variant, even if the executable architecture is -                # the 64-bit variant -                if sys.maxsize >= 2**32: -                    machine = 'x86_64' - -            elif machine in ('PowerPC', 'Power_Macintosh'): -                # Pick a sane name for the PPC architecture. -                # See 'i386' case -                if sys.maxsize >= 2**32: -                    machine = 'ppc64' -                else: -                    machine = 'ppc' +        import _osx_support +        osname, release, machine = _osx_support.get_platform_osx( +                                            get_config_vars(), +                                            osname, release, machine)      return "%s-%s-%s" % (osname, release, machine) @@ -749,21 +667,27 @@ def get_platform():  def get_python_version():      return _PY_VERSION_SHORT +  def _print_dict(title, data):      for index, (key, value) in enumerate(sorted(data.items())):          if index == 0: -            print('{0}: '.format(title)) -        print('\t{0} = "{1}"'.format(key, value)) +            print('%s: ' % (title)) +        print('\t%s = "%s"' % (key, value)) +  def _main():      """Display all information sysconfig detains.""" -    print('Platform: "{0}"'.format(get_platform())) -    print('Python version: "{0}"'.format(get_python_version())) -    print('Current installation scheme: "{0}"'.format(_get_default_scheme())) -    print('') +    if '--generate-posix-vars' in sys.argv: +        _generate_posix_vars() +        return +    print('Platform: "%s"' % get_platform()) +    print('Python version: "%s"' % get_python_version()) +    print('Current installation scheme: "%s"' % _get_default_scheme()) +    print()      _print_dict('Paths', get_paths()) -    print('') +    print()      _print_dict('Variables', get_config_vars()) +  if __name__ == '__main__':      _main() | 
