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