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