blob: b2183d8e67fbd95444edbdb98dc507b5efc31510 [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',
Barry Warsaw14d98ac2010-11-24 19:43:47 +000028 'include':
29 '{base}/include/python{py_version_short}{abiflags}',
30 'platinclude':
31 '{platbase}/include/python{py_version_short}{abiflags}',
Tarek Ziadéedacea32010-01-29 11:41:03 +000032 'scripts': '{base}/bin',
33 'data': '{base}',
34 },
35 'posix_home': {
36 'stdlib': '{base}/lib/python',
37 'platstdlib': '{base}/lib/python',
38 'purelib': '{base}/lib/python',
39 'platlib': '{base}/lib/python',
40 'include': '{base}/include/python',
41 'platinclude': '{base}/include/python',
42 'scripts': '{base}/bin',
43 'data' : '{base}',
44 },
45 'nt': {
46 'stdlib': '{base}/Lib',
47 'platstdlib': '{base}/Lib',
48 'purelib': '{base}/Lib/site-packages',
49 'platlib': '{base}/Lib/site-packages',
50 'include': '{base}/Include',
51 'platinclude': '{base}/Include',
52 'scripts': '{base}/Scripts',
53 'data' : '{base}',
54 },
55 'os2': {
56 'stdlib': '{base}/Lib',
57 'platstdlib': '{base}/Lib',
58 'purelib': '{base}/Lib/site-packages',
59 'platlib': '{base}/Lib/site-packages',
60 'include': '{base}/Include',
61 'platinclude': '{base}/Include',
62 'scripts': '{base}/Scripts',
63 'data' : '{base}',
64 },
65 'os2_home': {
Tarek Ziadé06710a82010-05-19 22:25:00 +000066 'stdlib': '{userbase}/lib/python{py_version_short}',
67 'platstdlib': '{userbase}/lib/python{py_version_short}',
68 'purelib': '{userbase}/lib/python{py_version_short}/site-packages',
69 'platlib': '{userbase}/lib/python{py_version_short}/site-packages',
Tarek Ziadéedacea32010-01-29 11:41:03 +000070 'include': '{userbase}/include/python{py_version_short}',
71 'scripts': '{userbase}/bin',
72 'data' : '{userbase}',
73 },
74 'nt_user': {
75 'stdlib': '{userbase}/Python{py_version_nodot}',
76 'platstdlib': '{userbase}/Python{py_version_nodot}',
77 'purelib': '{userbase}/Python{py_version_nodot}/site-packages',
78 'platlib': '{userbase}/Python{py_version_nodot}/site-packages',
79 'include': '{userbase}/Python{py_version_nodot}/Include',
80 'scripts': '{userbase}/Scripts',
81 'data' : '{userbase}',
82 },
83 'posix_user': {
Tarek Ziadé06710a82010-05-19 22:25:00 +000084 'stdlib': '{userbase}/lib/python{py_version_short}',
85 'platstdlib': '{userbase}/lib/python{py_version_short}',
86 'purelib': '{userbase}/lib/python{py_version_short}/site-packages',
87 'platlib': '{userbase}/lib/python{py_version_short}/site-packages',
Tarek Ziadéedacea32010-01-29 11:41:03 +000088 'include': '{userbase}/include/python{py_version_short}',
89 'scripts': '{userbase}/bin',
90 'data' : '{userbase}',
91 },
Ronald Oussoren4cda46a2010-05-08 10:49:43 +000092 'osx_framework_user': {
93 'stdlib': '{userbase}/lib/python',
94 'platstdlib': '{userbase}/lib/python',
95 'purelib': '{userbase}/lib/python/site-packages',
96 'platlib': '{userbase}/lib/python/site-packages',
97 'include': '{userbase}/include',
98 'scripts': '{userbase}/bin',
99 'data' : '{userbase}',
100 },
Tarek Ziadéedacea32010-01-29 11:41:03 +0000101 }
102
103_SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include',
104 'scripts', 'data')
105_PY_VERSION = sys.version.split()[0]
106_PY_VERSION_SHORT = sys.version[:3]
107_PY_VERSION_SHORT_NO_DOT = _PY_VERSION[0] + _PY_VERSION[2]
108_PREFIX = os.path.normpath(sys.prefix)
109_EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
110_CONFIG_VARS = None
111_USER_BASE = None
Victor Stinnerb103a932010-10-12 22:23:23 +0000112
113def _safe_realpath(path):
114 try:
115 return realpath(path)
116 except OSError:
117 return path
118
Victor Stinner171ba052010-03-12 14:20:59 +0000119if sys.executable:
Victor Stinnerb103a932010-10-12 22:23:23 +0000120 _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable))
Victor Stinner171ba052010-03-12 14:20:59 +0000121else:
122 # sys.executable can be empty if argv[0] has been changed and Python is
123 # unable to retrieve the real program name
Victor Stinnerb103a932010-10-12 22:23:23 +0000124 _PROJECT_BASE = _safe_realpath(os.getcwd())
Tarek Ziadéedacea32010-01-29 11:41:03 +0000125
126if os.name == "nt" and "pcbuild" in _PROJECT_BASE[-8:].lower():
Victor Stinnerb103a932010-10-12 22:23:23 +0000127 _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000128# PC/VS7.1
129if os.name == "nt" and "\\pc\\v" in _PROJECT_BASE[-10:].lower():
Victor Stinnerb103a932010-10-12 22:23:23 +0000130 _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000131# PC/AMD64
132if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower():
Victor Stinnerb103a932010-10-12 22:23:23 +0000133 _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000134
135def is_python_build():
136 for fn in ("Setup.dist", "Setup.local"):
137 if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)):
138 return True
139 return False
140
141_PYTHON_BUILD = is_python_build()
142
143if _PYTHON_BUILD:
144 for scheme in ('posix_prefix', 'posix_home'):
Vinay Sajipae7d7fa2010-09-20 10:29:54 +0000145 _INSTALL_SCHEMES[scheme]['include'] = '{srcdir}/Include'
Ronald Oussorene41a19e2010-06-15 16:05:20 +0000146 _INSTALL_SCHEMES[scheme]['platinclude'] = '{projectbase}/.'
Tarek Ziadéedacea32010-01-29 11:41:03 +0000147
148def _subst_vars(s, local_vars):
149 try:
150 return s.format(**local_vars)
151 except KeyError:
152 try:
153 return s.format(**os.environ)
154 except KeyError as var:
155 raise AttributeError('{%s}' % var)
156
157def _extend_dict(target_dict, other_dict):
158 target_keys = target_dict.keys()
159 for key, value in other_dict.items():
160 if key in target_keys:
161 continue
162 target_dict[key] = value
163
164def _expand_vars(scheme, vars):
165 res = {}
166 if vars is None:
167 vars = {}
168 _extend_dict(vars, get_config_vars())
169
170 for key, value in _INSTALL_SCHEMES[scheme].items():
171 if os.name in ('posix', 'nt'):
172 value = os.path.expanduser(value)
173 res[key] = os.path.normpath(_subst_vars(value, vars))
174 return res
175
176def _get_default_scheme():
177 if os.name == 'posix':
178 # the default scheme for posix is posix_prefix
179 return 'posix_prefix'
180 return os.name
181
182def _getuserbase():
183 env_base = os.environ.get("PYTHONUSERBASE", None)
184 def joinuser(*args):
185 return os.path.expanduser(os.path.join(*args))
186
187 # what about 'os2emx', 'riscos' ?
188 if os.name == "nt":
189 base = os.environ.get("APPDATA") or "~"
190 return env_base if env_base else joinuser(base, "Python")
191
Ronald Oussoren4cda46a2010-05-08 10:49:43 +0000192 if sys.platform == "darwin":
193 framework = get_config_var("PYTHONFRAMEWORK")
194 if framework:
Ronald Oussorenbda46722010-08-01 09:02:50 +0000195 return env_base if env_base else joinuser("~", "Library", framework, "%d.%d"%(
Ronald Oussoren4cda46a2010-05-08 10:49:43 +0000196 sys.version_info[:2]))
197
Tarek Ziadéedacea32010-01-29 11:41:03 +0000198 return env_base if env_base else joinuser("~", ".local")
199
200
201def _parse_makefile(filename, vars=None):
202 """Parse a Makefile-style file.
203
204 A dictionary containing name/value pairs is returned. If an
205 optional dictionary is passed in as the second argument, it is
206 used instead of a new dictionary.
207 """
208 import re
209 # Regexes needed for parsing Makefile (and similar syntaxes,
210 # like old-style Setup files).
211 _variable_rx = re.compile("([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)")
212 _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")
213 _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")
214
215 if vars is None:
216 vars = {}
217 done = {}
218 notdone = {}
219
Victor Stinner75d8c5c2010-10-23 17:02:31 +0000220 with open(filename, errors="surrogateescape") as f:
Tarek Ziadéedacea32010-01-29 11:41:03 +0000221 lines = f.readlines()
222
223 for line in lines:
224 if line.startswith('#') or line.strip() == '':
225 continue
226 m = _variable_rx.match(line)
227 if m:
228 n, v = m.group(1, 2)
229 v = v.strip()
230 # `$$' is a literal `$' in make
231 tmpv = v.replace('$$', '')
232
233 if "$" in tmpv:
234 notdone[n] = v
235 else:
236 try:
237 v = int(v)
238 except ValueError:
239 # insert literal `$'
240 done[n] = v.replace('$$', '$')
241 else:
242 done[n] = v
243
244 # do variable interpolation here
245 variables = list(notdone.keys())
246
Ronald Oussorend21886c2010-07-20 16:07:10 +0000247 # Variables with a 'PY_' prefix in the makefile. These need to
248 # be made available without that prefix through sysconfig.
249 # Special care is needed to ensure that variable expansion works, even
250 # if the expansion uses the name without a prefix.
251 renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')
252
Tarek Ziadéedacea32010-01-29 11:41:03 +0000253 while len(variables) > 0:
254 for name in tuple(variables):
255 value = notdone[name]
256 m = _findvar1_rx.search(value) or _findvar2_rx.search(value)
257 if m is not None:
258 n = m.group(1)
259 found = True
260 if n in done:
261 item = str(done[n])
262 elif n in notdone:
263 # get it on a subsequent round
264 found = False
265 elif n in os.environ:
266 # do it like make: fall back to environment
267 item = os.environ[n]
Ronald Oussorend21886c2010-07-20 16:07:10 +0000268
269 elif n in renamed_variables:
270 if name.startswith('PY_') and name[3:] in renamed_variables:
271 item = ""
272
273 elif 'PY_' + n in notdone:
274 found = False
275
276 else:
277 item = str(done['PY_' + n])
278
Tarek Ziadéedacea32010-01-29 11:41:03 +0000279 else:
280 done[n] = item = ""
Ronald Oussorend21886c2010-07-20 16:07:10 +0000281
Tarek Ziadéedacea32010-01-29 11:41:03 +0000282 if found:
283 after = value[m.end():]
284 value = value[:m.start()] + item + after
285 if "$" in after:
286 notdone[name] = value
287 else:
288 try:
289 value = int(value)
290 except ValueError:
291 done[name] = value.strip()
292 else:
293 done[name] = value
294 variables.remove(name)
Ronald Oussorend21886c2010-07-20 16:07:10 +0000295
296 if name.startswith('PY_') \
Victor Stinner1273b7c2011-05-24 23:37:07 +0200297 and name[3:] in renamed_variables:
Ronald Oussorend21886c2010-07-20 16:07:10 +0000298
299 name = name[3:]
300 if name not in done:
301 done[name] = value
302
303
Tarek Ziadéedacea32010-01-29 11:41:03 +0000304 else:
Victor Stinner1273b7c2011-05-24 23:37:07 +0200305 # bogus variable reference (e.g. "prefix=$/opt/python");
306 # just drop it since we can't deal
307 done[name] = value
Tarek Ziadéedacea32010-01-29 11:41:03 +0000308 variables.remove(name)
309
Antoine Pitroudbec7802010-10-10 09:37:12 +0000310 # strip spurious spaces
311 for k, v in done.items():
312 if isinstance(v, str):
313 done[k] = v.strip()
314
Tarek Ziadéedacea32010-01-29 11:41:03 +0000315 # save the results in the global dictionary
316 vars.update(done)
317 return vars
318
Tarek Ziadéedacea32010-01-29 11:41:03 +0000319
Barry Warsawebbef6f2010-09-20 15:29:53 +0000320def get_makefile_filename():
Éric Araujo300623d2010-11-22 01:19:20 +0000321 """Return the path of the Makefile."""
Tarek Ziadéedacea32010-01-29 11:41:03 +0000322 if _PYTHON_BUILD:
323 return os.path.join(_PROJECT_BASE, "Makefile")
Barry Warsaw14d98ac2010-11-24 19:43:47 +0000324 return os.path.join(get_path('stdlib'),
325 'config-{}{}'.format(_PY_VERSION_SHORT, sys.abiflags),
326 'Makefile')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000327
Tarek Ziadéedacea32010-01-29 11:41:03 +0000328
329def _init_posix(vars):
330 """Initialize the module as appropriate for POSIX systems."""
331 # load the installed Makefile:
Barry Warsawebbef6f2010-09-20 15:29:53 +0000332 makefile = get_makefile_filename()
Tarek Ziadéedacea32010-01-29 11:41:03 +0000333 try:
334 _parse_makefile(makefile, vars)
335 except IOError as e:
336 msg = "invalid Python installation: unable to open %s" % makefile
337 if hasattr(e, "strerror"):
338 msg = msg + " (%s)" % e.strerror
339 raise IOError(msg)
340 # load the installed pyconfig.h:
341 config_h = get_config_h_filename()
342 try:
Antoine Pitroub86680e2010-10-14 21:15:17 +0000343 with open(config_h) as f:
344 parse_config_h(f, vars)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000345 except IOError as e:
346 msg = "invalid Python installation: unable to open %s" % config_h
347 if hasattr(e, "strerror"):
348 msg = msg + " (%s)" % e.strerror
349 raise IOError(msg)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000350 # 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
Victor Stinnerb103a932010-10-12 22:23:23 +0000365 vars['BINDIR'] = os.path.dirname(_safe_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():
Éric Araujo300623d2010-11-22 01:19:20 +0000402 """Return the path of pyconfig.h."""
Tarek Ziadébd797682010-02-02 23:16:13 +0000403 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():
Éric Araujo300623d2010-11-22 01:19:20 +0000413 """Return a tuple containing the schemes names."""
Tarek Ziadébd797682010-02-02 23:16:13 +0000414 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():
Éric Araujo300623d2010-11-22 01:19:20 +0000419 """Return 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):
Éric Araujo300623d2010-11-22 01:19:20 +0000423 """Return a mapping containing an install scheme.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000424
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):
Éric Araujo300623d2010-11-22 01:19:20 +0000434 """Return a path corresponding to the scheme.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000435
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
Barry Warsawd5eaa5f2010-11-25 01:34:47 +0000465 try:
466 _CONFIG_VARS['abiflags'] = sys.abiflags
467 except AttributeError:
468 # sys.abiflags may not be defined on all platforms.
469 _CONFIG_VARS['abiflags'] = ''
Tarek Ziadéedacea32010-01-29 11:41:03 +0000470
471 if os.name in ('nt', 'os2'):
472 _init_non_posix(_CONFIG_VARS)
473 if os.name == 'posix':
474 _init_posix(_CONFIG_VARS)
Ronald Oussoren4cda46a2010-05-08 10:49:43 +0000475 # Setting 'userbase' is done below the call to the
476 # init function to enable using 'get_config_var' in
477 # the init-function.
478 _CONFIG_VARS['userbase'] = _getuserbase()
479
Tarek Ziadéedacea32010-01-29 11:41:03 +0000480 if 'srcdir' not in _CONFIG_VARS:
481 _CONFIG_VARS['srcdir'] = _PROJECT_BASE
Ronald Oussorenab4fd612010-06-15 21:19:50 +0000482 else:
Victor Stinnerb103a932010-10-12 22:23:23 +0000483 _CONFIG_VARS['srcdir'] = _safe_realpath(_CONFIG_VARS['srcdir'])
Tarek Ziadéedacea32010-01-29 11:41:03 +0000484
485
486 # Convert srcdir into an absolute path if it appears necessary.
487 # Normally it is relative to the build directory. However, during
488 # testing, for example, we might be running a non-installed python
489 # from a different directory.
490 if _PYTHON_BUILD and os.name == "posix":
491 base = _PROJECT_BASE
Victor Stinnerb103a932010-10-12 22:23:23 +0000492 try:
493 cwd = os.getcwd()
494 except OSError:
495 cwd = None
Tarek Ziadéedacea32010-01-29 11:41:03 +0000496 if (not os.path.isabs(_CONFIG_VARS['srcdir']) and
Victor Stinnerb103a932010-10-12 22:23:23 +0000497 base != cwd):
Tarek Ziadéedacea32010-01-29 11:41:03 +0000498 # srcdir is relative and we are not in the same directory
499 # as the executable. Assume executable is in the build
500 # directory and make srcdir absolute.
501 srcdir = os.path.join(base, _CONFIG_VARS['srcdir'])
502 _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir)
503
504 if sys.platform == 'darwin':
505 kernel_version = os.uname()[2] # Kernel version (8.4.3)
506 major_version = int(kernel_version.split('.')[0])
507
508 if major_version < 8:
509 # On Mac OS X before 10.4, check if -arch and -isysroot
510 # are in CFLAGS or LDFLAGS and remove them if they are.
511 # This is needed when building extensions on a 10.3 system
512 # using a universal build of python.
513 for key in ('LDFLAGS', 'BASECFLAGS',
514 # a number of derived variables. These need to be
515 # patched up as well.
516 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
517 flags = _CONFIG_VARS[key]
518 flags = re.sub('-arch\s+\w+\s', ' ', flags)
519 flags = re.sub('-isysroot [^ \t]*', ' ', flags)
520 _CONFIG_VARS[key] = flags
521 else:
522 # Allow the user to override the architecture flags using
523 # an environment variable.
524 # NOTE: This name was introduced by Apple in OSX 10.5 and
525 # is used by several scripting languages distributed with
526 # that OS release.
527 if 'ARCHFLAGS' in os.environ:
528 arch = os.environ['ARCHFLAGS']
529 for key in ('LDFLAGS', 'BASECFLAGS',
530 # a number of derived variables. These need to be
531 # patched up as well.
532 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
533
534 flags = _CONFIG_VARS[key]
535 flags = re.sub('-arch\s+\w+\s', ' ', flags)
536 flags = flags + ' ' + arch
537 _CONFIG_VARS[key] = flags
538
539 # If we're on OSX 10.5 or later and the user tries to
540 # compiles an extension using an SDK that is not present
541 # on the current machine it is better to not use an SDK
542 # than to fail.
543 #
544 # The major usecase for this is users using a Python.org
545 # binary installer on OSX 10.6: that installer uses
546 # the 10.4u SDK, but that SDK is not installed by default
547 # when you install Xcode.
548 #
549 CFLAGS = _CONFIG_VARS.get('CFLAGS', '')
550 m = re.search('-isysroot\s+(\S+)', CFLAGS)
551 if m is not None:
552 sdk = m.group(1)
553 if not os.path.exists(sdk):
554 for key in ('LDFLAGS', 'BASECFLAGS',
555 # a number of derived variables. These need to be
556 # patched up as well.
557 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
558
559 flags = _CONFIG_VARS[key]
560 flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags)
561 _CONFIG_VARS[key] = flags
562
563 if args:
564 vals = []
565 for name in args:
566 vals.append(_CONFIG_VARS.get(name))
567 return vals
568 else:
569 return _CONFIG_VARS
570
571def get_config_var(name):
572 """Return the value of a single variable using the dictionary returned by
573 'get_config_vars()'.
574
575 Equivalent to get_config_vars().get(name)
576 """
577 return get_config_vars().get(name)
578
579def get_platform():
580 """Return a string that identifies the current platform.
581
582 This is used mainly to distinguish platform-specific build directories and
583 platform-specific built distributions. Typically includes the OS name
584 and version and the architecture (as supplied by 'os.uname()'),
585 although the exact information included depends on the OS; eg. for IRIX
586 the architecture isn't particularly important (IRIX only runs on SGI
587 hardware), but for Linux the kernel version isn't particularly
588 important.
589
590 Examples of returned values:
591 linux-i586
592 linux-alpha (?)
593 solaris-2.6-sun4u
594 irix-5.3
595 irix64-6.2
596
597 Windows will return one of:
598 win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
599 win-ia64 (64bit Windows on Itanium)
600 win32 (all others - specifically, sys.platform is returned)
601
602 For other non-POSIX platforms, currently just returns 'sys.platform'.
603 """
604 import re
605 if os.name == 'nt':
606 # sniff sys.version for architecture.
607 prefix = " bit ("
608 i = sys.version.find(prefix)
609 if i == -1:
610 return sys.platform
611 j = sys.version.find(")", i)
612 look = sys.version[i+len(prefix):j].lower()
613 if look == 'amd64':
614 return 'win-amd64'
615 if look == 'itanium':
616 return 'win-ia64'
617 return sys.platform
618
619 if os.name != "posix" or not hasattr(os, 'uname'):
620 # XXX what about the architecture? NT is Intel or Alpha,
621 # Mac OS is M68k or PPC, etc.
622 return sys.platform
623
624 # Try to distinguish various flavours of Unix
625 osname, host, release, version, machine = os.uname()
626
627 # Convert the OS name to lowercase, remove '/' characters
628 # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh")
629 osname = osname.lower().replace('/', '')
630 machine = machine.replace(' ', '_')
631 machine = machine.replace('/', '-')
632
633 if osname[:5] == "linux":
634 # At least on Linux/Intel, 'machine' is the processor --
635 # i386, etc.
636 # XXX what about Alpha, SPARC, etc?
637 return "%s-%s" % (osname, machine)
638 elif osname[:5] == "sunos":
639 if release[0] >= "5": # SunOS 5 == Solaris 2
640 osname = "solaris"
641 release = "%d.%s" % (int(release[0]) - 3, release[2:])
Jesus Cea1aa1cf32012-01-18 04:49:26 +0100642 # We can't use "platform.architecture()[0]" because a
643 # bootstrap problem. We use a dict to get an error
644 # if some suspicious happens.
645 bitness = {2147483647:"32bit", 9223372036854775807:"64bit"}
Jesus Cea031605a2012-01-18 05:04:49 +0100646 machine += ".%s" % bitness[sys.maxsize]
Tarek Ziadéedacea32010-01-29 11:41:03 +0000647 # fall through to standard osname-release-machine representation
648 elif osname[:4] == "irix": # could be "irix64"!
649 return "%s-%s" % (osname, release)
650 elif osname[:3] == "aix":
651 return "%s-%s.%s" % (osname, version, release)
652 elif osname[:6] == "cygwin":
653 osname = "cygwin"
654 rel_re = re.compile (r'[\d.]+')
655 m = rel_re.match(release)
656 if m:
657 release = m.group()
658 elif osname[:6] == "darwin":
659 #
660 # For our purposes, we'll assume that the system version from
661 # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set
662 # to. This makes the compatibility story a bit more sane because the
663 # machine is going to compile and link as if it were
664 # MACOSX_DEPLOYMENT_TARGET.
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200665 #
Tarek Ziadéedacea32010-01-29 11:41:03 +0000666 cfgvars = get_config_vars()
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200667 macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000668
669 if 1:
670 # Always calculate the release of the running machine,
671 # needed to determine if we can build fat binaries or not.
672
673 macrelease = macver
674 # Get the system version. Reading this plist is a documented
675 # way to get the system version (see the documentation for
676 # the Gestalt Manager)
677 try:
678 f = open('/System/Library/CoreServices/SystemVersion.plist')
679 except IOError:
680 # We're on a plain darwin box, fall back to the default
681 # behaviour.
682 pass
683 else:
Éric Araujobee5cef2010-11-05 23:51:56 +0000684 try:
685 m = re.search(
686 r'<key>ProductUserVisibleVersion</key>\s*' +
687 r'<string>(.*?)</string>', f.read())
Éric Araujobee5cef2010-11-05 23:51:56 +0000688 if m is not None:
689 macrelease = '.'.join(m.group(1).split('.')[:2])
690 # else: fall back to the default behaviour
691 finally:
692 f.close()
Tarek Ziadéedacea32010-01-29 11:41:03 +0000693
694 if not macver:
695 macver = macrelease
696
697 if macver:
698 release = macver
699 osname = "macosx"
700
701 if (macrelease + '.') >= '10.4.' and \
702 '-arch' in get_config_vars().get('CFLAGS', '').strip():
703 # The universal build will build fat binaries, but not on
704 # systems before 10.4
705 #
706 # Try to detect 4-way universal builds, those have machine-type
707 # 'universal' instead of 'fat'.
708
709 machine = 'fat'
710 cflags = get_config_vars().get('CFLAGS')
711
712 archs = re.findall('-arch\s+(\S+)', cflags)
Ronald Oussorend3950522010-07-11 09:05:07 +0000713 archs = tuple(sorted(set(archs)))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000714
715 if len(archs) == 1:
716 machine = archs[0]
717 elif archs == ('i386', 'ppc'):
718 machine = 'fat'
719 elif archs == ('i386', 'x86_64'):
720 machine = 'intel'
721 elif archs == ('i386', 'ppc', 'x86_64'):
722 machine = 'fat3'
723 elif archs == ('ppc64', 'x86_64'):
724 machine = 'fat64'
725 elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'):
726 machine = 'universal'
727 else:
728 raise ValueError(
729 "Don't know machine value for archs=%r"%(archs,))
730
731 elif machine == 'i386':
732 # On OSX the machine type returned by uname is always the
733 # 32-bit variant, even if the executable architecture is
734 # the 64-bit variant
735 if sys.maxsize >= 2**32:
736 machine = 'x86_64'
737
738 elif machine in ('PowerPC', 'Power_Macintosh'):
739 # Pick a sane name for the PPC architecture.
740 # See 'i386' case
741 if sys.maxsize >= 2**32:
742 machine = 'ppc64'
743 else:
744 machine = 'ppc'
745
746 return "%s-%s-%s" % (osname, release, machine)
747
748
749def get_python_version():
750 return _PY_VERSION_SHORT
Tarek Ziadéa7514992010-05-25 09:44:36 +0000751
752def _print_dict(title, data):
753 for index, (key, value) in enumerate(sorted(data.items())):
754 if index == 0:
755 print('{0}: '.format(title))
756 print('\t{0} = "{1}"'.format(key, value))
757
758def _main():
Éric Araujo300623d2010-11-22 01:19:20 +0000759 """Display all information sysconfig detains."""
Tarek Ziadéa7514992010-05-25 09:44:36 +0000760 print('Platform: "{0}"'.format(get_platform()))
761 print('Python version: "{0}"'.format(get_python_version()))
762 print('Current installation scheme: "{0}"'.format(_get_default_scheme()))
763 print('')
764 _print_dict('Paths', get_paths())
765 print('')
766 _print_dict('Variables', get_config_vars())
767
768if __name__ == '__main__':
769 _main()