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