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