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