blob: 36c7aa49a56e0d244f90b0eabafa0e3e0ee31b13 [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')
Antoine Pitroudc567e42011-10-11 16:07:30 +020027_SCHEMES = RawConfigParser(dict_type=dict) # Faster than OrderedDict
Tarek Ziade1231a4e2011-05-19 13:07:25 +020028_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
Antoine Pitrou1e73a242011-10-18 17:52:24 +0200322def _generate_posix_vars():
323 """Generate the Python module containing build-time variables."""
324 import pprint
325 vars = {}
326 destfile = os.path.join(os.path.dirname(__file__), '_sysconfigdata.py')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000327 # load the installed Makefile:
Barry Warsawebbef6f2010-09-20 15:29:53 +0000328 makefile = get_makefile_filename()
Tarek Ziadéedacea32010-01-29 11:41:03 +0000329 try:
330 _parse_makefile(makefile, vars)
331 except IOError as e:
332 msg = "invalid Python installation: unable to open %s" % makefile
333 if hasattr(e, "strerror"):
334 msg = msg + " (%s)" % e.strerror
335 raise IOError(msg)
336 # load the installed pyconfig.h:
337 config_h = get_config_h_filename()
338 try:
Antoine Pitroub86680e2010-10-14 21:15:17 +0000339 with open(config_h) as f:
340 parse_config_h(f, vars)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000341 except IOError as e:
342 msg = "invalid Python installation: unable to open %s" % config_h
343 if hasattr(e, "strerror"):
344 msg = msg + " (%s)" % e.strerror
345 raise IOError(msg)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000346 # On AIX, there are wrong paths to the linker scripts in the Makefile
347 # -- these paths are relative to the Python source, but when installed
348 # the scripts are in another directory.
349 if _PYTHON_BUILD:
350 vars['LDSHARED'] = vars['BLDSHARED']
Antoine Pitrou1e73a242011-10-18 17:52:24 +0200351 with open(destfile, 'w', encoding='utf8') as f:
352 f.write('build_time_vars = ')
353 pprint.pprint(vars, stream=f)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000354
Antoine Pitrou1e73a242011-10-18 17:52:24 +0200355def _init_posix(vars):
356 """Initialize the module as appropriate for POSIX systems."""
357 # _sysconfigdata is generated at build time, see _generate_posix_vars()
358 from _sysconfigdata import build_time_vars
359 vars.update(build_time_vars)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200360
Tarek Ziadéedacea32010-01-29 11:41:03 +0000361def _init_non_posix(vars):
362 """Initialize the module as appropriate for NT"""
363 # set basic install directories
364 vars['LIBDEST'] = get_path('stdlib')
365 vars['BINLIBDEST'] = get_path('platstdlib')
366 vars['INCLUDEPY'] = get_path('include')
367 vars['SO'] = '.pyd'
368 vars['EXE'] = '.exe'
369 vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
Victor Stinnerb103a932010-10-12 22:23:23 +0000370 vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000371
372#
373# public APIs
374#
375
Tarek Ziadébd797682010-02-02 23:16:13 +0000376
377def parse_config_h(fp, vars=None):
378 """Parse a config.h-style file.
379
380 A dictionary containing name/value pairs is returned. If an
381 optional dictionary is passed in as the second argument, it is
382 used instead of a new dictionary.
383 """
Tarek Ziadébd797682010-02-02 23:16:13 +0000384 if vars is None:
385 vars = {}
386 define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
387 undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
388
389 while True:
390 line = fp.readline()
391 if not line:
392 break
393 m = define_rx.match(line)
394 if m:
395 n, v = m.group(1, 2)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200396 try:
397 v = int(v)
398 except ValueError:
399 pass
Tarek Ziadébd797682010-02-02 23:16:13 +0000400 vars[n] = v
401 else:
402 m = undef_rx.match(line)
403 if m:
404 vars[m.group(1)] = 0
405 return vars
406
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200407
Tarek Ziadébd797682010-02-02 23:16:13 +0000408def get_config_h_filename():
Éric Araujo300623d2010-11-22 01:19:20 +0000409 """Return the path of pyconfig.h."""
Tarek Ziadébd797682010-02-02 23:16:13 +0000410 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 Ziade1231a4e2011-05-19 13:07:25 +0200419
Tarek Ziadéedacea32010-01-29 11:41:03 +0000420def get_scheme_names():
Éric Araujo300623d2010-11-22 01:19:20 +0000421 """Return a tuple containing the schemes names."""
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200422 return tuple(sorted(_SCHEMES.sections()))
423
Tarek Ziadéedacea32010-01-29 11:41:03 +0000424
425def get_path_names():
Éric Araujo300623d2010-11-22 01:19:20 +0000426 """Return a tuple containing the paths names."""
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200427 # xxx see if we want a static list
428 return _SCHEMES.options('posix_prefix')
429
Tarek Ziadéedacea32010-01-29 11:41:03 +0000430
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:
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200440 return dict(_SCHEMES.items(scheme))
441
Tarek Ziadéedacea32010-01-29 11:41:03 +0000442
443def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True):
Éric Araujo300623d2010-11-22 01:19:20 +0000444 """Return a path corresponding to the scheme.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000445
446 ``scheme`` is the install scheme name.
447 """
448 return get_paths(scheme, vars, expand)[name]
449
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200450
Tarek Ziadéedacea32010-01-29 11:41:03 +0000451def get_config_vars(*args):
452 """With no arguments, return a dictionary of all configuration
453 variables relevant for the current platform.
454
455 On Unix, this means every variable defined in Python's installed Makefile;
456 On Windows and Mac OS it's a much smaller set.
457
458 With arguments, return a list of values that result from looking up
459 each argument in the configuration variable dictionary.
460 """
Tarek Ziadéedacea32010-01-29 11:41:03 +0000461 global _CONFIG_VARS
462 if _CONFIG_VARS is None:
463 _CONFIG_VARS = {}
464 # Normalized versions of prefix and exec_prefix are handy to have;
465 # in fact, these are the standard versions used most places in the
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200466 # packaging module.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000467 _CONFIG_VARS['prefix'] = _PREFIX
468 _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX
469 _CONFIG_VARS['py_version'] = _PY_VERSION
470 _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT
471 _CONFIG_VARS['py_version_nodot'] = _PY_VERSION[0] + _PY_VERSION[2]
472 _CONFIG_VARS['base'] = _PREFIX
473 _CONFIG_VARS['platbase'] = _EXEC_PREFIX
Tarek Ziadéedacea32010-01-29 11:41:03 +0000474 _CONFIG_VARS['projectbase'] = _PROJECT_BASE
Barry Warsawd5eaa5f2010-11-25 01:34:47 +0000475 try:
476 _CONFIG_VARS['abiflags'] = sys.abiflags
477 except AttributeError:
478 # sys.abiflags may not be defined on all platforms.
479 _CONFIG_VARS['abiflags'] = ''
Tarek Ziadéedacea32010-01-29 11:41:03 +0000480
481 if os.name in ('nt', 'os2'):
482 _init_non_posix(_CONFIG_VARS)
483 if os.name == 'posix':
484 _init_posix(_CONFIG_VARS)
Ronald Oussoren4cda46a2010-05-08 10:49:43 +0000485 # Setting 'userbase' is done below the call to the
486 # init function to enable using 'get_config_var' in
487 # the init-function.
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200488 if sys.version >= '2.6':
489 _CONFIG_VARS['userbase'] = _getuserbase()
Ronald Oussoren4cda46a2010-05-08 10:49:43 +0000490
Tarek Ziadéedacea32010-01-29 11:41:03 +0000491 if 'srcdir' not in _CONFIG_VARS:
492 _CONFIG_VARS['srcdir'] = _PROJECT_BASE
Ronald Oussorenab4fd612010-06-15 21:19:50 +0000493 else:
Victor Stinnerb103a932010-10-12 22:23:23 +0000494 _CONFIG_VARS['srcdir'] = _safe_realpath(_CONFIG_VARS['srcdir'])
Tarek Ziadéedacea32010-01-29 11:41:03 +0000495
Tarek Ziadéedacea32010-01-29 11:41:03 +0000496 # Convert srcdir into an absolute path if it appears necessary.
497 # Normally it is relative to the build directory. However, during
498 # testing, for example, we might be running a non-installed python
499 # from a different directory.
500 if _PYTHON_BUILD and os.name == "posix":
501 base = _PROJECT_BASE
Victor Stinnerb103a932010-10-12 22:23:23 +0000502 try:
503 cwd = os.getcwd()
504 except OSError:
505 cwd = None
Tarek Ziadéedacea32010-01-29 11:41:03 +0000506 if (not os.path.isabs(_CONFIG_VARS['srcdir']) and
Victor Stinnerb103a932010-10-12 22:23:23 +0000507 base != cwd):
Tarek Ziadéedacea32010-01-29 11:41:03 +0000508 # srcdir is relative and we are not in the same directory
509 # as the executable. Assume executable is in the build
510 # directory and make srcdir absolute.
511 srcdir = os.path.join(base, _CONFIG_VARS['srcdir'])
512 _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir)
513
514 if sys.platform == 'darwin':
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200515 kernel_version = os.uname()[2] # Kernel version (8.4.3)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000516 major_version = int(kernel_version.split('.')[0])
517
518 if major_version < 8:
519 # On Mac OS X before 10.4, check if -arch and -isysroot
520 # are in CFLAGS or LDFLAGS and remove them if they are.
521 # This is needed when building extensions on a 10.3 system
522 # using a universal build of python.
523 for key in ('LDFLAGS', 'BASECFLAGS',
524 # a number of derived variables. These need to be
525 # patched up as well.
526 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
527 flags = _CONFIG_VARS[key]
528 flags = re.sub('-arch\s+\w+\s', ' ', flags)
529 flags = re.sub('-isysroot [^ \t]*', ' ', flags)
530 _CONFIG_VARS[key] = flags
531 else:
532 # Allow the user to override the architecture flags using
533 # an environment variable.
534 # NOTE: This name was introduced by Apple in OSX 10.5 and
535 # is used by several scripting languages distributed with
536 # that OS release.
537 if 'ARCHFLAGS' in os.environ:
538 arch = os.environ['ARCHFLAGS']
539 for key in ('LDFLAGS', 'BASECFLAGS',
540 # a number of derived variables. These need to be
541 # patched up as well.
542 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
543
544 flags = _CONFIG_VARS[key]
545 flags = re.sub('-arch\s+\w+\s', ' ', flags)
546 flags = flags + ' ' + arch
547 _CONFIG_VARS[key] = flags
548
549 # If we're on OSX 10.5 or later and the user tries to
550 # compiles an extension using an SDK that is not present
551 # on the current machine it is better to not use an SDK
552 # than to fail.
553 #
554 # The major usecase for this is users using a Python.org
555 # binary installer on OSX 10.6: that installer uses
556 # the 10.4u SDK, but that SDK is not installed by default
557 # when you install Xcode.
558 #
559 CFLAGS = _CONFIG_VARS.get('CFLAGS', '')
560 m = re.search('-isysroot\s+(\S+)', CFLAGS)
561 if m is not None:
562 sdk = m.group(1)
563 if not os.path.exists(sdk):
564 for key in ('LDFLAGS', 'BASECFLAGS',
565 # a number of derived variables. These need to be
566 # patched up as well.
567 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
568
569 flags = _CONFIG_VARS[key]
570 flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags)
571 _CONFIG_VARS[key] = flags
572
573 if args:
574 vals = []
575 for name in args:
576 vals.append(_CONFIG_VARS.get(name))
577 return vals
578 else:
579 return _CONFIG_VARS
580
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200581
Tarek Ziadéedacea32010-01-29 11:41:03 +0000582def get_config_var(name):
583 """Return the value of a single variable using the dictionary returned by
584 'get_config_vars()'.
585
586 Equivalent to get_config_vars().get(name)
587 """
588 return get_config_vars().get(name)
589
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200590
Tarek Ziadéedacea32010-01-29 11:41:03 +0000591def get_platform():
592 """Return a string that identifies the current platform.
593
594 This is used mainly to distinguish platform-specific build directories and
595 platform-specific built distributions. Typically includes the OS name
596 and version and the architecture (as supplied by 'os.uname()'),
597 although the exact information included depends on the OS; eg. for IRIX
598 the architecture isn't particularly important (IRIX only runs on SGI
599 hardware), but for Linux the kernel version isn't particularly
600 important.
601
602 Examples of returned values:
603 linux-i586
604 linux-alpha (?)
605 solaris-2.6-sun4u
606 irix-5.3
607 irix64-6.2
608
609 Windows will return one of:
610 win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
611 win-ia64 (64bit Windows on Itanium)
612 win32 (all others - specifically, sys.platform is returned)
613
614 For other non-POSIX platforms, currently just returns 'sys.platform'.
615 """
Tarek Ziadéedacea32010-01-29 11:41:03 +0000616 if os.name == 'nt':
617 # sniff sys.version for architecture.
618 prefix = " bit ("
619 i = sys.version.find(prefix)
620 if i == -1:
621 return sys.platform
622 j = sys.version.find(")", i)
623 look = sys.version[i+len(prefix):j].lower()
624 if look == 'amd64':
625 return 'win-amd64'
626 if look == 'itanium':
627 return 'win-ia64'
628 return sys.platform
629
630 if os.name != "posix" or not hasattr(os, 'uname'):
631 # XXX what about the architecture? NT is Intel or Alpha,
632 # Mac OS is M68k or PPC, etc.
633 return sys.platform
634
635 # Try to distinguish various flavours of Unix
636 osname, host, release, version, machine = os.uname()
637
638 # Convert the OS name to lowercase, remove '/' characters
639 # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh")
640 osname = osname.lower().replace('/', '')
641 machine = machine.replace(' ', '_')
642 machine = machine.replace('/', '-')
643
644 if osname[:5] == "linux":
645 # At least on Linux/Intel, 'machine' is the processor --
646 # i386, etc.
647 # XXX what about Alpha, SPARC, etc?
648 return "%s-%s" % (osname, machine)
649 elif osname[:5] == "sunos":
650 if release[0] >= "5": # SunOS 5 == Solaris 2
651 osname = "solaris"
652 release = "%d.%s" % (int(release[0]) - 3, release[2:])
653 # fall through to standard osname-release-machine representation
654 elif osname[:4] == "irix": # could be "irix64"!
655 return "%s-%s" % (osname, release)
656 elif osname[:3] == "aix":
657 return "%s-%s.%s" % (osname, version, release)
658 elif osname[:6] == "cygwin":
659 osname = "cygwin"
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200660 rel_re = re.compile(r'[\d.]+')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000661 m = rel_re.match(release)
662 if m:
663 release = m.group()
664 elif osname[:6] == "darwin":
665 #
666 # For our purposes, we'll assume that the system version from
667 # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set
668 # to. This makes the compatibility story a bit more sane because the
669 # machine is going to compile and link as if it were
670 # MACOSX_DEPLOYMENT_TARGET.
671 cfgvars = get_config_vars()
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200672 macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000673
Éric Araujo559b5f12011-05-25 18:21:43 +0200674 if True:
Tarek Ziadéedacea32010-01-29 11:41:03 +0000675 # Always calculate the release of the running machine,
676 # needed to determine if we can build fat binaries or not.
677
678 macrelease = macver
679 # Get the system version. Reading this plist is a documented
680 # way to get the system version (see the documentation for
681 # the Gestalt Manager)
682 try:
683 f = open('/System/Library/CoreServices/SystemVersion.plist')
684 except IOError:
685 # We're on a plain darwin box, fall back to the default
686 # behaviour.
687 pass
688 else:
Éric Araujobee5cef2010-11-05 23:51:56 +0000689 try:
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200690 m = re.search(r'<key>ProductUserVisibleVersion</key>\s*'
691 r'<string>(.*?)</string>', f.read())
Éric Araujobee5cef2010-11-05 23:51:56 +0000692 finally:
693 f.close()
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200694 if m is not None:
695 macrelease = '.'.join(m.group(1).split('.')[:2])
696 # else: fall back to the default behaviour
Tarek Ziadéedacea32010-01-29 11:41:03 +0000697
698 if not macver:
699 macver = macrelease
700
701 if macver:
702 release = macver
703 osname = "macosx"
704
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200705 if ((macrelease + '.') >= '10.4.' and
706 '-arch' in get_config_vars().get('CFLAGS', '').strip()):
Tarek Ziadéedacea32010-01-29 11:41:03 +0000707 # The universal build will build fat binaries, but not on
708 # systems before 10.4
709 #
710 # Try to detect 4-way universal builds, those have machine-type
711 # 'universal' instead of 'fat'.
712
713 machine = 'fat'
714 cflags = get_config_vars().get('CFLAGS')
715
716 archs = re.findall('-arch\s+(\S+)', cflags)
Ronald Oussorend3950522010-07-11 09:05:07 +0000717 archs = tuple(sorted(set(archs)))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000718
719 if len(archs) == 1:
720 machine = archs[0]
721 elif archs == ('i386', 'ppc'):
722 machine = 'fat'
723 elif archs == ('i386', 'x86_64'):
724 machine = 'intel'
725 elif archs == ('i386', 'ppc', 'x86_64'):
726 machine = 'fat3'
727 elif archs == ('ppc64', 'x86_64'):
728 machine = 'fat64'
729 elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'):
730 machine = 'universal'
731 else:
732 raise ValueError(
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200733 "Don't know machine value for archs=%r" % (archs,))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000734
735 elif machine == 'i386':
736 # On OSX the machine type returned by uname is always the
737 # 32-bit variant, even if the executable architecture is
738 # the 64-bit variant
739 if sys.maxsize >= 2**32:
740 machine = 'x86_64'
741
742 elif machine in ('PowerPC', 'Power_Macintosh'):
743 # Pick a sane name for the PPC architecture.
744 # See 'i386' case
745 if sys.maxsize >= 2**32:
746 machine = 'ppc64'
747 else:
748 machine = 'ppc'
749
750 return "%s-%s-%s" % (osname, release, machine)
751
752
753def get_python_version():
754 return _PY_VERSION_SHORT
Tarek Ziadéa7514992010-05-25 09:44:36 +0000755
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200756
Tarek Ziadéa7514992010-05-25 09:44:36 +0000757def _print_dict(title, data):
758 for index, (key, value) in enumerate(sorted(data.items())):
759 if index == 0:
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200760 print('%s: ' % (title))
761 print('\t%s = "%s"' % (key, value))
762
Tarek Ziadéa7514992010-05-25 09:44:36 +0000763
764def _main():
Éric Araujo300623d2010-11-22 01:19:20 +0000765 """Display all information sysconfig detains."""
Antoine Pitrou1e73a242011-10-18 17:52:24 +0200766 if '--generate-posix-vars' in sys.argv:
767 _generate_posix_vars()
768 return
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200769 print('Platform: "%s"' % get_platform())
770 print('Python version: "%s"' % get_python_version())
771 print('Current installation scheme: "%s"' % _get_default_scheme())
Éric Araujo559b5f12011-05-25 18:21:43 +0200772 print()
Tarek Ziadéa7514992010-05-25 09:44:36 +0000773 _print_dict('Paths', get_paths())
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200774 print()
Tarek Ziadéa7514992010-05-25 09:44:36 +0000775 _print_dict('Variables', get_config_vars())
776
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200777
Tarek Ziadéa7514992010-05-25 09:44:36 +0000778if __name__ == '__main__':
779 _main()