sysconfig.py 23.6 KB
Newer Older
1
"""Access to Python's configuration information."""
2 3

import os
4 5
import re
import sys
6
from os.path import pardir, realpath
7

8 9 10 11 12 13 14 15 16 17 18 19
__all__ = [
    'get_config_h_filename',
    'get_config_var',
    'get_config_vars',
    'get_makefile_filename',
    'get_path',
    'get_path_names',
    'get_paths',
    'get_platform',
    'get_python_version',
    'get_scheme_names',
    'parse_config_h',
20 21
]

22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
_INSTALL_SCHEMES = {
    'posix_prefix': {
        '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':
            '{installed_base}/include/python{py_version_short}{abiflags}',
        'platinclude':
            '{installed_platbase}/include/python{py_version_short}{abiflags}',
        'scripts': '{base}/bin',
        'data': '{base}',
        },
    'posix_home': {
        'stdlib': '{installed_base}/lib/python',
        'platstdlib': '{base}/lib/python',
        'purelib': '{base}/lib/python',
        'platlib': '{base}/lib/python',
        'include': '{installed_base}/include/python',
        'platinclude': '{installed_base}/include/python',
        'scripts': '{base}/bin',
        'data': '{base}',
        },
    'nt': {
        'stdlib': '{installed_base}/Lib',
        'platstdlib': '{base}/Lib',
        'purelib': '{base}/Lib/site-packages',
        'platlib': '{base}/Lib/site-packages',
        'include': '{installed_base}/Include',
        'platinclude': '{installed_base}/Include',
        'scripts': '{base}/Scripts',
        'data': '{base}',
        },
    'nt_user': {
        'stdlib': '{userbase}/Python{py_version_nodot}',
        'platstdlib': '{userbase}/Python{py_version_nodot}',
        'purelib': '{userbase}/Python{py_version_nodot}/site-packages',
        'platlib': '{userbase}/Python{py_version_nodot}/site-packages',
        'include': '{userbase}/Python{py_version_nodot}/Include',
        'scripts': '{userbase}/Scripts',
        'data': '{userbase}',
        },
    'posix_user': {
        'stdlib': '{userbase}/lib/python{py_version_short}',
        'platstdlib': '{userbase}/lib/python{py_version_short}',
        'purelib': '{userbase}/lib/python{py_version_short}/site-packages',
        'platlib': '{userbase}/lib/python{py_version_short}/site-packages',
        'include': '{userbase}/include/python{py_version_short}',
        'scripts': '{userbase}/bin',
        'data': '{userbase}',
        },
    'osx_framework_user': {
        'stdlib': '{userbase}/lib/python',
        'platstdlib': '{userbase}/lib/python',
        'purelib': '{userbase}/lib/python/site-packages',
        'platlib': '{userbase}/lib/python/site-packages',
        'include': '{userbase}/include',
        'scripts': '{userbase}/bin',
        'data': '{userbase}',
        },
    }

_SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include',
                'scripts', 'data')
86

87
 # FIXME don't rely on sys.version here, its format is an implementation detail
88
 # of CPython, use sys.version_info or sys.hexversion
89 90 91 92
_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)
93
_BASE_PREFIX = os.path.normpath(sys.base_prefix)
94
_EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
95
_BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix)
96 97
_CONFIG_VARS = None
_USER_BASE = None
98

99

100 101 102 103 104 105
def _safe_realpath(path):
    try:
        return realpath(path)
    except OSError:
        return path

106
if sys.executable:
107
    _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable))
108 109 110
else:
    # sys.executable can be empty if argv[0] has been changed and Python is
    # unable to retrieve the real program name
111
    _PROJECT_BASE = _safe_realpath(os.getcwd())
112 113

if os.name == "nt" and "pcbuild" in _PROJECT_BASE[-8:].lower():
114
    _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir))
115 116
# PC/VS7.1
if os.name == "nt" and "\\pc\\v" in _PROJECT_BASE[-10:].lower():
117
    _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
118 119
# PC/AMD64
if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower():
120
    _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
121

122
# set for cross builds
123 124
if "_PYTHON_PROJECT_BASE" in os.environ:
    _PROJECT_BASE = _safe_realpath(os.environ["_PYTHON_PROJECT_BASE"])
125

126
def _is_python_source_dir(d):
127
    for fn in ("Setup.dist", "Setup.local"):
128
        if os.path.isfile(os.path.join(d, "Modules", fn)):
129 130 131
            return True
    return False

