blob: d07784d9670cda15e2b5330d423793b39d65c8ab [file] [log] [blame]
Tarek Ziade1231a4e2011-05-19 13:07:25 +02001"""Access to Python's configuration information."""
Tarek Ziadéedacea32010-01-29 11:41:03 +00002
Tarek Ziadéedacea32010-01-29 11:41:03 +00003import os
Tarek Ziade1231a4e2011-05-19 13:07:25 +02004import re
5import sys
Florent Xiclunaa4707382010-03-11 00:05:17 +00006from os.path import pardir, realpath
Tarek Ziade1231a4e2011-05-19 13:07:25 +02007from configparser import RawConfigParser
Tarek Ziadéedacea32010-01-29 11:41:03 +00008
Barry Warsawebbef6f2010-09-20 15:29:53 +00009__all__ = [
10 'get_config_h_filename',
11 'get_config_var',
12 'get_config_vars',
13 'get_makefile_filename',
14 'get_path',
15 'get_path_names',
16 'get_paths',
17 'get_platform',
18 'get_python_version',
19 'get_scheme_names',
20 'parse_config_h',
Tarek Ziade1231a4e2011-05-19 13:07:25 +020021]
Tarek Ziadé16ed6cb2010-05-25 09:47:06 +000022
Tarek Ziade1231a4e2011-05-19 13:07:25 +020023# let's read the configuration file
24# XXX _CONFIG_DIR will be set by the Makefile later
25_CONFIG_DIR = os.path.normpath(os.path.dirname(__file__))
26_CONFIG_FILE = os.path.join(_CONFIG_DIR, 'sysconfig.cfg')
27_SCHEMES = RawConfigParser()
28_SCHEMES.read(_CONFIG_FILE)
29_VAR_REPL = re.compile(r'\{([^{]*?)\}')
Tarek Ziadéedacea32010-01-29 11:41:03 +000030
Tarek Ziade1231a4e2011-05-19 13:07:25 +020031
32def _expand_globals(config):
33 if config.has_section('globals'):
34 globals = config.items('globals')
35 else:
36 globals = tuple()
37
38 sections = config.sections()
39 for section in sections:
40 if section == 'globals':
41 continue
42 for option, value in globals:
43 if config.has_option(section, option):
44 continue
45 config.set(section, option, value)
46 config.remove_section('globals')
47
48 # now expanding local variables defined in the cfg file
49 #
50 for section in config.sections():
51 variables = dict(config.items(section))
52
53 def _replacer(matchobj):
54 name = matchobj.group(1)
55 if name in variables:
56 return variables[name]
57 return matchobj.group(0)
58
59 for option, value in config.items(section):
60 config.set(section, option, _VAR_REPL.sub(_replacer, value))
61
62_expand_globals(_SCHEMES)
63
64 # FIXME don't rely on sys.version here, its format is an implementatin detail
65 # of CPython, use sys.version_info or sys.hexversion
Tarek Ziadéedacea32010-01-29 11:41:03 +000066_PY_VERSION = sys.version.split()[0]
67_PY_VERSION_SHORT = sys.version[:3]
68_PY_VERSION_SHORT_NO_DOT = _PY_VERSION[0] + _PY_VERSION[2]
69_PREFIX = os.path.normpath(sys.prefix)
70_EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
71_CONFIG_VARS = None
72_USER_BASE = None
Victor Stinnerb103a932010-10-12 22:23:23 +000073
Tarek Ziade1231a4e2011-05-19 13:07:25 +020074
Victor Stinnerb103a932010-10-12 22:23:23 +000075def _safe_realpath(path):
76 try:
77 return realpath(path)
78 except OSError:
79 return path
80
Victor Stinner171ba052010-03-12 14:20:59 +000081if sys.executable:
Victor Stinnerb103a932010-10-12 22:23:23 +000082 _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable))
Victor Stinner171ba052010-03-12 14:20:59 +000083else:
84 # sys.executable can be empty if argv[0] has been changed and Python is
85 # unable to retrieve the real program name
Victor Stinnerb103a932010-10-12 22:23:23 +000086 _PROJECT_BASE = _safe_realpath(os.getcwd())
Tarek Ziadéedacea32010-01-29 11:41:03 +000087
88if os.name == "nt" and "pcbuild" in _PROJECT_BASE[-8:].lower():
Victor Stinnerb103a932010-10-12 22:23:23 +000089 _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir))
Tarek Ziadéedacea32010-01-29 11:41:03 +000090# PC/VS7.1
91if os.name == "nt" and "\\pc\\v" in _PROJECT_BASE[-10:].lower():
Victor Stinnerb103a932010-10-12 22:23:23 +000092 _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
Tarek Ziadéedacea32010-01-29 11:41:03 +000093# PC/AMD64
94if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower():
Victor Stinnerb103a932010-10-12 22:23:23 +000095 _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
Tarek Ziadéedacea32010-01-29 11:41:03 +000096
Tarek Ziade1231a4e2011-05-19 13:07:25 +020097
Tarek Ziadéedacea32010-01-29 11:41:03 +000098def is_python_build():
99 for fn in ("Setup.dist", "Setup.local"):
100 if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)):
101 return True
102 return False
103
104_PYTHON_BUILD = is_python_build()
105
106if _PYTHON_BUILD:
107 for scheme in ('posix_prefix', 'posix_home'):
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200108 _SCHEMES.set(scheme, 'include', '{srcdir}/Include')
109 _SCHEMES.set(scheme, 'platinclude', '{projectbase}/.')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000110
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200111
112def _subst_vars(path, local_vars):
113 """In the string `path`, replace tokens like {some.thing} with the
114 corresponding value from the map `local_vars`.
115
116 If there is no corresponding value, leave the token unchanged.
117 """
118 def _replacer(matchobj):
119 name = matchobj.group(1)
120 if name in local_vars:
121 return local_vars[name]
122 elif name in os.environ:
123 return os.environ[name]
124 return matchobj.group(0)
125 return _VAR_REPL.sub(_replacer, path)
126
Tarek Ziadéedacea32010-01-29 11:41:03 +0000127
128def _extend_dict(target_dict, other_dict):
129 target_keys = target_dict.keys()
130 for key, value in other_dict.items():
131 if key in target_keys:
132 continue
133 target_dict[key] = value
134
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200135
Tarek Ziadéedacea32010-01-29 11:41:03 +0000136def _expand_vars(scheme, vars):
137 res = {}
138 if vars is None:
139 vars = {}
140 _extend_dict(vars, get_config_vars())
141
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200142 for key, value in _SCHEMES.items(scheme):
Tarek Ziadéedacea32010-01-29 11:41:03 +0000143 if os.name in ('posix', 'nt'):
144 value = os.path.expanduser(value)
145 res[key] = os.path.normpath(_subst_vars(value, vars))
146 return res
147
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200148
149def format_value(value, vars):
150 def _replacer(matchobj):
151 name = matchobj.group(1)
152 if name in vars:
153 return vars[name]
154 return matchobj.group(0)
155 return _VAR_REPL.sub(_replacer, value)
156
157
Tarek Ziadéedacea32010-01-29 11:41:03 +0000158def _get_default_scheme():
159 if os.name == 'posix':
160 # the default scheme for posix is posix_prefix
161 return 'posix_prefix'
162 return os.name
163
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200164
Tarek Ziadéedacea32010-01-29 11:41:03 +0000165def _getuserbase():
166 env_base = os.environ.get("PYTHONUSERBASE", None)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200167
Tarek Ziadéedacea32010-01-29 11:41:03 +0000168 def joinuser(*args):
169 return os.path.expanduser(os.path.join(*args))
170
171 # what about 'os2emx', 'riscos' ?
172 if os.name == "nt":
173 base = os.environ.get("APPDATA") or "~"
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200174 if env_base:
175 return env_base
176 else:
177 return joinuser(base, "Python")
Tarek Ziadéedacea32010-01-29 11:41:03 +0000178
Ronald Oussoren4cda46a2010-05-08 10:49:43 +0000179 if sys.platform == "darwin":
180 framework = get_config_var("PYTHONFRAMEWORK")
181 if framework:
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200182 if env_base:
183 return env_base
184 else:
185 return joinuser("~", "Library", framework, "%d.%d" %
186 sys.version_info[:2])
Ronald Oussoren4cda46a2010-05-08 10:49:43 +0000187
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200188 if env_base:
189 return env_base
190 else:
191 return joinuser("~", ".local")
Tarek Ziadéedacea32010-01-29 11:41:03 +0000192
193
194def _parse_makefile(filename, vars=None):
195 """Parse a Makefile-style file.
196
197 A dictionary containing name/value pairs is returned. If an
198 optional dictionary is passed in as the second argument, it is
199 used instead of a new dictionary.
200 """
Tarek Ziadéedacea32010-01-29 11:41:03 +0000201 # Regexes needed for parsing Makefile (and similar syntaxes,
202 # like old-style Setup files).
203 _variable_rx = re.compile("([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)")
204 _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")
205 _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")
206
207 if vars is None:
208 vars = {}
209 done = {}
210 notdone = {}
211
Victor Stinner75d8c5c2010-10-23 17:02:31 +0000212 with open(filename, errors="surrogateescape") as f:
Tarek Ziadéedacea32010-01-29 11:41:03 +0000213 lines = f.readlines()
214
215 for line in lines:
216 if line.startswith('#') or line.strip() == '':
217 continue
218 m = _variable_rx.match(line)
219 if m:
220 n, v = m.group(1, 2)
221 v = v.strip()
222 # `$$' is a literal `$' in make
223 tmpv = v.replace('$$', '')
224
225 if "$" in tmpv:
226 notdone[n] = v
227 else:
228 try:
229 v = int(v)
230 except ValueError:
231 # insert literal `$'
232 done[n] = v.replace('$$', '$')
233 else:
234 done[n] = v
235
236 # do variable interpolation here
237 variables = list(notdone.keys())
238
Ronald Oussorend21886c2010-07-20 16:07:10 +0000239 # Variables with a 'PY_' prefix in the makefile. These need to
240 # be made available without that prefix through sysconfig.
241 # Special care is needed to ensure that variable expansion works, even
242 # if the expansion uses the name without a prefix.
243 renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')
244
Tarek Ziadéedacea32010-01-29 11:41:03 +0000245 while len(variables) > 0:
246 for name in tuple(variables):
247 value = notdone[name]
248 m = _findvar1_rx.search(value) or _findvar2_rx.search(value)
249 if m is not None:
250 n = m.group(1)
251 found = True
252 if n in done:
253 item = str(done[n])
254 elif n in notdone:
255 # get it on a subsequent round
256 found = False
257 elif n in os.environ:
258 # do it like make: fall back to environment
259 item = os.environ[n]
Ronald Oussorend21886c2010-07-20 16:07:10 +0000260
261 elif n in renamed_variables:
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200262 if (name.startswith('PY_') and
263 name[3:] in renamed_variables):
Ronald Oussorend21886c2010-07-20 16:07:10 +0000264 item = ""
265
266 elif 'PY_' + n in notdone:
267 found = False
268
269 else:
270 item = str(done['PY_' + n])
271
Tarek Ziadéedacea32010-01-29 11:41:03 +0000272 else:
273 done[n] = item = ""
Ronald Oussorend21886c2010-07-20 16:07:10 +0000274
Tarek Ziadéedacea32010-01-29 11:41:03 +0000275 if found:
276 after = value[m.end():]
277 value = value[:m.start()] + item + after
278 if "$" in after:
279 notdone[name] = value
280 else:
281 try:
282 value = int(value)
283 except ValueError:
284 done[name] = value.strip()
285 else:
286 done[name] = value
287 variables.remove(name)
Ronald Oussorend21886c2010-07-20 16:07:10 +0000288
289 if name.startswith('PY_') \
Victor Stinner1273b7c2011-05-24 23:37:07 +0200290 and name[3:] in renamed_variables:
Ronald Oussorend21886c2010-07-20 16:07:10 +0000291
292 name = name[3:]
293 if name not in done:
294 done[name] = value
295
Tarek Ziadéedacea32010-01-29 11:41:03 +0000296 else:
Victor Stinner1273b7c2011-05-24 23:37:07 +0200297 # bogus variable reference (e.g. "prefix=$/opt/python");
298 # just drop it since we can't deal
299 done[name] = value
Tarek Ziadéedacea32010-01-29 11:41:03 +0000300 variables.remove(name)
301
Antoine Pitroudbec7802010-10-10 09:37:12 +0000302 # strip spurious spaces
303 for k, v in done.items():
304 if isinstance(v, str):
305 done[k] = v.strip()
306
Tarek Ziadéedacea32010-01-29 11:41:03 +0000307 # save the results in the global dictionary
308 vars.update(done)
309 return vars
310
Tarek Ziadéedacea32010-01-29 11:41:03 +0000311
Barry Warsawebbef6f2010-09-20 15:29:53 +0000312def get_makefile_filename():
Éric Araujo300623d2010-11-22 01:19:20 +0000313 """Return the path of the Makefile."""
Tarek Ziadéedacea32010-01-29 11:41:03 +0000314 if _PYTHON_BUILD:
315 return os.path.join(_PROJECT_BASE, "Makefile")
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200316 if hasattr(sys, 'abiflags'):
317 config_dir_name = 'config-%s%s' % (_PY_VERSION_SHORT, sys.abiflags)
318 else:
319 config_dir_name = 'config'
320 return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000321
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)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000344 # On AIX, there are wrong paths to the linker scripts in the Makefile
345 # -- these paths are relative to the Python source, but when installed
346 # the scripts are in another directory.
347 if _PYTHON_BUILD:
348 vars['LDSHARED'] = vars['BLDSHARED']
349
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200350
Tarek Ziadéedacea32010-01-29 11:41:03 +0000351def _init_non_posix(vars):
352 """Initialize the module as appropriate for NT"""
353 # set basic install directories
354 vars['LIBDEST'] = get_path('stdlib')
355 vars['BINLIBDEST'] = get_path('platstdlib')
356 vars['INCLUDEPY'] = get_path('include')
357 vars['SO'] = '.pyd'
358 vars['EXE'] = '.exe'
359 vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
Victor Stinnerb103a932010-10-12 22:23:23 +0000360 vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000361
362#
363# public APIs
364#
365
Tarek Ziadébd797682010-02-02 23:16:13 +0000366
367def parse_config_h(fp, vars=None):
368 """Parse a config.h-style file.
369
370 A dictionary containing name/value pairs is returned. If an
371 optional dictionary is passed in as the second argument, it is
372 used instead of a new dictionary.
373 """
Tarek Ziadébd797682010-02-02 23:16:13 +0000374 if vars is None:
375 vars = {}
376 define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
377 undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
378
379 while True:
380 line = fp.readline()
381 if not line:
382 break
383 m = define_rx.match(line)
384 if m:
385 n, v = m.group(1, 2)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200386 try:
387 v = int(v)
388 except ValueError:
389 pass
Tarek Ziadébd797682010-02-02 23:16:13 +0000390 vars[n] = v
391 else:
392 m = undef_rx.match(line)
393 if m:
394 vars[m.group(1)] = 0
395 return vars
396
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200397
Tarek Ziadébd797682010-02-02 23:16:13 +0000398def get_config_h_filename():
Éric Araujo300623d2010-11-22 01:19:20 +0000399 """Return the path of pyconfig.h."""
Tarek Ziadébd797682010-02-02 23:16:13 +0000400 if _PYTHON_BUILD:
401 if os.name == "nt":
402 inc_dir = os.path.join(_PROJECT_BASE, "PC")
403 else:
404 inc_dir = _PROJECT_BASE
405 else:
406 inc_dir = get_path('platinclude')
407 return os.path.join(inc_dir, 'pyconfig.h')
408
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200409
Tarek Ziadéedacea32010-01-29 11:41:03 +0000410def get_scheme_names():
Éric Araujo300623d2010-11-22 01:19:20 +0000411 """Return a tuple containing the schemes names."""
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200412 return tuple(sorted(_SCHEMES.sections()))
413
Tarek Ziadéedacea32010-01-29 11:41:03 +0000414
415def get_path_names():
Éric Araujo300623d2010-11-22 01:19:20 +0000416 """Return a tuple containing the paths names."""
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200417 # xxx see if we want a static list
418 return _SCHEMES.options('posix_prefix')
419
Tarek Ziadéedacea32010-01-29 11:41:03 +0000420
421def get_paths(scheme=_get_default_scheme(), vars=None, expand=True):
Éric Araujo300623d2010-11-22 01:19:20 +0000422 """Return a mapping containing an install scheme.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000423
424 ``scheme`` is the install scheme name. If not provided, it will
425 return the default scheme for the current platform.
426 """
427 if expand:
428 return _expand_vars(scheme, vars)
429 else:
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200430 return dict(_SCHEMES.items(scheme))
431
Tarek Ziadéedacea32010-01-29 11:41:03 +0000432
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
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200440
Tarek Ziadéedacea32010-01-29 11:41:03 +0000441def get_config_vars(*args):
442 """With no arguments, return a dictionary of all configuration
443 variables relevant for the current platform.
444
445 On Unix, this means every variable defined in Python's installed Makefile;
446 On Windows and Mac OS it's a much smaller set.
447
448 With arguments, return a list of values that result from looking up
449 each argument in the configuration variable dictionary.
450 """
Tarek Ziadéedacea32010-01-29 11:41:03 +0000451 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
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200456 # packaging module.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000457 _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.
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200478 if sys.version >= '2.6':
479 _CONFIG_VARS['userbase'] = _getuserbase()
Ronald Oussoren4cda46a2010-05-08 10:49:43 +0000480
Tarek Ziadéedacea32010-01-29 11:41:03 +0000481 if 'srcdir' not in _CONFIG_VARS:
482 _CONFIG_VARS['srcdir'] = _PROJECT_BASE
Ronald Oussorenab4fd612010-06-15 21:19:50 +0000483 else:
Victor Stinnerb103a932010-10-12 22:23:23 +0000484 _CONFIG_VARS['srcdir'] = _safe_realpath(_CONFIG_VARS['srcdir'])
Tarek Ziadéedacea32010-01-29 11:41:03 +0000485
Tarek Ziadéedacea32010-01-29 11:41:03 +0000486 # 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':
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200505 kernel_version = os.uname()[2] # Kernel version (8.4.3)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000506 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
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200571
Tarek Ziadéedacea32010-01-29 11:41:03 +0000572def get_config_var(name):
573 """Return the value of a single variable using the dictionary returned by
574 'get_config_vars()'.
575
576 Equivalent to get_config_vars().get(name)
577 """
578 return get_config_vars().get(name)
579
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200580
Tarek Ziadéedacea32010-01-29 11:41:03 +0000581def 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 """
Tarek Ziadéedacea32010-01-29 11:41:03 +0000606 if os.name == 'nt':
607 # sniff sys.version for architecture.
608 prefix = " bit ("
609 i = sys.version.find(prefix)
610 if i == -1:
611 return sys.platform
612 j = sys.version.find(")", i)
613 look = sys.version[i+len(prefix):j].lower()
614 if look == 'amd64':
615 return 'win-amd64'
616 if look == 'itanium':
617 return 'win-ia64'
618 return sys.platform
619
620 if os.name != "posix" or not hasattr(os, 'uname'):
621 # XXX what about the architecture? NT is Intel or Alpha,
622 # Mac OS is M68k or PPC, etc.
623 return sys.platform
624
625 # Try to distinguish various flavours of Unix
626 osname, host, release, version, machine = os.uname()
627
628 # Convert the OS name to lowercase, remove '/' characters
629 # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh")
630 osname = osname.lower().replace('/', '')
631 machine = machine.replace(' ', '_')
632 machine = machine.replace('/', '-')
633
634 if osname[:5] == "linux":
635 # At least on Linux/Intel, 'machine' is the processor --
636 # i386, etc.
637 # XXX what about Alpha, SPARC, etc?
638 return "%s-%s" % (osname, machine)
639 elif osname[:5] == "sunos":
640 if release[0] >= "5": # SunOS 5 == Solaris 2
641 osname = "solaris"
642 release = "%d.%s" % (int(release[0]) - 3, release[2:])
643 # fall through to standard osname-release-machine representation
644 elif osname[:4] == "irix": # could be "irix64"!
645 return "%s-%s" % (osname, release)
646 elif osname[:3] == "aix":
647 return "%s-%s.%s" % (osname, version, release)
648 elif osname[:6] == "cygwin":
649 osname = "cygwin"
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200650 rel_re = re.compile(r'[\d.]+')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000651 m = rel_re.match(release)
652 if m:
653 release = m.group()
654 elif osname[:6] == "darwin":
655 #
656 # For our purposes, we'll assume that the system version from
657 # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set
658 # to. This makes the compatibility story a bit more sane because the
659 # machine is going to compile and link as if it were
660 # MACOSX_DEPLOYMENT_TARGET.
661 cfgvars = get_config_vars()
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200662 macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000663
Éric Araujo559b5f12011-05-25 18:21:43 +0200664 if True:
Tarek Ziadéedacea32010-01-29 11:41:03 +0000665 # Always calculate the release of the running machine,
666 # needed to determine if we can build fat binaries or not.
667
668 macrelease = macver
669 # Get the system version. Reading this plist is a documented
670 # way to get the system version (see the documentation for
671 # the Gestalt Manager)
672 try:
673 f = open('/System/Library/CoreServices/SystemVersion.plist')
674 except IOError:
675 # We're on a plain darwin box, fall back to the default
676 # behaviour.
677 pass
678 else:
Éric Araujobee5cef2010-11-05 23:51:56 +0000679 try:
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200680 m = re.search(r'<key>ProductUserVisibleVersion</key>\s*'
681 r'<string>(.*?)</string>', f.read())
Éric Araujobee5cef2010-11-05 23:51:56 +0000682 finally:
683 f.close()
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200684 if m is not None:
685 macrelease = '.'.join(m.group(1).split('.')[:2])
686 # else: fall back to the default behaviour
Tarek Ziadéedacea32010-01-29 11:41:03 +0000687
688 if not macver:
689 macver = macrelease
690
691 if macver:
692 release = macver
693 osname = "macosx"
694
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200695 if ((macrelease + '.') >= '10.4.' and
696 '-arch' in get_config_vars().get('CFLAGS', '').strip()):
Tarek Ziadéedacea32010-01-29 11:41:03 +0000697 # The universal build will build fat binaries, but not on
698 # systems before 10.4
699 #
700 # Try to detect 4-way universal builds, those have machine-type
701 # 'universal' instead of 'fat'.
702
703 machine = 'fat'
704 cflags = get_config_vars().get('CFLAGS')
705
706 archs = re.findall('-arch\s+(\S+)', cflags)
Ronald Oussorend3950522010-07-11 09:05:07 +0000707 archs = tuple(sorted(set(archs)))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000708
709 if len(archs) == 1:
710 machine = archs[0]
711 elif archs == ('i386', 'ppc'):
712 machine = 'fat'
713 elif archs == ('i386', 'x86_64'):
714 machine = 'intel'
715 elif archs == ('i386', 'ppc', 'x86_64'):
716 machine = 'fat3'
717 elif archs == ('ppc64', 'x86_64'):
718 machine = 'fat64'
719 elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'):
720 machine = 'universal'
721 else:
722 raise ValueError(
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200723 "Don't know machine value for archs=%r" % (archs,))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000724
725 elif machine == 'i386':
726 # On OSX the machine type returned by uname is always the
727 # 32-bit variant, even if the executable architecture is
728 # the 64-bit variant
729 if sys.maxsize >= 2**32:
730 machine = 'x86_64'
731
732 elif machine in ('PowerPC', 'Power_Macintosh'):
733 # Pick a sane name for the PPC architecture.
734 # See 'i386' case
735 if sys.maxsize >= 2**32:
736 machine = 'ppc64'
737 else:
738 machine = 'ppc'
739
740 return "%s-%s-%s" % (osname, release, machine)
741
742
743def get_python_version():
744 return _PY_VERSION_SHORT
Tarek Ziadéa7514992010-05-25 09:44:36 +0000745
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200746
Tarek Ziadéa7514992010-05-25 09:44:36 +0000747def _print_dict(title, data):
748 for index, (key, value) in enumerate(sorted(data.items())):
749 if index == 0:
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200750 print('%s: ' % (title))
751 print('\t%s = "%s"' % (key, value))
752
Tarek Ziadéa7514992010-05-25 09:44:36 +0000753
754def _main():
Éric Araujo300623d2010-11-22 01:19:20 +0000755 """Display all information sysconfig detains."""
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200756 print('Platform: "%s"' % get_platform())
757 print('Python version: "%s"' % get_python_version())
758 print('Current installation scheme: "%s"' % _get_default_scheme())
Éric Araujo559b5f12011-05-25 18:21:43 +0200759 print()
Tarek Ziadéa7514992010-05-25 09:44:36 +0000760 _print_dict('Paths', get_paths())
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200761 print()
Tarek Ziadéa7514992010-05-25 09:44:36 +0000762 _print_dict('Variables', get_config_vars())
763
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200764
Tarek Ziadéa7514992010-05-25 09:44:36 +0000765if __name__ == '__main__':
766 _main()