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