• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Provide access to Python's configuration information.
2
3"""
4import sys
5import os
6from os.path import pardir, realpath
7
8_INSTALL_SCHEMES = {
9    'posix_prefix': {
10        'stdlib': '{base}/lib/python{py_version_short}',
11        'platstdlib': '{platbase}/lib/python{py_version_short}',
12        'purelib': '{base}/lib/python{py_version_short}/site-packages',
13        'platlib': '{platbase}/lib/python{py_version_short}/site-packages',
14        'include': '{base}/include/python{py_version_short}',
15        'platinclude': '{platbase}/include/python{py_version_short}',
16        'scripts': '{base}/bin',
17        'data': '{base}',
18        },
19    'posix_home': {
20        'stdlib': '{base}/lib/python',
21        'platstdlib': '{base}/lib/python',
22        'purelib': '{base}/lib/python',
23        'platlib': '{base}/lib/python',
24        'include': '{base}/include/python',
25        'platinclude': '{base}/include/python',
26        'scripts': '{base}/bin',
27        'data'   : '{base}',
28        },
29    'nt': {
30        'stdlib': '{base}/Lib',
31        'platstdlib': '{base}/Lib',
32        'purelib': '{base}/Lib/site-packages',
33        'platlib': '{base}/Lib/site-packages',
34        'include': '{base}/Include',
35        'platinclude': '{base}/Include',
36        'scripts': '{base}/Scripts',
37        'data'   : '{base}',
38        },
39    'os2': {
40        'stdlib': '{base}/Lib',
41        'platstdlib': '{base}/Lib',
42        'purelib': '{base}/Lib/site-packages',
43        'platlib': '{base}/Lib/site-packages',
44        'include': '{base}/Include',
45        'platinclude': '{base}/Include',
46        'scripts': '{base}/Scripts',
47        'data'   : '{base}',
48        },
49    'os2_home': {
50        'stdlib': '{userbase}/lib/python{py_version_short}',
51        'platstdlib': '{userbase}/lib/python{py_version_short}',
52        'purelib': '{userbase}/lib/python{py_version_short}/site-packages',
53        'platlib': '{userbase}/lib/python{py_version_short}/site-packages',
54        'include': '{userbase}/include/python{py_version_short}',
55        'scripts': '{userbase}/bin',
56        'data'   : '{userbase}',
57        },
58    'nt_user': {
59        'stdlib': '{userbase}/Python{py_version_nodot}',
60        'platstdlib': '{userbase}/Python{py_version_nodot}',
61        'purelib': '{userbase}/Python{py_version_nodot}/site-packages',
62        'platlib': '{userbase}/Python{py_version_nodot}/site-packages',
63        'include': '{userbase}/Python{py_version_nodot}/Include',
64        'scripts': '{userbase}/Scripts',
65        'data'   : '{userbase}',
66        },
67    'posix_user': {
68        'stdlib': '{userbase}/lib/python{py_version_short}',
69        'platstdlib': '{userbase}/lib/python{py_version_short}',
70        'purelib': '{userbase}/lib/python{py_version_short}/site-packages',
71        'platlib': '{userbase}/lib/python{py_version_short}/site-packages',
72        'include': '{userbase}/include/python{py_version_short}',
73        'scripts': '{userbase}/bin',
74        'data'   : '{userbase}',
75        },
76    'osx_framework_user': {
77        'stdlib': '{userbase}/lib/python',
78        'platstdlib': '{userbase}/lib/python',
79        'purelib': '{userbase}/lib/python/site-packages',
80        'platlib': '{userbase}/lib/python/site-packages',
81        'include': '{userbase}/include',
82        'scripts': '{userbase}/bin',
83        'data'   : '{userbase}',
84        },
85    }
86
87_SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include',
88                'scripts', 'data')
89_PY_VERSION = sys.version.split()[0]
90_PY_VERSION_SHORT = sys.version[:3]
91_PY_VERSION_SHORT_NO_DOT = _PY_VERSION[0] + _PY_VERSION[2]
92_PREFIX = os.path.normpath(sys.prefix)
93_EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
94_CONFIG_VARS = None
95_USER_BASE = None
96
97def _safe_realpath(path):
98    try:
99        return realpath(path)
100    except OSError:
101        return path
102
103if sys.executable:
104    _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable))
105else:
106    # sys.executable can be empty if argv[0] has been changed and Python is
107    # unable to retrieve the real program name
108    _PROJECT_BASE = _safe_realpath(os.getcwd())
109
110if os.name == "nt" and "pcbuild" in _PROJECT_BASE[-8:].lower():
111    _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir))
112# PC/VS7.1
113if os.name == "nt" and "\\pc\\v" in _PROJECT_BASE[-10:].lower():
114    _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
115# PC/AMD64
116if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower():
117    _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
118
119def is_python_build():
120    for fn in ("Setup.dist", "Setup.local"):
121        if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)):
122            return True
123    return False
124
125_PYTHON_BUILD = is_python_build()
126
127if _PYTHON_BUILD:
128    for scheme in ('posix_prefix', 'posix_home'):
129        _INSTALL_SCHEMES[scheme]['include'] = '{projectbase}/Include'
130        _INSTALL_SCHEMES[scheme]['platinclude'] = '{srcdir}'
131
132def _subst_vars(s, local_vars):
133    try:
134        return s.format(**local_vars)
135    except KeyError:
136        try:
137            return s.format(**os.environ)
138        except KeyError, var:
139            raise AttributeError('{%s}' % var)
140
141def _extend_dict(target_dict, other_dict):
142    target_keys = target_dict.keys()
143    for key, value in other_dict.items():
144        if key in target_keys:
145            continue
146        target_dict[key] = value
147
148def _expand_vars(scheme, vars):
149    res = {}
150    if vars is None:
151        vars = {}
152    _extend_dict(vars, get_config_vars())
153
154    for key, value in _INSTALL_SCHEMES[scheme].items():
155        if os.name in ('posix', 'nt'):
156            value = os.path.expanduser(value)
157        res[key] = os.path.normpath(_subst_vars(value, vars))
158    return res
159
160def _get_default_scheme():
161    if os.name == 'posix':
162        # the default scheme for posix is posix_prefix
163        return 'posix_prefix'
164    return os.name
165
166def _getuserbase():
167    env_base = os.environ.get("PYTHONUSERBASE", None)
168    def joinuser(*args):
169        return os.path.expanduser(os.path.join(*args))
170
171    # what about 'os2emx', 'riscos' ?
172    if os.name == "nt":
173        base = os.environ.get("APPDATA") or "~"
174        return env_base if env_base else joinuser(base, "Python")
175
176    if sys.platform == "darwin":
177        framework = get_config_var("PYTHONFRAMEWORK")
178        if framework:
179            return joinuser("~", "Library", framework, "%d.%d"%(
180                sys.version_info[:2]))
181
182    return env_base if env_base else joinuser("~", ".local")
183
184
185def _parse_makefile(filename, vars=None):
186    """Parse a Makefile-style file.
187
188    A dictionary containing name/value pairs is returned.  If an
189    optional dictionary is passed in as the second argument, it is
190    used instead of a new dictionary.
191    """
192    import re
193    # Regexes needed for parsing Makefile (and similar syntaxes,
194    # like old-style Setup files).
195    _variable_rx = re.compile("([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)")
196    _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")
197    _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")
198
199    if vars is None:
200        vars = {}
201    done = {}
202    notdone = {}
203
204    with open(filename) as f:
205        lines = f.readlines()
206
207    for line in lines:
208        if line.startswith('#') or line.strip() == '':
209            continue
210        m = _variable_rx.match(line)
211        if m:
212            n, v = m.group(1, 2)
213            v = v.strip()
214            # `$$' is a literal `$' in make
215            tmpv = v.replace('$$', '')
216
217            if "$" in tmpv:
218                notdone[n] = v
219            else:
220                try:
221                    v = int(v)
222                except ValueError:
223                    # insert literal `$'
224                    done[n] = v.replace('$$', '$')
225                else:
226                    done[n] = v
227
228    # do variable interpolation here
229    while notdone:
230        for name in notdone.keys():
231            value = notdone[name]
232            m = _findvar1_rx.search(value) or _findvar2_rx.search(value)
233            if m:
234                n = m.group(1)
235                found = True
236                if n in done:
237                    item = str(done[n])
238                elif n in notdone:
239                    # get it on a subsequent round
240                    found = False
241                elif n in os.environ:
242                    # do it like make: fall back to environment
243                    item = os.environ[n]
244                else:
245                    done[n] = item = ""
246                if found:
247                    after = value[m.end():]
248                    value = value[:m.start()] + item + after
249                    if "$" in after:
250                        notdone[name] = value
251                    else:
252                        try: value = int(value)
253                        except ValueError:
254                            done[name] = value.strip()
255                        else:
256                            done[name] = value
257                        del notdone[name]
258            else:
259                # bogus variable reference; just drop it since we can't deal
260                del notdone[name]
261    # strip spurious spaces
262    for k, v in done.items():
263        if isinstance(v, str):
264            done[k] = v.strip()
265
266    # save the results in the global dictionary
267    vars.update(done)
268    return vars
269
270
271def _get_makefile_filename():
272    if _PYTHON_BUILD:
273        return os.path.join(_PROJECT_BASE, "Makefile")
274    return os.path.join(get_path('platstdlib'), "config", "Makefile")
275
276
277def _init_posix(vars):
278    """Initialize the module as appropriate for POSIX systems."""
279    # load the installed Makefile:
280    makefile = _get_makefile_filename()
281    try:
282        _parse_makefile(makefile, vars)
283    except IOError, e:
284        msg = "invalid Python installation: unable to open %s" % makefile
285        if hasattr(e, "strerror"):
286            msg = msg + " (%s)" % e.strerror
287        raise IOError(msg)
288
289    # load the installed pyconfig.h:
290    config_h = get_config_h_filename()
291    try:
292        with open(config_h) as f:
293            parse_config_h(f, vars)
294    except IOError, e:
295        msg = "invalid Python installation: unable to open %s" % config_h
296        if hasattr(e, "strerror"):
297            msg = msg + " (%s)" % e.strerror
298        raise IOError(msg)
299
300    # On AIX, there are wrong paths to the linker scripts in the Makefile
301    # -- these paths are relative to the Python source, but when installed
302    # the scripts are in another directory.
303    if _PYTHON_BUILD:
304        vars['LDSHARED'] = vars['BLDSHARED']
305
306def _init_non_posix(vars):
307    """Initialize the module as appropriate for NT"""
308    # set basic install directories
309    vars['LIBDEST'] = get_path('stdlib')
310    vars['BINLIBDEST'] = get_path('platstdlib')
311    vars['INCLUDEPY'] = get_path('include')
312    vars['SO'] = '.pyd'
313    vars['EXE'] = '.exe'
314    vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
315    vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))
316
317#
318# public APIs
319#
320
321
322def parse_config_h(fp, vars=None):
323    """Parse a config.h-style file.
324
325    A dictionary containing name/value pairs is returned.  If an
326    optional dictionary is passed in as the second argument, it is
327    used instead of a new dictionary.
328    """
329    import re
330    if vars is None:
331        vars = {}
332    define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
333    undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
334
335    while True:
336        line = fp.readline()
337        if not line:
338            break
339        m = define_rx.match(line)
340        if m:
341            n, v = m.group(1, 2)
342            try: v = int(v)
343            except ValueError: pass
344            vars[n] = v
345        else:
346            m = undef_rx.match(line)
347            if m:
348                vars[m.group(1)] = 0
349    return vars
350
351def get_config_h_filename():
352    """Returns the path of pyconfig.h."""
353    if _PYTHON_BUILD:
354        if os.name == "nt":
355            inc_dir = os.path.join(_PROJECT_BASE, "PC")
356        else:
357            inc_dir = _PROJECT_BASE
358    else:
359        inc_dir = get_path('platinclude')
360    return os.path.join(inc_dir, 'pyconfig.h')
361
362def get_scheme_names():
363    """Returns a tuple containing the schemes names."""
364    schemes = _INSTALL_SCHEMES.keys()
365    schemes.sort()
366    return tuple(schemes)
367
368def get_path_names():
369    """Returns a tuple containing the paths names."""
370    return _SCHEME_KEYS
371
372def get_paths(scheme=_get_default_scheme(), vars=None, expand=True):
373    """Returns a mapping containing an install scheme.
374
375    ``scheme`` is the install scheme name. If not provided, it will
376    return the default scheme for the current platform.
377    """
378    if expand:
379        return _expand_vars(scheme, vars)
380    else:
381        return _INSTALL_SCHEMES[scheme]
382
383def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True):
384    """Returns a path corresponding to the scheme.
385
386    ``scheme`` is the install scheme name.
387    """
388    return get_paths(scheme, vars, expand)[name]
389
390def get_config_vars(*args):
391    """With no arguments, return a dictionary of all configuration
392    variables relevant for the current platform.
393
394    On Unix, this means every variable defined in Python's installed Makefile;
395    On Windows and Mac OS it's a much smaller set.
396
397    With arguments, return a list of values that result from looking up
398    each argument in the configuration variable dictionary.
399    """
400    import re
401    global _CONFIG_VARS
402    if _CONFIG_VARS is None:
403        _CONFIG_VARS = {}
404        # Normalized versions of prefix and exec_prefix are handy to have;
405        # in fact, these are the standard versions used most places in the
406        # Distutils.
407        _CONFIG_VARS['prefix'] = _PREFIX
408        _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX
409        _CONFIG_VARS['py_version'] = _PY_VERSION
410        _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT
411        _CONFIG_VARS['py_version_nodot'] = _PY_VERSION[0] + _PY_VERSION[2]
412        _CONFIG_VARS['base'] = _PREFIX
413        _CONFIG_VARS['platbase'] = _EXEC_PREFIX
414        _CONFIG_VARS['projectbase'] = _PROJECT_BASE
415
416        if os.name in ('nt', 'os2'):
417            _init_non_posix(_CONFIG_VARS)
418        if os.name == 'posix':
419            _init_posix(_CONFIG_VARS)
420
421        # Setting 'userbase' is done below the call to the
422        # init function to enable using 'get_config_var' in
423        # the init-function.
424        _CONFIG_VARS['userbase'] = _getuserbase()
425
426        if 'srcdir' not in _CONFIG_VARS:
427            _CONFIG_VARS['srcdir'] = _PROJECT_BASE
428
429        # Convert srcdir into an absolute path if it appears necessary.
430        # Normally it is relative to the build directory.  However, during
431        # testing, for example, we might be running a non-installed python
432        # from a different directory.
433        if _PYTHON_BUILD and os.name == "posix":
434            base = _PROJECT_BASE
435            try:
436                cwd = os.getcwd()
437            except OSError:
438                cwd = None
439            if (not os.path.isabs(_CONFIG_VARS['srcdir']) and
440                base != cwd):
441                # srcdir is relative and we are not in the same directory
442                # as the executable. Assume executable is in the build
443                # directory and make srcdir absolute.
444                srcdir = os.path.join(base, _CONFIG_VARS['srcdir'])
445                _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir)
446
447        if sys.platform == 'darwin':
448            kernel_version = os.uname()[2] # Kernel version (8.4.3)
449            major_version = int(kernel_version.split('.')[0])
450
451            if major_version < 8:
452                # On Mac OS X before 10.4, check if -arch and -isysroot
453                # are in CFLAGS or LDFLAGS and remove them if they are.
454                # This is needed when building extensions on a 10.3 system
455                # using a universal build of python.
456                for key in ('LDFLAGS', 'BASECFLAGS',
457                        # a number of derived variables. These need to be
458                        # patched up as well.
459                        'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
460                    flags = _CONFIG_VARS[key]
461                    flags = re.sub('-arch\s+\w+\s', ' ', flags)
462                    flags = re.sub('-isysroot [^ \t]*', ' ', flags)
463                    _CONFIG_VARS[key] = flags
464            else:
465                # Allow the user to override the architecture flags using
466                # an environment variable.
467                # NOTE: This name was introduced by Apple in OSX 10.5 and
468                # is used by several scripting languages distributed with
469                # that OS release.
470                if 'ARCHFLAGS' in os.environ:
471                    arch = os.environ['ARCHFLAGS']
472                    for key in ('LDFLAGS', 'BASECFLAGS',
473                        # a number of derived variables. These need to be
474                        # patched up as well.
475                        'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
476
477                        flags = _CONFIG_VARS[key]
478                        flags = re.sub('-arch\s+\w+\s', ' ', flags)
479                        flags = flags + ' ' + arch
480                        _CONFIG_VARS[key] = flags
481
482                # If we're on OSX 10.5 or later and the user tries to
483                # compiles an extension using an SDK that is not present
484                # on the current machine it is better to not use an SDK
485                # than to fail.
486                #
487                # The major usecase for this is users using a Python.org
488                # binary installer  on OSX 10.6: that installer uses
489                # the 10.4u SDK, but that SDK is not installed by default
490                # when you install Xcode.
491                #
492                CFLAGS = _CONFIG_VARS.get('CFLAGS', '')
493                m = re.search('-isysroot\s+(\S+)', CFLAGS)
494                if m is not None:
495                    sdk = m.group(1)
496                    if not os.path.exists(sdk):
497                        for key in ('LDFLAGS', 'BASECFLAGS',
498                             # a number of derived variables. These need to be
499                             # patched up as well.
500                            'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
501
502                            flags = _CONFIG_VARS[key]
503                            flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags)
504                            _CONFIG_VARS[key] = flags
505
506    if args:
507        vals = []
508        for name in args:
509            vals.append(_CONFIG_VARS.get(name))
510        return vals
511    else:
512        return _CONFIG_VARS
513
514def get_config_var(name):
515    """Return the value of a single variable using the dictionary returned by
516    'get_config_vars()'.
517
518    Equivalent to get_config_vars().get(name)
519    """
520    return get_config_vars().get(name)
521
522def get_platform():
523    """Return a string that identifies the current platform.
524
525    This is used mainly to distinguish platform-specific build directories and
526    platform-specific built distributions.  Typically includes the OS name
527    and version and the architecture (as supplied by 'os.uname()'),
528    although the exact information included depends on the OS; eg. for IRIX
529    the architecture isn't particularly important (IRIX only runs on SGI
530    hardware), but for Linux the kernel version isn't particularly
531    important.
532
533    Examples of returned values:
534       linux-i586
535       linux-alpha (?)
536       solaris-2.6-sun4u
537       irix-5.3
538       irix64-6.2
539
540    Windows will return one of:
541       win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
542       win-ia64 (64bit Windows on Itanium)
543       win32 (all others - specifically, sys.platform is returned)
544
545    For other non-POSIX platforms, currently just returns 'sys.platform'.
546    """
547    import re
548    if os.name == 'nt':
549        # sniff sys.version for architecture.
550        prefix = " bit ("
551        i = sys.version.find(prefix)
552        if i == -1:
553            return sys.platform
554        j = sys.version.find(")", i)
555        look = sys.version[i+len(prefix):j].lower()
556        if look == 'amd64':
557            return 'win-amd64'
558        if look == 'itanium':
559            return 'win-ia64'
560        return sys.platform
561
562    if os.name != "posix" or not hasattr(os, 'uname'):
563        # XXX what about the architecture? NT is Intel or Alpha,
564        # Mac OS is M68k or PPC, etc.
565        return sys.platform
566
567    # Try to distinguish various flavours of Unix
568    osname, host, release, version, machine = os.uname()
569
570    # Convert the OS name to lowercase, remove '/' characters
571    # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh")
572    osname = osname.lower().replace('/', '')
573    machine = machine.replace(' ', '_')
574    machine = machine.replace('/', '-')
575
576    if osname[:5] == "linux":
577        # At least on Linux/Intel, 'machine' is the processor --
578        # i386, etc.
579        # XXX what about Alpha, SPARC, etc?
580        return  "%s-%s" % (osname, machine)
581    elif osname[:5] == "sunos":
582        if release[0] >= "5":           # SunOS 5 == Solaris 2
583            osname = "solaris"
584            release = "%d.%s" % (int(release[0]) - 3, release[2:])
585        # fall through to standard osname-release-machine representation
586    elif osname[:4] == "irix":              # could be "irix64"!
587        return "%s-%s" % (osname, release)
588    elif osname[:3] == "aix":
589        return "%s-%s.%s" % (osname, version, release)
590    elif osname[:6] == "cygwin":
591        osname = "cygwin"
592        rel_re = re.compile (r'[\d.]+')
593        m = rel_re.match(release)
594        if m:
595            release = m.group()
596    elif osname[:6] == "darwin":
597        #
598        # For our purposes, we'll assume that the system version from
599        # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set
600        # to. This makes the compatibility story a bit more sane because the
601        # machine is going to compile and link as if it were
602        # MACOSX_DEPLOYMENT_TARGET.
603        cfgvars = get_config_vars()
604        macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET')
605
606        if 1:
607            # Always calculate the release of the running machine,
608            # needed to determine if we can build fat binaries or not.
609
610            macrelease = macver
611            # Get the system version. Reading this plist is a documented
612            # way to get the system version (see the documentation for
613            # the Gestalt Manager)
614            try:
615                f = open('/System/Library/CoreServices/SystemVersion.plist')
616            except IOError:
617                # We're on a plain darwin box, fall back to the default
618                # behaviour.
619                pass
620            else:
621                try:
622                    m = re.search(
623                            r'<key>ProductUserVisibleVersion</key>\s*' +
624                            r'<string>(.*?)</string>', f.read())
625                    if m is not None:
626                        macrelease = '.'.join(m.group(1).split('.')[:2])
627                    # else: fall back to the default behaviour
628                finally:
629                    f.close()
630
631        if not macver:
632            macver = macrelease
633
634        if macver:
635            release = macver
636            osname = "macosx"
637
638            if (macrelease + '.') >= '10.4.' and \
639                    '-arch' in get_config_vars().get('CFLAGS', '').strip():
640                # The universal build will build fat binaries, but not on
641                # systems before 10.4
642                #
643                # Try to detect 4-way universal builds, those have machine-type
644                # 'universal' instead of 'fat'.
645
646                machine = 'fat'
647                cflags = get_config_vars().get('CFLAGS')
648
649                archs = re.findall('-arch\s+(\S+)', cflags)
650                archs = tuple(sorted(set(archs)))
651
652                if len(archs) == 1:
653                    machine = archs[0]
654                elif archs == ('i386', 'ppc'):
655                    machine = 'fat'
656                elif archs == ('i386', 'x86_64'):
657                    machine = 'intel'
658                elif archs == ('i386', 'ppc', 'x86_64'):
659                    machine = 'fat3'
660                elif archs == ('ppc64', 'x86_64'):
661                    machine = 'fat64'
662                elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'):
663                    machine = 'universal'
664                else:
665                    raise ValueError(
666                       "Don't know machine value for archs=%r"%(archs,))
667
668            elif machine == 'i386':
669                # On OSX the machine type returned by uname is always the
670                # 32-bit variant, even if the executable architecture is
671                # the 64-bit variant
672                if sys.maxint >= 2**32:
673                    machine = 'x86_64'
674
675            elif machine in ('PowerPC', 'Power_Macintosh'):
676                # Pick a sane name for the PPC architecture.
677                # See 'i386' case
678                if sys.maxint >= 2**32:
679                    machine = 'ppc64'
680                else:
681                    machine = 'ppc'
682
683    return "%s-%s-%s" % (osname, release, machine)
684
685
686def get_python_version():
687    return _PY_VERSION_SHORT
688