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