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