132
_sys_home = getattr(sys, '_home', None)
133 134
if _sys_home and os.name == 'nt' and \
    _sys_home.lower().endswith(('pcbuild', 'pcbuild\\amd64')):
135
    _sys_home = os.path.dirname(_sys_home)
136 137
    if _sys_home.endswith('pcbuild'):   # must be amd64
        _sys_home = os.path.dirname(_sys_home)
138 139 140 141 142 143
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)
144 145 146

if _PYTHON_BUILD:
    for scheme in ('posix_prefix', 'posix_home'):
147 148
        _INSTALL_SCHEMES[scheme]['include'] = '{srcdir}/Include'
        _INSTALL_SCHEMES[scheme]['platinclude'] = '{projectbase}/.'
149

150

151 152 153 154 155 156 157 158
def _subst_vars(s, local_vars):
    try:
        return s.format(**local_vars)
    except KeyError:
        try:
            return s.format(**os.environ)
        except KeyError as var:
            raise AttributeError('{%s}' % var)
159 160 161 162 163 164 165 166

def _extend_dict(target_dict, other_dict):
    target_keys = target_dict.keys()
    for key, value in other_dict.items():
        if key in target_keys:
            continue
        target_dict[key] = value

167

168 169 170 171 172 173
def _expand_vars(scheme, vars):
    res = {}
    if vars is None:
        vars = {}
    _extend_dict(vars, get_config_vars())

174
    for key, value in _INSTALL_SCHEMES[scheme].items():
175 176 177 178 179
        if os.name in ('posix', 'nt'):
            value = os.path.expanduser(value)
        res[key] = os.path.normpath(_subst_vars(value, vars))
    return res

180

181 182 183 184 185 186
def _get_default_scheme():
    if os.name == 'posix':
        # the default scheme for posix is posix_prefix
        return 'posix_prefix'
    return os.name

187

188 189
def _getuserbase():
    env_base = os.environ.get("PYTHONUSERBASE", None)
190

191 192 193 194 195
    def joinuser(*args):
        return os.path.expanduser(os.path.join(*args))

    if os.name == "nt":
        base = os.environ.get("APPDATA") or "~"
196 197 198 199
        if env_base:
            return env_base
        else:
            return joinuser(base, "Python")
200

201 202 203
    if sys.platform == "darwin":
        framework = get_config_var("PYTHONFRAMEWORK")
        if framework:
204 205 206 207 208
            if env_base:
                return env_base
            else:
                return joinuser("~", "Library", framework, "%d.%d" %
                                sys.version_info[:2])
209

210 211 212 213
    if env_base:
        return env_base
    else:
        return joinuser("~", ".local")
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233


def _parse_makefile(filename, vars=None):
    """Parse a Makefile-style file.

    A dictionary containing name/value pairs is returned.  If an
    optional dictionary is passed in as the second argument, it is
    used instead of a new dictionary.
    """
    # 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*(.*)")
    _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")
    _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")

    if vars is None:
        vars = {}
    done = {}
    notdone = {}

234
    with open(filename, errors="surrogateescape") as f:
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
        lines = f.readlines()

    for line in lines:
        if line.startswith('#') or line.strip() == '':
            continue
        m = _variable_rx.match(line)
        if m:
            n, v = m.group(1, 2)
            v = v.strip()
            # `$$' is a literal `$' in make
            tmpv = v.replace('$$', '')

            if "$" in tmpv:
                notdone[n] = v
            else:
                try:
                    v = int(v)
                except ValueError:
                    # insert literal `$'
                    done[n] = v.replace('$$', '$')
                else:
                    done[n] = v

    # do variable interpolation here
    variables = list(notdone.keys())

261 262 263 264 265 266
    # Variables with a 'PY_' prefix in the makefile. These need to
    # be made available without that prefix through sysconfig.
    # Special care is needed to ensure that variable expansion works, even
    # if the expansion uses the name without a prefix.
    renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')

267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
    while len(variables) > 0:
        for name in tuple(variables):
            value = notdone[name]
            m = _findvar1_rx.search(value) or _findvar2_rx.search(value)
            if m is not None:
                n = m.group(1)
                found = True
                if n in done:
                    item = str(done[n])
                elif n in notdone:
                    # get it on a subsequent round
                    found = False
                elif n in os.environ:
                    # do it like make: fall back to environment
                    item = os.environ[n]
282 283

                elif n in renamed_variables:
