blob: 0b79ffb90e209d6d27dc69906f85654e430ae805 [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 = {}
Tarek Ziadéedacea32010-01-29 11:41:03 +0000326 # load the installed Makefile:
Barry Warsawebbef6f2010-09-20 15:29:53 +0000327 makefile = get_makefile_filename()
Tarek Ziadéedacea32010-01-29 11:41:03 +0000328 try:
329 _parse_makefile(makefile, vars)
330 except IOError as e:
331 msg = "invalid Python installation: unable to open %s" % makefile
332 if hasattr(e, "strerror"):
333 msg = msg + " (%s)" % e.strerror
334 raise IOError(msg)
335 # load the installed pyconfig.h:
336 config_h = get_config_h_filename()
337 try:
Antoine Pitroub86680e2010-10-14 21:15:17 +0000338 with open(config_h) as f:
339 parse_config_h(f, vars)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000340 except IOError as e:
341 msg = "invalid Python installation: unable to open %s" % config_h
342 if hasattr(e, "strerror"):
343 msg = msg + " (%s)" % e.strerror
344 raise IOError(msg)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000345 # On AIX, there are wrong paths to the linker scripts in the Makefile
346 # -- these paths are relative to the Python source, but when installed
347 # the scripts are in another directory.
348 if _PYTHON_BUILD:
349 vars['LDSHARED'] = vars['BLDSHARED']
Victor Stinner65651ea2011-10-20 00:41:21 +0200350
351 destfile = os.path.join(os.path.dirname(__file__), '_sysconfigdata.py')
Antoine Pitrou1e73a242011-10-18 17:52:24 +0200352 with open(destfile, 'w', encoding='utf8') as f:
Victor Stinner65651ea2011-10-20 00:41:21 +0200353 f.write('# system configuration generated and used by'
354 ' the sysconfig module\n')
Antoine Pitrou1e73a242011-10-18 17:52:24 +0200355 f.write('build_time_vars = ')
356 pprint.pprint(vars, stream=f)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000357
Antoine Pitrou1e73a242011-10-18 17:52:24 +0200358def _init_posix(vars):
359 """Initialize the module as appropriate for POSIX systems."""
360 # _sysconfigdata is generated at build time, see _generate_posix_vars()
361 from _sysconfigdata import build_time_vars
362 vars.update(build_time_vars)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200363
Tarek Ziadéedacea32010-01-29 11:41:03 +0000364def _init_non_posix(vars):
365 """Initialize the module as appropriate for NT"""
366 # set basic install directories
367 vars['LIBDEST'] = get_path('stdlib')
368 vars['BINLIBDEST'] = get_path('platstdlib')
369 vars['INCLUDEPY'] = get_path('include')
370 vars['SO'] = '.pyd'
371 vars['EXE'] = '.exe'
372 vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
Victor Stinnerb103a932010-10-12 22:23:23 +0000373 vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000374
375#
376# public APIs
377#
378
Tarek Ziadébd797682010-02-02 23:16:13 +0000379
380def parse_config_h(fp, vars=None):
381 """Parse a config.h-style file.
382
383 A dictionary containing name/value pairs is returned. If an
384 optional dictionary is passed in as the second argument, it is
385 used instead of a new dictionary.
386 """
Tarek Ziadébd797682010-02-02 23:16:13 +0000387 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)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200399 try:
400 v = int(v)
401 except ValueError:
402 pass
Tarek Ziadébd797682010-02-02 23:16:13 +0000403 vars[n] = v
404 else:
405 m = undef_rx.match(line)
406 if m:
407 vars[m.group(1)] = 0
408 return vars
409
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200410
Tarek Ziadébd797682010-02-02 23:16:13 +0000411def get_config_h_filename():
Éric Araujo300623d2010-11-22 01:19:20 +0000412 """Return the path of pyconfig.h."""
Tarek Ziadébd797682010-02-02 23:16:13 +0000413 if _PYTHON_BUILD:
414 if os.name == "nt":
415 inc_dir = os.path.join(_PROJECT_BASE, "PC")
416 else:
417 inc_dir = _PROJECT_BASE
418 else:
419 inc_dir = get_path('platinclude')
420 return os.path.join(inc_dir, 'pyconfig.h')
421
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200422
Tarek Ziadéedacea32010-01-29 11:41:03 +0000423def get_scheme_names():
Éric Araujo300623d2010-11-22 01:19:20 +0000424 """Return a tuple containing the schemes names."""
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200425 return tuple(sorted(_SCHEMES.sections()))
426
Tarek Ziadéedacea32010-01-29 11:41:03 +0000427
428def get_path_names():
Éric Araujo300623d2010-11-22 01:19:20 +0000429 """Return a tuple containing the paths names."""
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200430 # xxx see if we want a static list
431 return _SCHEMES.options('posix_prefix')
432
Tarek Ziadéedacea32010-01-29 11:41:03 +0000433
434def get_paths(scheme=_get_default_scheme(), vars=None, expand=True):
Éric Araujo300623d2010-11-22 01:19:20 +0000435 """Return a mapping containing an install scheme.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000436
437 ``scheme`` is the install scheme name. If not provided, it will
438 return the default scheme for the current platform.
439 """
440 if expand:
441 return _expand_vars(scheme, vars)
442 else:
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200443 return dict(_SCHEMES.items(scheme))
444
Tarek Ziadéedacea32010-01-29 11:41:03 +0000445
446def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True):
Éric Araujo300623d2010-11-22 01:19:20 +0000447 """Return a path corresponding to the scheme.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000448
449 ``scheme`` is the install scheme name.
450 """
451 return get_paths(scheme, vars, expand)[name]
452
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200453
Tarek Ziadéedacea32010-01-29 11:41:03 +0000454def get_config_vars(*args):
455 """With no arguments, return a dictionary of all configuration
456 variables relevant for the current platform.
457
458 On Unix, this means every variable defined in Python's installed Makefile;
459 On Windows and Mac OS it's a much smaller set.
460
461 With arguments, return a list of values that result from looking up
462 each argument in the configuration variable dictionary.
463 """
Tarek Ziadéedacea32010-01-29 11:41:03 +0000464 global _CONFIG_VARS
465 if _CONFIG_VARS is None:
466 _CONFIG_VARS = {}
467 # Normalized versions of prefix and exec_prefix are handy to have;
468 # in fact, these are the standard versions used most places in the
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200469 # packaging module.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000470 _CONFIG_VARS['prefix'] = _PREFIX
471 _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX
472 _CONFIG_VARS['py_version'] = _PY_VERSION
473 _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT
474 _CONFIG_VARS['py_version_nodot'] = _PY_VERSION[0] + _PY_VERSION[2]
475 _CONFIG_VARS['base'] = _PREFIX
476 _CONFIG_VARS['platbase'] = _EXEC_PREFIX
Tarek Ziadéedacea32010-01-29 11:41:03 +0000477 _CONFIG_VARS['projectbase'] = _PROJECT_BASE
Barry Warsawd5eaa5f2010-11-25 01:34:47 +0000478 try:
479 _CONFIG_VARS['abiflags'] = sys.abiflags
480 except AttributeError:
481 # sys.abiflags may not be defined on all platforms.
482 _CONFIG_VARS['abiflags'] = ''
Tarek Ziadéedacea32010-01-29 11:41:03 +0000483
484 if os.name in ('nt', 'os2'):
485 _init_non_posix(_CONFIG_VARS)
486 if os.name == 'posix':
487 _init_posix(_CONFIG_VARS)
Ronald Oussoren4cda46a2010-05-08 10:49:43 +0000488 # Setting 'userbase' is done below the call to the
489 # init function to enable using 'get_config_var' in
490 # the init-function.
Éric Araujo2a7cc532011-11-07 09:18:30 +0100491 _CONFIG_VARS['userbase'] = _getuserbase()
Ronald Oussoren4cda46a2010-05-08 10:49:43 +0000492
Tarek Ziadéedacea32010-01-29 11:41:03 +0000493 if 'srcdir' not in _CONFIG_VARS:
494 _CONFIG_VARS['srcdir'] = _PROJECT_BASE
Ronald Oussorenab4fd612010-06-15 21:19:50 +0000495 else:
Victor Stinnerb103a932010-10-12 22:23:23 +0000496 _CONFIG_VARS['srcdir'] = _safe_realpath(_CONFIG_VARS['srcdir'])
Tarek Ziadéedacea32010-01-29 11:41:03 +0000497
Tarek Ziadéedacea32010-01-29 11:41:03 +0000498 # Convert srcdir into an absolute path if it appears necessary.
499 # Normally it is relative to the build directory. However, during
500 # testing, for example, we might be running a non-installed python
501 # from a different directory.
502 if _PYTHON_BUILD and os.name == "posix":
503 base = _PROJECT_BASE
Victor Stinnerb103a932010-10-12 22:23:23 +0000504 try:
505 cwd = os.getcwd()
506 except OSError:
507 cwd = None
Tarek Ziadéedacea32010-01-29 11:41:03 +0000508 if (not os.path.isabs(_CONFIG_VARS['srcdir']) and
Victor Stinnerb103a932010-10-12 22:23:23 +0000509 base != cwd):
Tarek Ziadéedacea32010-01-29 11:41:03 +0000510 # srcdir is relative and we are not in the same directory
511 # as the executable. Assume executable is in the build
512 # directory and make srcdir absolute.
513 srcdir = os.path.join(base, _CONFIG_VARS['srcdir'])
514 _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir)
515
516 if sys.platform == 'darwin':
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200517 kernel_version = os.uname()[2] # Kernel version (8.4.3)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000518 major_version = int(kernel_version.split('.')[0])
519
520 if major_version < 8:
521 # On Mac OS X before 10.4, check if -arch and -isysroot
522 # are in CFLAGS or LDFLAGS and remove them if they are.
523 # This is needed when building extensions on a 10.3 system
524 # using a universal build of python.
525 for key in ('LDFLAGS', 'BASECFLAGS',
526 # a number of derived variables. These need to be
527 # patched up as well.
528 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
529 flags = _CONFIG_VARS[key]
530 flags = re.sub('-arch\s+\w+\s', ' ', flags)
531 flags = re.sub('-isysroot [^ \t]*', ' ', flags)
532 _CONFIG_VARS[key] = flags
533 else:
534 # Allow the user to override the architecture flags using
535 # an environment variable.
536 # NOTE: This name was introduced by Apple in OSX 10.5 and
537 # is used by several scripting languages distributed with
538 # that OS release.
539 if 'ARCHFLAGS' in os.environ:
540 arch = os.environ['ARCHFLAGS']
541 for key in ('LDFLAGS', 'BASECFLAGS',
542 # a number of derived variables. These need to be
543 # patched up as well.
544 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
545
546 flags = _CONFIG_VARS[key]
547 flags = re.sub('-arch\s+\w+\s', ' ', flags)
548 flags = flags + ' ' + arch
549 _CONFIG_VARS[key] = flags
550
551 # If we're on OSX 10.5 or later and the user tries to
552 # compiles an extension using an SDK that is not present
553 # on the current machine it is better to not use an SDK
554 # than to fail.
555 #
556 # The major usecase for this is users using a Python.org
557 # binary installer on OSX 10.6: that installer uses
558 # the 10.4u SDK, but that SDK is not installed by default
559 # when you install Xcode.
560 #
561 CFLAGS = _CONFIG_VARS.get('CFLAGS', '')
562 m = re.search('-isysroot\s+(\S+)', CFLAGS)
563 if m is not None:
564 sdk = m.group(1)
565 if not os.path.exists(sdk):
566 for key in ('LDFLAGS', 'BASECFLAGS',
567 # a number of derived variables. These need to be
568 # patched up as well.
569 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
570
571 flags = _CONFIG_VARS[key]
572 flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags)
573 _CONFIG_VARS[key] = flags
574
575 if args:
576 vals = []
577 for name in args:
578 vals.append(_CONFIG_VARS.get(name))
579 return vals
580 else:
581 return _CONFIG_VARS
582
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200583
Tarek Ziadéedacea32010-01-29 11:41:03 +0000584def get_config_var(name):
585 """Return the value of a single variable using the dictionary returned by
586 'get_config_vars()'.
587
588 Equivalent to get_config_vars().get(name)
589 """
590 return get_config_vars().get(name)
591
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200592
Tarek Ziadéedacea32010-01-29 11:41:03 +0000593def get_platform():
594 """Return a string that identifies the current platform.
595
596 This is used mainly to distinguish platform-specific build directories and
597 platform-specific built distributions. Typically includes the OS name
598 and version and the architecture (as supplied by 'os.uname()'),
599 although the exact information included depends on the OS; eg. for IRIX
600 the architecture isn't particularly important (IRIX only runs on SGI
601 hardware), but for Linux the kernel version isn't particularly
602 important.
603
604 Examples of returned values:
605 linux-i586
606 linux-alpha (?)
607 solaris-2.6-sun4u
608 irix-5.3
609 irix64-6.2
610
611 Windows will return one of:
612 win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
613 win-ia64 (64bit Windows on Itanium)
614 win32 (all others - specifically, sys.platform is returned)
615
616 For other non-POSIX platforms, currently just returns 'sys.platform'.
617 """
Tarek Ziadéedacea32010-01-29 11:41:03 +0000618 if os.name == 'nt':
619 # sniff sys.version for architecture.
620 prefix = " bit ("
621 i = sys.version.find(prefix)
622 if i == -1:
623 return sys.platform
624 j = sys.version.find(")", i)
625 look = sys.version[i+len(prefix):j].lower()
626 if look == 'amd64':
627 return 'win-amd64'
628 if look == 'itanium':
629 return 'win-ia64'
630 return sys.platform
631
632 if os.name != "posix" or not hasattr(os, 'uname'):
633 # XXX what about the architecture? NT is Intel or Alpha,
634 # Mac OS is M68k or PPC, etc.
635 return sys.platform
636
637 # Try to distinguish various flavours of Unix
638 osname, host, release, version, machine = os.uname()
639
640 # Convert the OS name to lowercase, remove '/' characters
641 # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh")
642 osname = osname.lower().replace('/', '')
643 machine = machine.replace(' ', '_')
644 machine = machine.replace('/', '-')
645
646 if osname[:5] == "linux":
647 # At least on Linux/Intel, 'machine' is the processor --
648 # i386, etc.
649 # XXX what about Alpha, SPARC, etc?
650 return "%s-%s" % (osname, machine)
651 elif osname[:5] == "sunos":
652 if release[0] >= "5": # SunOS 5 == Solaris 2
653 osname = "solaris"
654 release = "%d.%s" % (int(release[0]) - 3, release[2:])
655 # fall through to standard osname-release-machine representation
656 elif osname[:4] == "irix": # could be "irix64"!
657 return "%s-%s" % (osname, release)
658 elif osname[:3] == "aix":
659 return "%s-%s.%s" % (osname, version, release)
660 elif osname[:6] == "cygwin":
661 osname = "cygwin"
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200662 rel_re = re.compile(r'[\d.]+')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000663 m = rel_re.match(release)
664 if m:
665 release = m.group()
666 elif osname[:6] == "darwin":
667 #
668 # For our purposes, we'll assume that the system version from
669 # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set
670 # to. This makes the compatibility story a bit more sane because the
671 # machine is going to compile and link as if it were
672 # MACOSX_DEPLOYMENT_TARGET.
673 cfgvars = get_config_vars()
Ronald Oussoren222e89a2011-05-15 16:46:11 +0200674 macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000675
Éric Araujo559b5f12011-05-25 18:21:43 +0200676 if True:
Tarek Ziadéedacea32010-01-29 11:41:03 +0000677 # Always calculate the release of the running machine,
678 # needed to determine if we can build fat binaries or not.
679
680 macrelease = macver
681 # Get the system version. Reading this plist is a documented
682 # way to get the system version (see the documentation for
683 # the Gestalt Manager)
684 try:
685 f = open('/System/Library/CoreServices/SystemVersion.plist')
686 except IOError:
687 # We're on a plain darwin box, fall back to the default
688 # behaviour.
689 pass
690 else:
Éric Araujobee5cef2010-11-05 23:51:56 +0000691 try:
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200692 m = re.search(r'<key>ProductUserVisibleVersion</key>\s*'
693 r'<string>(.*?)</string>', f.read())
Éric Araujobee5cef2010-11-05 23:51:56 +0000694 finally:
695 f.close()
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200696 if m is not None:
697 macrelease = '.'.join(m.group(1).split('.')[:2])
698 # else: fall back to the default behaviour
Tarek Ziadéedacea32010-01-29 11:41:03 +0000699
700 if not macver:
701 macver = macrelease
702
703 if macver:
704 release = macver
705 osname = "macosx"
706
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200707 if ((macrelease + '.') >= '10.4.' and
708 '-arch' in get_config_vars().get('CFLAGS', '').strip()):
Tarek Ziadéedacea32010-01-29 11:41:03 +0000709 # The universal build will build fat binaries, but not on
710 # systems before 10.4
711 #
712 # Try to detect 4-way universal builds, those have machine-type
713 # 'universal' instead of 'fat'.
714
715 machine = 'fat'
716 cflags = get_config_vars().get('CFLAGS')
717
718 archs = re.findall('-arch\s+(\S+)', cflags)
Ronald Oussorend3950522010-07-11 09:05:07 +0000719 archs = tuple(sorted(set(archs)))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000720
721 if len(archs) == 1:
722 machine = archs[0]
723 elif archs == ('i386', 'ppc'):
724 machine = 'fat'
725 elif archs == ('i386', 'x86_64'):
726 machine = 'intel'
727 elif archs == ('i386', 'ppc', 'x86_64'):
728 machine = 'fat3'
729 elif archs == ('ppc64', 'x86_64'):
730 machine = 'fat64'
731 elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'):
732 machine = 'universal'
733 else:
734 raise ValueError(
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200735 "Don't know machine value for archs=%r" % (archs,))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000736
737 elif machine == 'i386':
738 # On OSX the machine type returned by uname is always the
739 # 32-bit variant, even if the executable architecture is
740 # the 64-bit variant
741 if sys.maxsize >= 2**32:
742 machine = 'x86_64'
743
744 elif machine in ('PowerPC', 'Power_Macintosh'):
745 # Pick a sane name for the PPC architecture.
746 # See 'i386' case
747 if sys.maxsize >= 2**32:
748 machine = 'ppc64'
749 else:
750 machine = 'ppc'
751
752 return "%s-%s-%s" % (osname, release, machine)
753
754
755def get_python_version():
756 return _PY_VERSION_SHORT
Tarek Ziadéa7514992010-05-25 09:44:36 +0000757
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200758
Tarek Ziadéa7514992010-05-25 09:44:36 +0000759def _print_dict(title, data):
760 for index, (key, value) in enumerate(sorted(data.items())):
761 if index == 0:
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200762 print('%s: ' % (title))
763 print('\t%s = "%s"' % (key, value))
764
Tarek Ziadéa7514992010-05-25 09:44:36 +0000765
766def _main():
Éric Araujo300623d2010-11-22 01:19:20 +0000767 """Display all information sysconfig detains."""
Antoine Pitrou1e73a242011-10-18 17:52:24 +0200768 if '--generate-posix-vars' in sys.argv:
769 _generate_posix_vars()
770 return
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200771 print('Platform: "%s"' % get_platform())
772 print('Python version: "%s"' % get_python_version())
773 print('Current installation scheme: "%s"' % _get_default_scheme())
Éric Araujo559b5f12011-05-25 18:21:43 +0200774 print()
Tarek Ziadéa7514992010-05-25 09:44:36 +0000775 _print_dict('Paths', get_paths())
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200776 print()
Tarek Ziadéa7514992010-05-25 09:44:36 +0000777 _print_dict('Variables', get_config_vars())
778
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200779
Tarek Ziadéa7514992010-05-25 09:44:36 +0000780if __name__ == '__main__':
781 _main()