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