284 285
                    if (name.startswith('PY_') and
                        name[3:] in renamed_variables):
286 287 288 289 290 291 292 293
                        item = ""

                    elif 'PY_' + n in notdone:
                        found = False

                    else:
                        item = str(done['PY_' + n])

294 295
                else:
                    done[n] = item = ""
296

297 298 299 300 301 302 303 304 305 306 307 308 309
                if found:
                    after = value[m.end():]
                    value = value[:m.start()] + item + after
                    if "$" in after:
                        notdone[name] = value
                    else:
                        try:
                            value = int(value)
                        except ValueError:
                            done[name] = value.strip()
                        else:
                            done[name] = value
                        variables.remove(name)
310 311

                        if name.startswith('PY_') \
312
                        and name[3:] in renamed_variables:
313 314 315 316 317

                            name = name[3:]
                            if name not in done:
                                done[name] = value

318
            else:
319 320 321
                # bogus variable reference (e.g. "prefix=$/opt/python");
                # just drop it since we can't deal
                done[name] = value
322 323
                variables.remove(name)

324 325 326 327 328
    # strip spurious spaces
    for k, v in done.items():
        if isinstance(v, str):
            done[k] = v.strip()

329 330 331 332 333
    # save the results in the global dictionary
    vars.update(done)
    return vars


334
def get_makefile_filename():
335
    """Return the path of the Makefile."""
336
    if _PYTHON_BUILD:
337
        return os.path.join(_sys_home or _PROJECT_BASE, "Makefile")
338 339 340 341 342
    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')
343

344 345 346 347
def _generate_posix_vars():
    """Generate the Python module containing build-time variables."""
    import pprint
    vars = {}
348
    # load the installed Makefile:
349
    makefile = get_makefile_filename()
350 351
    try:
        _parse_makefile(makefile, vars)
352
    except OSError as e:
353 354 355
        msg = "invalid Python installation: unable to open %s" % makefile
        if hasattr(e, "strerror"):
            msg = msg + " (%s)" % e.strerror
356
        raise OSError(msg)
357 358 359
    # load the installed pyconfig.h:
    config_h = get_config_h_filename()
    try:
360 361
        with open(config_h) as f:
            parse_config_h(f, vars)
362
    except OSError as e:
363 364 365
        msg = "invalid Python installation: unable to open %s" % config_h
        if hasattr(e, "strerror"):
            msg = msg + " (%s)" % e.strerror
366
        raise OSError(msg)
367 368 369 370 371
    # On AIX, there are wrong paths to the linker scripts in the Makefile
    # -- these paths are relative to the Python source, but when installed
    # the scripts are in another directory.
    if _PYTHON_BUILD:
        vars['LDSHARED'] = vars['BLDSHARED']
372

373 374 375 376 377 378
    # There's a chicken-and-egg situation on OS X with regards to the
    # _sysconfigdata module after the changes introduced by #15298:
    # get_config_vars() is called by get_platform() as part of the
    # `make pybuilddir.txt` target -- which is a precursor to the
    # _sysconfigdata.py module being constructed.  Unfortunately,
    # get_config_vars() eventually calls _init_posix(), which attempts
379 380 381 382 383 384 385
    # to import _sysconfigdata, which we won't have built yet.  In order
    # for _init_posix() to work, if we're on Darwin, just mock up the
    # _sysconfigdata module manually and populate it with the build vars.
    # This is more than sufficient for ensuring the subsequent call to
    # get_platform() succeeds.
    name = '_sysconfigdata'
    if 'darwin' in sys.platform:
386 387
        import types
        module = types.ModuleType(name)
388 389
        module.build_time_vars = vars
        sys.modules[name] = module
390

391 392 393 394
    pybuilddir = 'build/lib.%s-%s' % (get_platform(), sys.version[:3])
    if hasattr(sys, "gettotalrefcount"):
        pybuilddir += '-pydebug'
    os.makedirs(pybuilddir, exist_ok=True)
395
    destfile = os.path.join(pybuilddir, name + '.py')
396

397 398 399 400 401
    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)
402

403 404 405 406
    # Create file used for sys.path fixup -- see Modules/getpath.c
    with open('pybuilddir.txt', 'w', encoding='ascii') as f:
        f.write(pybuilddir)

407 408 409 410 411
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)
412

413 414 415 416 417 418
def _init_non_posix(vars):
    """Initialize the module as appropriate for NT"""
    # set basic install directories
    vars['LIBDEST'] = get_path('stdlib')
    vars['BINLIBDEST'] = get_path('platstdlib')
    vars['INCLUDEPY'] = get_path('include')
