• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Access to Python's configuration information."""
2
3import os
4import sys
5from 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
99def _safe_realpath(path):
100    try:
101        return realpath(path)
102    except OSError:
103        return path
104
105if sys.executable:
106    _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable))
107else:
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
112if (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
117if "_PYTHON_PROJECT_BASE" in os.environ:
118    _PROJECT_BASE = _safe_realpath(os.environ["_PYTHON_PROJECT_BASE"])
119
120def _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)
127if (_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))
130def 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
137if _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
143def _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
152def _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
160def _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
173def _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
180def _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
208def _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
332def 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
345def _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
354def _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
417def _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
425def _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
441def 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
473def 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
485def get_scheme_names():
486    """Return a tuple containing the schemes names."""
487    return tuple(sorted(_INSTALL_SCHEMES))
488
489
490def get_path_names():
491    """Return a tuple containing the paths names."""
492    return _SCHEME_KEYS
493
494
495def 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
507def 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
515def 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
592def 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
604def 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
695def get_python_version():
696    return _PY_VERSION_SHORT
697
698
699def _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
706def _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
720if __name__ == '__main__':
721    _main()
722