blob: 69264d2e4811cce71a0cf2a513307f6db4ea7ecd [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
Florent Xicluna85677612010-03-10 23:58:42 +00006from os.path import pardir, realpath
Tarek Ziadé5633a802010-01-23 09:23:15 +00007
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
Florent Xicluna85677612010-03-10 23:58:42 +000087_PROJECT_BASE = os.path.dirname(realpath(sys.executable))
Tarek Ziadé5633a802010-01-23 09:23:15 +000088
89if os.name == "nt" and "pcbuild" in _PROJECT_BASE[-8:].lower():
Florent Xicluna85677612010-03-10 23:58:42 +000090 _PROJECT_BASE = realpath(os.path.join(_PROJECT_BASE, pardir))
Tarek Ziadé5633a802010-01-23 09:23:15 +000091# PC/VS7.1
92if os.name == "nt" and "\\pc\\v" in _PROJECT_BASE[-10:].lower():
Florent Xicluna85677612010-03-10 23:58:42 +000093 _PROJECT_BASE = realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
Tarek Ziadé5633a802010-01-23 09:23:15 +000094# PC/AMD64
95if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower():
Florent Xicluna85677612010-03-10 23:58:42 +000096 _PROJECT_BASE = realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
Tarek Ziadé5633a802010-01-23 09:23:15 +000097
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
Florent Xicluna85677612010-03-10 23:58:42 +0000297 vars['BINDIR'] = os.path.dirname(realpath(sys.executable))
Tarek Ziadé5633a802010-01-23 09:23:15 +0000298
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ée81b0282010-02-02 22:54:28 +0000346 schemes = _INSTALL_SCHEMES.keys()
347 schemes.sort()
348 return tuple(schemes)
Tarek Ziadé5633a802010-01-23 09:23:15 +0000349
350def get_path_names():
Tarek Ziadécc118172010-02-02 22:50:23 +0000351 """Returns a tuple containing the paths names."""
Tarek Ziadé5633a802010-01-23 09:23:15 +0000352 return _SCHEME_KEYS
353
354def get_paths(scheme=_get_default_scheme(), vars=None, expand=True):
355 """Returns a mapping containing an install scheme.
356
357 ``scheme`` is the install scheme name. If not provided, it will
358 return the default scheme for the current platform.
359 """
360 if expand:
361 return _expand_vars(scheme, vars)
362 else:
363 return _INSTALL_SCHEMES[scheme]
364
365def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True):
366 """Returns a path corresponding to the scheme.
367
368 ``scheme`` is the install scheme name.
369 """
370 return get_paths(scheme, vars, expand)[name]
371
372def get_config_vars(*args):
373 """With no arguments, return a dictionary of all configuration
374 variables relevant for the current platform.
375
376 On Unix, this means every variable defined in Python's installed Makefile;
377 On Windows and Mac OS it's a much smaller set.
378
379 With arguments, return a list of values that result from looking up
380 each argument in the configuration variable dictionary.
381 """
382 import re
383 global _CONFIG_VARS
384 if _CONFIG_VARS is None:
385 _CONFIG_VARS = {}
386 # Normalized versions of prefix and exec_prefix are handy to have;
387 # in fact, these are the standard versions used most places in the
388 # Distutils.
389 _CONFIG_VARS['prefix'] = _PREFIX
390 _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX
391 _CONFIG_VARS['py_version'] = _PY_VERSION
392 _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT
393 _CONFIG_VARS['py_version_nodot'] = _PY_VERSION[0] + _PY_VERSION[2]
394 _CONFIG_VARS['base'] = _PREFIX
395 _CONFIG_VARS['platbase'] = _EXEC_PREFIX
396 _CONFIG_VARS['userbase'] = _getuserbase()
397 _CONFIG_VARS['projectbase'] = _PROJECT_BASE
398
399 if os.name in ('nt', 'os2'):
400 _init_non_posix(_CONFIG_VARS)
401 if os.name == 'posix':
402 _init_posix(_CONFIG_VARS)
403
404 if 'srcdir' not in _CONFIG_VARS:
405 _CONFIG_VARS['srcdir'] = _PROJECT_BASE
406
407 # Convert srcdir into an absolute path if it appears necessary.
408 # Normally it is relative to the build directory. However, during
409 # testing, for example, we might be running a non-installed python
410 # from a different directory.
411 if _PYTHON_BUILD and os.name == "posix":
412 base = _PROJECT_BASE
413 if (not os.path.isabs(_CONFIG_VARS['srcdir']) and
414 base != os.getcwd()):
415 # srcdir is relative and we are not in the same directory
416 # as the executable. Assume executable is in the build
417 # directory and make srcdir absolute.
418 srcdir = os.path.join(base, _CONFIG_VARS['srcdir'])
419 _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir)
420
421 if sys.platform == 'darwin':
422 kernel_version = os.uname()[2] # Kernel version (8.4.3)
423 major_version = int(kernel_version.split('.')[0])
424
425 if major_version < 8:
426 # On Mac OS X before 10.4, check if -arch and -isysroot
427 # are in CFLAGS or LDFLAGS and remove them if they are.
428 # This is needed when building extensions on a 10.3 system
429 # using a universal build of python.
430 for key in ('LDFLAGS', 'BASECFLAGS',
431 # a number of derived variables. These need to be
432 # patched up as well.
433 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
434 flags = _CONFIG_VARS[key]
435 flags = re.sub('-arch\s+\w+\s', ' ', flags)
436 flags = re.sub('-isysroot [^ \t]*', ' ', flags)
437 _CONFIG_VARS[key] = flags
438 else:
439 # Allow the user to override the architecture flags using
440 # an environment variable.
441 # NOTE: This name was introduced by Apple in OSX 10.5 and
442 # is used by several scripting languages distributed with
443 # that OS release.
444 if 'ARCHFLAGS' in os.environ:
445 arch = os.environ['ARCHFLAGS']
446 for key in ('LDFLAGS', 'BASECFLAGS',
447 # a number of derived variables. These need to be
448 # patched up as well.
449 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
450
451 flags = _CONFIG_VARS[key]
452 flags = re.sub('-arch\s+\w+\s', ' ', flags)
453 flags = flags + ' ' + arch
454 _CONFIG_VARS[key] = flags
455
456 # If we're on OSX 10.5 or later and the user tries to
457 # compiles an extension using an SDK that is not present
458 # on the current machine it is better to not use an SDK
459 # than to fail.
460 #
461 # The major usecase for this is users using a Python.org
462 # binary installer on OSX 10.6: that installer uses
463 # the 10.4u SDK, but that SDK is not installed by default
464 # when you install Xcode.
465 #
466 CFLAGS = _CONFIG_VARS.get('CFLAGS', '')
467 m = re.search('-isysroot\s+(\S+)', CFLAGS)
468 if m is not None:
469 sdk = m.group(1)
470 if not os.path.exists(sdk):
471 for key in ('LDFLAGS', 'BASECFLAGS',
472 # a number of derived variables. These need to be
473 # patched up as well.
474 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
475
476 flags = _CONFIG_VARS[key]
477 flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags)
478 _CONFIG_VARS[key] = flags
479
480 if args:
481 vals = []
482 for name in args:
483 vals.append(_CONFIG_VARS.get(name))
484 return vals
485 else:
486 return _CONFIG_VARS
487
488def get_config_var(name):
489 """Return the value of a single variable using the dictionary returned by
490 'get_config_vars()'.
491
492 Equivalent to get_config_vars().get(name)
493 """
494 return get_config_vars().get(name)
495
496def get_platform():
497 """Return a string that identifies the current platform.
498
499 This is used mainly to distinguish platform-specific build directories and
500 platform-specific built distributions. Typically includes the OS name
501 and version and the architecture (as supplied by 'os.uname()'),
502 although the exact information included depends on the OS; eg. for IRIX
503 the architecture isn't particularly important (IRIX only runs on SGI
504 hardware), but for Linux the kernel version isn't particularly
505 important.
506
507 Examples of returned values:
508 linux-i586
509 linux-alpha (?)
510 solaris-2.6-sun4u
511 irix-5.3
512 irix64-6.2
513
514 Windows will return one of:
515 win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
516 win-ia64 (64bit Windows on Itanium)
517 win32 (all others - specifically, sys.platform is returned)
518
519 For other non-POSIX platforms, currently just returns 'sys.platform'.
520 """
521 import re
522 if os.name == 'nt':
523 # sniff sys.version for architecture.
524 prefix = " bit ("
525 i = sys.version.find(prefix)
526 if i == -1:
527 return sys.platform
528 j = sys.version.find(")", i)
529 look = sys.version[i+len(prefix):j].lower()
530 if look == 'amd64':
531 return 'win-amd64'
532 if look == 'itanium':
533 return 'win-ia64'
534 return sys.platform
535
536 if os.name != "posix" or not hasattr(os, 'uname'):
537 # XXX what about the architecture? NT is Intel or Alpha,
538 # Mac OS is M68k or PPC, etc.
539 return sys.platform
540
541 # Try to distinguish various flavours of Unix
542 osname, host, release, version, machine = os.uname()
543
544 # Convert the OS name to lowercase, remove '/' characters
545 # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh")
546 osname = osname.lower().replace('/', '')
547 machine = machine.replace(' ', '_')
548 machine = machine.replace('/', '-')
549
550 if osname[:5] == "linux":
551 # At least on Linux/Intel, 'machine' is the processor --
552 # i386, etc.
553 # XXX what about Alpha, SPARC, etc?
554 return "%s-%s" % (osname, machine)
555 elif osname[:5] == "sunos":
556 if release[0] >= "5": # SunOS 5 == Solaris 2
557 osname = "solaris"
558 release = "%d.%s" % (int(release[0]) - 3, release[2:])
559 # fall through to standard osname-release-machine representation
560 elif osname[:4] == "irix": # could be "irix64"!
561 return "%s-%s" % (osname, release)
562 elif osname[:3] == "aix":
563 return "%s-%s.%s" % (osname, version, release)
564 elif osname[:6] == "cygwin":
565 osname = "cygwin"
566 rel_re = re.compile (r'[\d.]+')
567 m = rel_re.match(release)
568 if m:
569 release = m.group()
570 elif osname[:6] == "darwin":
571 #
572 # For our purposes, we'll assume that the system version from
573 # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set
574 # to. This makes the compatibility story a bit more sane because the
575 # machine is going to compile and link as if it were
576 # MACOSX_DEPLOYMENT_TARGET.
577 cfgvars = get_config_vars()
578 macver = os.environ.get('MACOSX_DEPLOYMENT_TARGET')
579 if not macver:
580 macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET')
581
582 if 1:
583 # Always calculate the release of the running machine,
584 # needed to determine if we can build fat binaries or not.
585
586 macrelease = macver
587 # Get the system version. Reading this plist is a documented
588 # way to get the system version (see the documentation for
589 # the Gestalt Manager)
590 try:
591 f = open('/System/Library/CoreServices/SystemVersion.plist')
592 except IOError:
593 # We're on a plain darwin box, fall back to the default
594 # behaviour.
595 pass
596 else:
597 m = re.search(
598 r'<key>ProductUserVisibleVersion</key>\s*' +
599 r'<string>(.*?)</string>', f.read())
600 f.close()
601 if m is not None:
602 macrelease = '.'.join(m.group(1).split('.')[:2])
603 # else: fall back to the default behaviour
604
605 if not macver:
606 macver = macrelease
607
608 if macver:
609 release = macver
610 osname = "macosx"
611
612 if (macrelease + '.') >= '10.4.' and \
613 '-arch' in get_config_vars().get('CFLAGS', '').strip():
614 # The universal build will build fat binaries, but not on
615 # systems before 10.4
616 #
617 # Try to detect 4-way universal builds, those have machine-type
618 # 'universal' instead of 'fat'.
619
620 machine = 'fat'
621 cflags = get_config_vars().get('CFLAGS')
622
623 archs = re.findall('-arch\s+(\S+)', cflags)
624 archs.sort()
625 archs = tuple(archs)
626
627 if len(archs) == 1:
628 machine = archs[0]
629 elif archs == ('i386', 'ppc'):
630 machine = 'fat'
631 elif archs == ('i386', 'x86_64'):
632 machine = 'intel'
633 elif archs == ('i386', 'ppc', 'x86_64'):
634 machine = 'fat3'
635 elif archs == ('ppc64', 'x86_64'):
636 machine = 'fat64'
637 elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'):
638 machine = 'universal'
639 else:
640 raise ValueError(
641 "Don't know machine value for archs=%r"%(archs,))
642
643 elif machine == 'i386':
644 # On OSX the machine type returned by uname is always the
645 # 32-bit variant, even if the executable architecture is
646 # the 64-bit variant
647 if sys.maxint >= 2**32:
648 machine = 'x86_64'
649
650 elif machine in ('PowerPC', 'Power_Macintosh'):
651 # Pick a sane name for the PPC architecture.
652 # See 'i386' case
653 if sys.maxint >= 2**32:
654 machine = 'ppc64'
655 else:
656 machine = 'ppc'
657
658 return "%s-%s-%s" % (osname, release, machine)
659
660
661def get_python_version():
662 return _PY_VERSION_SHORT