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