419
    vars['EXT_SUFFIX'] = '.pyd'
420 421
    vars['EXE'] = '.exe'
    vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
422
    vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))
423 424 425 426 427

#
# public APIs
#

428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447

def parse_config_h(fp, vars=None):
    """Parse a config.h-style file.

    A dictionary containing name/value pairs is returned.  If an
    optional dictionary is passed in as the second argument, it is
    used instead of a new dictionary.
    """
    if vars is None:
        vars = {}
    define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
    undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")

    while True:
        line = fp.readline()
        if not line:
            break
        m = define_rx.match(line)
        if m:
            n, v = m.group(1, 2)
448 449 450 451
            try:
                v = int(v)
            except ValueError:
                pass
452 453 454 455 456 457 458
            vars[n] = v
        else:
            m = undef_rx.match(line)
            if m:
                vars[m.group(1)] = 0
    return vars

459

460
def get_config_h_filename():
461
    """Return the path of pyconfig.h."""
462 463
    if _PYTHON_BUILD:
        if os.name == "nt":
464
            inc_dir = os.path.join(_sys_home or _PROJECT_BASE, "PC")
465
        else:
466
            inc_dir = _sys_home or _PROJECT_BASE
467 468 469 470
    else:
        inc_dir = get_path('platinclude')
    return os.path.join(inc_dir, 'pyconfig.h')

471

472
def get_scheme_names():
473
    """Return a tuple containing the schemes names."""
474
    return tuple(sorted(_INSTALL_SCHEMES))
475

476 477

def get_path_names():
478
    """Return a tuple containing the paths names."""
479
    return _SCHEME_KEYS
480

481 482

def get_paths(scheme=_get_default_scheme(), vars=None, expand=True):
483
    """Return a mapping containing an install scheme.
484 485 486 487 488 489 490

    ``scheme`` is the install scheme name. If not provided, it will
    return the default scheme for the current platform.
    """
    if expand:
        return _expand_vars(scheme, vars)
    else:
491
        return _INSTALL_SCHEMES[scheme]
492

493 494

def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True):
495
    """Return a path corresponding to the scheme.
496 497 498 499 500

    ``scheme`` is the install scheme name.
    """
    return get_paths(scheme, vars, expand)[name]

501

502 503 504 505 506
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;
507
    On Windows it's a much smaller set.
