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