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