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