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