508 509 510 511 512 513 514 515 516

    With arguments, return a list of values that result from looking up
    each argument in the configuration variable dictionary.
    """
    global _CONFIG_VARS
    if _CONFIG_VARS is None:
        _CONFIG_VARS = {}
        # Normalized versions of prefix and exec_prefix are handy to have;
        # in fact, these are the standard versions used most places in the
517
        # Distutils.
518 519 520 521 522
        _CONFIG_VARS['prefix'] = _PREFIX
        _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX
        _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]
523
        _CONFIG_VARS['installed_base'] = _BASE_PREFIX
524
        _CONFIG_VARS['base'] = _PREFIX
525
        _CONFIG_VARS['installed_platbase'] = _BASE_EXEC_PREFIX
526 527
        _CONFIG_VARS['platbase'] = _EXEC_PREFIX
        _CONFIG_VARS['projectbase'] = _PROJECT_BASE
528 529 530 531 532
        try:
            _CONFIG_VARS['abiflags'] = sys.abiflags
        except AttributeError:
            # sys.abiflags may not be defined on all platforms.
            _CONFIG_VARS['abiflags'] = ''
533

534
        if os.name == 'nt':
535 536 537
            _init_non_posix(_CONFIG_VARS)
        if os.name == 'posix':
            _init_posix(_CONFIG_VARS)
538 539 540
        # Setting 'userbase' is done below the call to the
        # init function to enable using 'get_config_var' in
        # the init-function.
541
        _CONFIG_VARS['userbase'] = _getuserbase()
542

543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
        # 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:
                # 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)
559

560 561
        # OS X platforms require special customization to handle
        # multi-architecture, multi-os-version installers
562
        if sys.platform == 'darwin':
563 564
            import _osx_support
            _osx_support.customize_config_vars(_CONFIG_VARS)
565 566 567 568 569 570 571 572 573

    if args:
        vals = []
        for name in args:
            vals.append(_CONFIG_VARS.get(name))
        return vals
    else:
        return _CONFIG_VARS

574

575 576 577 578 579 580 581 582
def get_config_var(name):
    """Return the value of a single variable using the dictionary returned by
    'get_config_vars()'.

    Equivalent to get_config_vars().get(name)
    """
    return get_config_vars().get(name)

583

584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
def get_platform():
    """Return a string that identifies the current platform.

    This is used mainly to distinguish platform-specific build directories and
    platform-specific built distributions.  Typically includes the OS name
    and version and the architecture (as supplied by 'os.uname()'),
    although the exact information included depends on the OS; eg. for IRIX
    the architecture isn't particularly important (IRIX only runs on SGI
    hardware), but for Linux the kernel version isn't particularly
    important.

    Examples of returned values:
       linux-i586
       linux-alpha (?)
       solaris-2.6-sun4u
       irix-5.3
       irix64-6.2

    Windows will return one of:
       win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
       win-ia64 (64bit Windows on Itanium)
       win32 (all others - specifically, sys.platform is returned)

    For other non-POSIX platforms, currently just returns 'sys.platform'.
    """
    if os.name == 'nt':
        # sniff sys.version for architecture.
        prefix = " bit ("
        i = sys.version.find(prefix)
        if i == -1:
            return sys.platform
        j = sys.version.find(")", i)
        look = sys.version[i+len(prefix):j].lower()
        if look == 'amd64':
            return 'win-amd64'
        if look == 'itanium':
            return 'win-ia64'
        return sys.platform

    if os.name != "posix" or not hasattr(os, 'uname'):
624
        # XXX what about the architecture? NT is Intel or Alpha
625 626
        return sys.platform

627 628 629 630
    # Set for cross builds explicitly
    if "_PYTHON_HOST_PLATFORM" in os.environ:
        return os.environ["_PYTHON_HOST_PLATFORM"]

631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648
    # Try to distinguish various flavours of Unix
    osname, host, release, version, machine = os.uname()

    # Convert the OS name to lowercase, remove '/' characters
    # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh")
    osname = osname.lower().replace('/', '')
    machine = machine.replace(' ', '_')
    machine = machine.replace('/', '-')

    if osname[:5] == "linux":
        # At least on Linux/Intel, 'machine' is the processor --
        # i386, etc.
        # XXX what about Alpha, SPARC, etc?
        return  "%s-%s" % (osname, machine)
    elif osname[:5] == "sunos":
        if release[0] >= "5":           # SunOS 5 == Solaris 2
            osname = "solaris"
            release = "%d.%s" % (int(release[0]) - 3, release[2:])
649 650 651 652
            # We can't use "platform.architecture()[0]" because a
            # bootstrap problem. We use a dict to get an error
            # if some suspicious happens.
            bitness = {2147483647:"32bit", 9223372036854775807:"64bit"}
653
            machine += ".%s" % bitness[sys.maxsize]
654 655 656 657 658 659 660
        # fall through to standard osname-release-machine representation
    elif osname[:4] == "irix":              # could be "irix64"!
        return "%s-%s" % (osname, release)
    elif osname[:3] == "aix":
        return "%s-%s.%s" % (osname, version, release)
    elif osname[:6] == "cygwin":
        osname = "cygwin"
661
        rel_re = re.compile(r'[\d.]+')
662 663 664 665
        m = rel_re.match(release)
        if m:
            release = m.group()
    elif osname[:6] == "darwin":
666 667 668 669
        import _osx_support
        osname, release, machine = _osx_support.get_platform_osx(
                                            get_config_vars(),
                                            osname, release, machine)
670 671 672 673 674 675

    return "%s-%s-%s" % (osname, release, machine)


def get_python_version():
    return _PY_VERSION_SHORT
676

677

678 679 680
def _print_dict(title, data):
    for index, (key, value) in enumerate(sorted(data.items())):
        if index == 0:
681 682 683
            print('%s: ' % (title))
        print('\t%s = "%s"' % (key, value))

684 685

def _main():
686
    """Display all information sysconfig detains."""
687 688 689
    if '--generate-posix-vars' in sys.argv:
        _generate_posix_vars()
        return
690 691 692
    print('Platform: "%s"' % get_platform())
    print('Python version: "%s"' % get_python_version())
    print('Current installation scheme: "%s"' % _get_default_scheme())
693
    print()
694
    _print_dict('Paths', get_paths())
695
    print()
696 697
    _print_dict('Variables', get_config_vars())

698

699 700
if __name__ == '__main__':
    _main()