Home | History | Annotate | Download | only in Lib
      1 """Access to Python's configuration information."""
      2 
      3 import os
      4 import sys
      5 from os.path import pardir, realpath
      6 
      7 __all__ = [
      8     'get_config_h_filename',
      9     'get_config_var',
     10     'get_config_vars',
     11     'get_makefile_filename',
     12     'get_path',
     13     'get_path_names',
     14     'get_paths',
     15     'get_platform',
     16     'get_python_version',
     17     'get_scheme_names',
     18     'parse_config_h',
     19 ]
     20 
     21 _INSTALL_SCHEMES = {
     22     'posix_prefix': {
     23         'stdlib': '{installed_base}/lib/python{py_version_short}',
     24         'platstdlib': '{platbase}/lib/python{py_version_short}',
     25         'purelib': '{base}/lib/python{py_version_short}/site-packages',
     26         'platlib': '{platbase}/lib/python{py_version_short}/site-packages',
     27         'include':
     28             '{installed_base}/include/python{py_version_short}{abiflags}',
     29         'platinclude':
     30             '{installed_platbase}/include/python{py_version_short}{abiflags}',
     31         'scripts': '{base}/bin',
     32         'data': '{base}',
     33         },
     34     'posix_home': {
     35         'stdlib': '{installed_base}/lib/python',
     36         'platstdlib': '{base}/lib/python',
     37         'purelib': '{base}/lib/python',
     38         'platlib': '{base}/lib/python',
     39         'include': '{installed_base}/include/python',
     40         'platinclude': '{installed_base}/include/python',
     41         'scripts': '{base}/bin',
     42         'data': '{base}',
     43         },
     44     'nt': {
     45         'stdlib': '{installed_base}/Lib',
     46         'platstdlib': '{base}/Lib',
     47         'purelib': '{base}/Lib/site-packages',
     48         'platlib': '{base}/Lib/site-packages',
     49         'include': '{installed_base}/Include',
     50         'platinclude': '{installed_base}/Include',
     51         'scripts': '{base}/Scripts',
     52         'data': '{base}',
     53         },
     54     'nt_user': {
     55         'stdlib': '{userbase}/Python{py_version_nodot}',
     56         'platstdlib': '{userbase}/Python{py_version_nodot}',
     57         'purelib': '{userbase}/Python{py_version_nodot}/site-packages',
     58         'platlib': '{userbase}/Python{py_version_nodot}/site-packages',
     59         'include': '{userbase}/Python{py_version_nodot}/Include',
     60         'scripts': '{userbase}/Python{py_version_nodot}/Scripts',
     61         'data': '{userbase}',
     62         },
     63     'posix_user': {
     64         'stdlib': '{userbase}/lib/python{py_version_short}',
     65         'platstdlib': '{userbase}/lib/python{py_version_short}',
     66         'purelib': '{userbase}/lib/python{py_version_short}/site-packages',
     67         'platlib': '{userbase}/lib/python{py_version_short}/site-packages',
     68         'include': '{userbase}/include/python{py_version_short}',
     69         'scripts': '{userbase}/bin',
     70         'data': '{userbase}',
     71         },
     72     'osx_framework_user': {
     73         'stdlib': '{userbase}/lib/python',
     74         'platstdlib': '{userbase}/lib/python',
     75         'purelib': '{userbase}/lib/python/site-packages',
     76         'platlib': '{userbase}/lib/python/site-packages',
     77         'include': '{userbase}/include',
     78         'scripts': '{userbase}/bin',
     79         'data': '{userbase}',
     80         },
     81     }
     82 
     83 _SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include',
     84                 'scripts', 'data')
     85 
     86  # FIXME don't rely on sys.version here, its format is an implementation detail
     87  # of CPython, use sys.version_info or sys.hexversion
     88 _PY_VERSION = sys.version.split()[0]
     89 _PY_VERSION_SHORT = '%d.%d' % sys.version_info[:2]
     90 _PY_VERSION_SHORT_NO_DOT = '%d%d' % sys.version_info[:2]
     91 _PREFIX = os.path.normpath(sys.prefix)
     92 _BASE_PREFIX = os.path.normpath(sys.base_prefix)
     93 _EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
     94 _BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix)
     95 _CONFIG_VARS = None
     96 _USER_BASE = None
     97 
     98 
     99 def _safe_realpath(path):
    100     try:
    101         return realpath(path)
    102     except OSError:
    103         return path
    104 
    105 if sys.executable:
    106     _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable))
    107 else:
    108     # sys.executable can be empty if argv[0] has been changed and Python is
    109     # unable to retrieve the real program name
    110     _PROJECT_BASE = _safe_realpath(os.getcwd())
    111 
    112 if (os.name == 'nt' and
    113     _PROJECT_BASE.lower().endswith(('\\pcbuild\\win32', '\\pcbuild\\amd64'))):
    114     _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
    115 
    116 # set for cross builds
    117 if "_PYTHON_PROJECT_BASE" in os.environ:
    118     _PROJECT_BASE = _safe_realpath(os.environ["_PYTHON_PROJECT_BASE"])
    119 
    120 def _is_python_source_dir(d):
    121     for fn in ("Setup.dist", "Setup.local"):
    122         if os.path.isfile(os.path.join(d, "Modules", fn)):
    123             return True
    124     return False
    125 
    126 _sys_home = getattr(sys, '_home', None)
    127 if (_sys_home and os.name == 'nt' and
    128     _sys_home.lower().endswith(('\\pcbuild\\win32', '\\pcbuild\\amd64'))):
    129     _sys_home = os.path.dirname(os.path.dirname(_sys_home))
    130 def is_python_build(check_home=False):
    131     if check_home and _sys_home:
    132         return _is_python_source_dir(_sys_home)
    133     return _is_python_source_dir(_PROJECT_BASE)
    134 
    135 _PYTHON_BUILD = is_python_build(True)
    136 
    137 if _PYTHON_BUILD:
    138     for scheme in ('posix_prefix', 'posix_home'):
    139         _INSTALL_SCHEMES[scheme]['include'] = '{srcdir}/Include'
    140         _INSTALL_SCHEMES[scheme]['platinclude'] = '{projectbase}/.'
    141 
    142 
    143 def _subst_vars(s, local_vars):
    144     try:
    145         return s.format(**local_vars)
    146     except KeyError:
    147         try:
    148             return s.format(**os.environ)
    149         except KeyError as var:
    150             raise AttributeError('{%s}' % var)
    151 
    152 def _extend_dict(target_dict, other_dict):
    153     target_keys = target_dict.keys()
    154     for key, value in other_dict.items():
    155         if key in target_keys:
    156             continue
    157         target_dict[key] = value
    158 
    159 
    160 def _expand_vars(scheme, vars):
    161     res = {}
    162     if vars is None:
    163         vars = {}
    164     _extend_dict(vars, get_config_vars())
    165 
    166     for key, value in _INSTALL_SCHEMES[scheme].items():
    167         if os.name in ('posix', 'nt'):
    168             value = os.path.expanduser(value)
    169         res[key] = os.path.normpath(_subst_vars(value, vars))
    170     return res
    171 
    172 
    173 def _get_default_scheme():
    174     if os.name == 'posix':
    175         # the default scheme for posix is posix_prefix
    176         return 'posix_prefix'
    177     return os.name
    178 
    179 
    180 def _getuserbase():
    181     env_base = os.environ.get("PYTHONUSERBASE", None)
    182 
    183     def joinuser(*args):
    184         return os.path.expanduser(os.path.join(*args))
    185 
    186     if os.name == "nt":
    187         base = os.environ.get("APPDATA") or "~"
    188         if env_base:
    189             return env_base
    190         else:
    191             return joinuser(base, "Python")
    192 
    193     if sys.platform == "darwin":
    194         framework = get_config_var("PYTHONFRAMEWORK")
    195         if framework:
    196             if env_base:
    197                 return env_base
    198             else:
    199                 return joinuser("~", "Library", framework, "%d.%d" %
    200                                 sys.version_info[:2])
    201 
    202     if env_base:
    203         return env_base
    204     else:
    205         return joinuser("~", ".local")
    206 
    207 
    208 def _parse_makefile(filename, vars=None):
    209     """Parse a Makefile-style file.
    210 
    211     A dictionary containing name/value pairs is returned.  If an
    212     optional dictionary is passed in as the second argument, it is
    213     used instead of a new dictionary.
    214     """
    215     # Regexes needed for parsing Makefile (and similar syntaxes,
    216     # like old-style Setup files).
    217     import re
    218     _variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)")
    219     _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")
    220     _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")
    221 
    222     if vars is None:
    223         vars = {}
    224     done = {}
    225     notdone = {}
    226 
    227     with open(filename, errors="surrogateescape") as f:
    228         lines = f.readlines()
    229 
    230     for line in lines:
    231         if line.startswith('#') or line.strip() == '':
    232             continue
    233         m = _variable_rx.match(line)
    234         if m:
    235             n, v = m.group(1, 2)
    236             v = v.strip()
    237             # `$$' is a literal `$' in make
    238             tmpv = v.replace('$$', '')
    239 
    240             if "$" in tmpv:
    241                 notdone[n] = v
    242             else:
    243                 try:
    244                     v = int(v)
    245                 except ValueError:
    246                     # insert literal `$'
    247                     done[n] = v.replace('$$', '$')
    248                 else:
    249                     done[n] = v
    250 
    251     # do variable interpolation here
    252     variables = list(notdone.keys())
    253 
    254     # Variables with a 'PY_' prefix in the makefile. These need to
    255     # be made available without that prefix through sysconfig.
    256     # Special care is needed to ensure that variable expansion works, even
    257     # if the expansion uses the name without a prefix.
    258     renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')
    259 
    260     while len(variables) > 0:
    261         for name in tuple(variables):
    262             value = notdone[name]
    263             m1 = _findvar1_rx.search(value)
    264             m2 = _findvar2_rx.search(value)
    265             if m1 and m2:
    266                 m = m1 if m1.start() < m2.start() else m2
    267             else:
    268                 m = m1 if m1 else m2
    269             if m is not None:
    270                 n = m.group(1)
    271                 found = True
    272                 if n in done:
    273                     item = str(done[n])
    274                 elif n in notdone:
    275                     # get it on a subsequent round
    276                     found = False
    277                 elif n in os.environ:
    278                     # do it like make: fall back to environment
    279                     item = os.environ[n]
    280 
    281                 elif n in renamed_variables:
    282                     if (name.startswith('PY_') and
    283                         name[3:] in renamed_variables):
    284                         item = ""
    285 
    286                     elif 'PY_' + n in notdone:
    287                         found = False
    288 
    289                     else:
    290                         item = str(done['PY_' + n])
    291 
    292                 else:
    293                     done[n] = item = ""
    294 
    295                 if found:
    296                     after = value[m.end():]
    297                     value = value[:m.start()] + item + after
    298                     if "$" in after:
    299                         notdone[name] = value
    300                     else:
    301                         try:
    302                             value = int(value)
    303                         except ValueError:
    304                             done[name] = value.strip()
    305                         else:
    306                             done[name] = value
    307                         variables.remove(name)
    308 
    309                         if name.startswith('PY_') \
    310                         and name[3:] in renamed_variables:
    311 
    312                             name = name[3:]
    313                             if name not in done:
    314                                 done[name] = value
    315 
    316             else:
    317                 # bogus variable reference (e.g. "prefix=$/opt/python");
    318                 # just drop it since we can't deal
    319                 done[name] = value
    320                 variables.remove(name)
    321 
    322     # strip spurious spaces
    323     for k, v in done.items():
    324         if isinstance(v, str):
    325             done[k] = v.strip()
    326 
    327     # save the results in the global dictionary
    328     vars.update(done)
    329     return vars
    330 
    331 
    332 def get_makefile_filename():
    333     """Return the path of the Makefile."""
    334     if _PYTHON_BUILD:
    335         return os.path.join(_sys_home or _PROJECT_BASE, "Makefile")
    336     if hasattr(sys, 'abiflags'):
    337         config_dir_name = 'config-%s%s' % (_PY_VERSION_SHORT, sys.abiflags)
    338     else:
    339         config_dir_name = 'config'
    340     if hasattr(sys.implementation, '_multiarch'):
    341         config_dir_name += '-%s' % sys.implementation._multiarch
    342     return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile')
    343 
    344 
    345 def _get_sysconfigdata_name():
    346     return os.environ.get('_PYTHON_SYSCONFIGDATA_NAME',
    347         '_sysconfigdata_{abi}_{platform}_{multiarch}'.format(
    348         abi=sys.abiflags,
    349         platform=sys.platform,
    350         multiarch=getattr(sys.implementation, '_multiarch', ''),
    351     ))
    352 
    353 
    354 def _generate_posix_vars():
    355     """Generate the Python module containing build-time variables."""
    356     import pprint
    357     vars = {}
    358     # load the installed Makefile:
    359     makefile = get_makefile_filename()
    360     try:
    361         _parse_makefile(makefile, vars)
    362     except OSError as e:
    363         msg = "invalid Python installation: unable to open %s" % makefile
    364         if hasattr(e, "strerror"):
    365             msg = msg + " (%s)" % e.strerror
    366         raise OSError(msg)
    367     # load the installed pyconfig.h:
    368     config_h = get_config_h_filename()
    369     try:
    370         with open(config_h) as f:
    371             parse_config_h(f, vars)
    372     except OSError as e:
    373         msg = "invalid Python installation: unable to open %s" % config_h
    374         if hasattr(e, "strerror"):
    375             msg = msg + " (%s)" % e.strerror
    376         raise OSError(msg)
    377     # On AIX, there are wrong paths to the linker scripts in the Makefile
    378     # -- these paths are relative to the Python source, but when installed
    379     # the scripts are in another directory.
    380     if _PYTHON_BUILD:
    381         vars['BLDSHARED'] = vars['LDSHARED']
    382 
    383     # There's a chicken-and-egg situation on OS X with regards to the
    384     # _sysconfigdata module after the changes introduced by #15298:
    385     # get_config_vars() is called by get_platform() as part of the
    386     # `make pybuilddir.txt` target -- which is a precursor to the
    387     # _sysconfigdata.py module being constructed.  Unfortunately,
    388     # get_config_vars() eventually calls _init_posix(), which attempts
    389     # to import _sysconfigdata, which we won't have built yet.  In order
    390     # for _init_posix() to work, if we're on Darwin, just mock up the
    391     # _sysconfigdata module manually and populate it with the build vars.
    392     # This is more than sufficient for ensuring the subsequent call to
    393     # get_platform() succeeds.
    394     name = _get_sysconfigdata_name()
    395     if 'darwin' in sys.platform:
    396         import types
    397         module = types.ModuleType(name)
    398         module.build_time_vars = vars
    399         sys.modules[name] = module
    400 
    401     pybuilddir = 'build/lib.%s-%s' % (get_platform(), _PY_VERSION_SHORT)
    402     if hasattr(sys, "gettotalrefcount"):
    403         pybuilddir += '-pydebug'
    404     os.makedirs(pybuilddir, exist_ok=True)
    405     destfile = os.path.join(pybuilddir, name + '.py')
    406 
    407     with open(destfile, 'w', encoding='utf8') as f:
    408         f.write('# system configuration generated and used by'
    409                 ' the sysconfig module\n')
    410         f.write('build_time_vars = ')
    411         pprint.pprint(vars, stream=f)
    412 
    413     # Create file used for sys.path fixup -- see Modules/getpath.c
    414     with open('pybuilddir.txt', 'w', encoding='ascii') as f:
    415         f.write(pybuilddir)
    416 
    417 def _init_posix(vars):
    418     """Initialize the module as appropriate for POSIX systems."""
    419     # _sysconfigdata is generated at build time, see _generate_posix_vars()
    420     name = _get_sysconfigdata_name()
    421     _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0)
    422     build_time_vars = _temp.build_time_vars
    423     vars.update(build_time_vars)
    424 
    425 def _init_non_posix(vars):
    426     """Initialize the module as appropriate for NT"""
    427     # set basic install directories
    428     vars['LIBDEST'] = get_path('stdlib')
    429     vars['BINLIBDEST'] = get_path('platstdlib')
    430     vars['INCLUDEPY'] = get_path('include')
    431     vars['EXT_SUFFIX'] = '.pyd'
    432     vars['EXE'] = '.exe'
    433     vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
    434     vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))
    435 
    436 #
    437 # public APIs
    438 #
    439 
    440 
    441 def parse_config_h(fp, vars=None):
    442     """Parse a config.h-style file.
    443 
    444     A dictionary containing name/value pairs is returned.  If an
    445     optional dictionary is passed in as the second argument, it is
    446     used instead of a new dictionary.
    447     """
    448     if vars is None:
    449         vars = {}
    450     import re
    451     define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
    452     undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
    453 
    454     while True:
    455         line = fp.readline()
    456         if not line:
    457             break
    458         m = define_rx.match(line)
    459         if m:
    460             n, v = m.group(1, 2)
    461             try:
    462                 v = int(v)
    463             except ValueError:
    464                 pass
    465             vars[n] = v
    466         else:
    467             m = undef_rx.match(line)
    468             if m:
    469                 vars[m.group(1)] = 0
    470     return vars
    471 
    472 
    473 def get_config_h_filename():
    474     """Return the path of pyconfig.h."""
    475     if _PYTHON_BUILD:
    476         if os.name == "nt":
    477             inc_dir = os.path.join(_sys_home or _PROJECT_BASE, "PC")
    478         else:
    479             inc_dir = _sys_home or _PROJECT_BASE
    480     else:
    481         inc_dir = get_path('platinclude')
    482     return os.path.join(inc_dir, 'pyconfig.h')
    483 
    484 
    485 def get_scheme_names():
    486     """Return a tuple containing the schemes names."""
    487     return tuple(sorted(_INSTALL_SCHEMES))
    488 
    489 
    490 def get_path_names():
    491     """Return a tuple containing the paths names."""
    492     return _SCHEME_KEYS
    493 
    494 
    495 def get_paths(scheme=_get_default_scheme(), vars=None, expand=True):
    496     """Return a mapping containing an install scheme.
    497 
    498     ``scheme`` is the install scheme name. If not provided, it will
    499     return the default scheme for the current platform.
    500     """
    501     if expand:
    502         return _expand_vars(scheme, vars)
    503     else:
    504         return _INSTALL_SCHEMES[scheme]
    505 
    506 
    507 def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True):
    508     """Return a path corresponding to the scheme.
    509 
    510     ``scheme`` is the install scheme name.
    511     """
    512     return get_paths(scheme, vars, expand)[name]
    513 
    514 
    515 def get_config_vars(*args):
    516     """With no arguments, return a dictionary of all configuration
    517     variables relevant for the current platform.
    518 
    519     On Unix, this means every variable defined in Python's installed Makefile;
    520     On Windows it's a much smaller set.
    521 
    522     With arguments, return a list of values that result from looking up
    523     each argument in the configuration variable dictionary.
    524     """
    525     global _CONFIG_VARS
    526     if _CONFIG_VARS is None:
    527         _CONFIG_VARS = {}
    528         # Normalized versions of prefix and exec_prefix are handy to have;
    529         # in fact, these are the standard versions used most places in the
    530         # Distutils.
    531         _CONFIG_VARS['prefix'] = _PREFIX
    532         _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX
    533         _CONFIG_VARS['py_version'] = _PY_VERSION
    534         _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT
    535         _CONFIG_VARS['py_version_nodot'] = _PY_VERSION_SHORT_NO_DOT
    536         _CONFIG_VARS['installed_base'] = _BASE_PREFIX
    537         _CONFIG_VARS['base'] = _PREFIX
    538         _CONFIG_VARS['installed_platbase'] = _BASE_EXEC_PREFIX
    539         _CONFIG_VARS['platbase'] = _EXEC_PREFIX
    540         _CONFIG_VARS['projectbase'] = _PROJECT_BASE
    541         try:
    542             _CONFIG_VARS['abiflags'] = sys.abiflags
    543         except AttributeError:
    544             # sys.abiflags may not be defined on all platforms.
    545             _CONFIG_VARS['abiflags'] = ''
    546 
    547         if os.name == 'nt':
    548             _init_non_posix(_CONFIG_VARS)
    549         if os.name == 'posix':
    550             _init_posix(_CONFIG_VARS)
    551         # For backward compatibility, see issue19555
    552         SO = _CONFIG_VARS.get('EXT_SUFFIX')
    553         if SO is not None:
    554             _CONFIG_VARS['SO'] = SO
    555         # Setting 'userbase' is done below the call to the
    556         # init function to enable using 'get_config_var' in
    557         # the init-function.
    558         _CONFIG_VARS['userbase'] = _getuserbase()
    559 
    560         # Always convert srcdir to an absolute path
    561         srcdir = _CONFIG_VARS.get('srcdir', _PROJECT_BASE)
    562         if os.name == 'posix':
    563             if _PYTHON_BUILD:
    564                 # If srcdir is a relative path (typically '.' or '..')
    565                 # then it should be interpreted relative to the directory
    566                 # containing Makefile.
    567                 base = os.path.dirname(get_makefile_filename())
    568                 srcdir = os.path.join(base, srcdir)
    569             else:
    570                 # srcdir is not meaningful since the installation is
    571                 # spread about the filesystem.  We choose the
    572                 # directory containing the Makefile since we know it
    573                 # exists.
    574                 srcdir = os.path.dirname(get_makefile_filename())
    575         _CONFIG_VARS['srcdir'] = _safe_realpath(srcdir)
    576 
    577         # OS X platforms require special customization to handle
    578         # multi-architecture, multi-os-version installers
    579         if sys.platform == 'darwin':
    580             import _osx_support
    581             _osx_support.customize_config_vars(_CONFIG_VARS)
    582 
    583     if args:
    584         vals = []
    585         for name in args:
    586             vals.append(_CONFIG_VARS.get(name))
    587         return vals
    588     else:
    589         return _CONFIG_VARS
    590 
    591 
    592 def get_config_var(name):
    593     """Return the value of a single variable using the dictionary returned by
    594     'get_config_vars()'.
    595 
    596     Equivalent to get_config_vars().get(name)
    597     """
    598     if name == 'SO':
    599         import warnings
    600         warnings.warn('SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2)
    601     return get_config_vars().get(name)
    602 
    603 
    604 def get_platform():
    605     """Return a string that identifies the current platform.
    606 
    607     This is used mainly to distinguish platform-specific build directories and
    608     platform-specific built distributions.  Typically includes the OS name
    609     and version and the architecture (as supplied by 'os.uname()'),
    610     although the exact information included depends on the OS; eg. for IRIX
    611     the architecture isn't particularly important (IRIX only runs on SGI
    612     hardware), but for Linux the kernel version isn't particularly
    613     important.
    614 
    615     Examples of returned values:
    616        linux-i586
    617        linux-alpha (?)
    618        solaris-2.6-sun4u
    619        irix-5.3
    620        irix64-6.2
    621 
    622     Windows will return one of:
    623        win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
    624        win-ia64 (64bit Windows on Itanium)
    625        win32 (all others - specifically, sys.platform is returned)
    626 
    627     For other non-POSIX platforms, currently just returns 'sys.platform'.
    628     """
    629     if os.name == 'nt':
    630         # sniff sys.version for architecture.
    631         prefix = " bit ("
    632         i = sys.version.find(prefix)
    633         if i == -1:
    634             return sys.platform
    635         j = sys.version.find(")", i)
    636         look = sys.version[i+len(prefix):j].lower()
    637         if look == 'amd64':
    638             return 'win-amd64'
    639         if look == 'itanium':
    640             return 'win-ia64'
    641         return sys.platform
    642 
    643     if os.name != "posix" or not hasattr(os, 'uname'):
    644         # XXX what about the architecture? NT is Intel or Alpha
    645         return sys.platform
    646 
    647     # Set for cross builds explicitly
    648     if "_PYTHON_HOST_PLATFORM" in os.environ:
    649         return os.environ["_PYTHON_HOST_PLATFORM"]
    650 
    651     # Try to distinguish various flavours of Unix
    652     osname, host, release, version, machine = os.uname()
    653 
    654     # Convert the OS name to lowercase, remove '/' characters
    655     # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh")
    656     osname = osname.lower().replace('/', '')
    657     machine = machine.replace(' ', '_')
    658     machine = machine.replace('/', '-')
    659 
    660     if osname[:5] == "linux":
    661         # At least on Linux/Intel, 'machine' is the processor --
    662         # i386, etc.
    663         # XXX what about Alpha, SPARC, etc?
    664         return  "%s-%s" % (osname, machine)
    665     elif osname[:5] == "sunos":
    666         if release[0] >= "5":           # SunOS 5 == Solaris 2
    667             osname = "solaris"
    668             release = "%d.%s" % (int(release[0]) - 3, release[2:])
    669             # We can't use "platform.architecture()[0]" because a
    670             # bootstrap problem. We use a dict to get an error
    671             # if some suspicious happens.
    672             bitness = {2147483647:"32bit", 9223372036854775807:"64bit"}
    673             machine += ".%s" % bitness[sys.maxsize]
    674         # fall through to standard osname-release-machine representation
    675     elif osname[:4] == "irix":              # could be "irix64"!
    676         return "%s-%s" % (osname, release)
    677     elif osname[:3] == "aix":
    678         return "%s-%s.%s" % (osname, version, release)
    679     elif osname[:6] == "cygwin":
    680         osname = "cygwin"
    681         import re
    682         rel_re = re.compile(r'[\d.]+')
    683         m = rel_re.match(release)
    684         if m:
    685             release = m.group()
    686     elif osname[:6] == "darwin":
    687         import _osx_support
    688         osname, release, machine = _osx_support.get_platform_osx(
    689                                             get_config_vars(),
    690                                             osname, release, machine)
    691 
    692     return "%s-%s-%s" % (osname, release, machine)
    693 
    694 
    695 def get_python_version():
    696     return _PY_VERSION_SHORT
    697 
    698 
    699 def _print_dict(title, data):
    700     for index, (key, value) in enumerate(sorted(data.items())):
    701         if index == 0:
    702             print('%s: ' % (title))
    703         print('\t%s = "%s"' % (key, value))
    704 
    705 
    706 def _main():
    707     """Display all information sysconfig detains."""
    708     if '--generate-posix-vars' in sys.argv:
    709         _generate_posix_vars()
    710         return
    711     print('Platform: "%s"' % get_platform())
    712     print('Python version: "%s"' % get_python_version())
    713     print('Current installation scheme: "%s"' % _get_default_scheme())
    714     print()
    715     _print_dict('Paths', get_paths())
    716     print()
    717     _print_dict('Variables', get_config_vars())
    718 
    719 
    720 if __name__ == '__main__':
    721     _main()
    722