blob: 730d33dfe1ec775963eef40636f9d1d9b19d2f5a [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 sys
Florent Xiclunaa4707382010-03-11 00:05:17 +00005from os.path import pardir, realpath
Tarek Ziadéedacea32010-01-29 11:41:03 +00006
Barry Warsawebbef6f2010-09-20 15:29:53 +00007__all__ = [
8 'get_config_h_filename',
9 'get_config_var',
10 'get_config_vars',
11 'get_makefile_filename',
12 'get_path',
13 'get_path_names',
14 'get_paths',
15 'get_platform',
16 'get_python_version',
17 'get_scheme_names',
18 'parse_config_h',
Tarek Ziade1231a4e2011-05-19 13:07:25 +020019]
Tarek Ziadé16ed6cb2010-05-25 09:47:06 +000020
Ronald Oussoren49926cf2021-02-01 04:29:44 +010021# Keys for get_config_var() that are never converted to Python integers.
22_ALWAYS_STR = {
23 'MACOSX_DEPLOYMENT_TARGET',
24}
25
Éric Araujoec177c12012-06-24 03:27:43 -040026_INSTALL_SCHEMES = {
27 'posix_prefix': {
Victor Stinner8510f432020-03-10 09:53:09 +010028 'stdlib': '{installed_base}/{platlibdir}/python{py_version_short}',
29 'platstdlib': '{platbase}/{platlibdir}/python{py_version_short}',
Éric Araujoec177c12012-06-24 03:27:43 -040030 'purelib': '{base}/lib/python{py_version_short}/site-packages',
Victor Stinner8510f432020-03-10 09:53:09 +010031 'platlib': '{platbase}/{platlibdir}/python{py_version_short}/site-packages',
Éric Araujoec177c12012-06-24 03:27:43 -040032 'include':
33 '{installed_base}/include/python{py_version_short}{abiflags}',
34 'platinclude':
35 '{installed_platbase}/include/python{py_version_short}{abiflags}',
36 'scripts': '{base}/bin',
37 'data': '{base}',
38 },
39 'posix_home': {
40 'stdlib': '{installed_base}/lib/python',
41 'platstdlib': '{base}/lib/python',
42 'purelib': '{base}/lib/python',
43 'platlib': '{base}/lib/python',
44 'include': '{installed_base}/include/python',
45 'platinclude': '{installed_base}/include/python',
46 'scripts': '{base}/bin',
47 'data': '{base}',
48 },
49 'nt': {
50 'stdlib': '{installed_base}/Lib',
51 'platstdlib': '{base}/Lib',
52 'purelib': '{base}/Lib/site-packages',
53 'platlib': '{base}/Lib/site-packages',
54 'include': '{installed_base}/Include',
55 'platinclude': '{installed_base}/Include',
56 'scripts': '{base}/Scripts',
57 'data': '{base}',
58 },
pxinwrab74c012020-12-21 06:27:42 +080059 }
60
61
62# NOTE: site.py has copy of this function.
63# Sync it when modify this function.
64def _getuserbase():
65 env_base = os.environ.get("PYTHONUSERBASE", None)
66 if env_base:
67 return env_base
68
69 # VxWorks has no home directories
70 if sys.platform == "vxworks":
71 return None
72
73 def joinuser(*args):
74 return os.path.expanduser(os.path.join(*args))
75
76 if os.name == "nt":
77 base = os.environ.get("APPDATA") or "~"
78 return joinuser(base, "Python")
79
80 if sys.platform == "darwin" and sys._framework:
81 return joinuser("~", "Library", sys._framework,
Tzu-ping Chungd9251332021-04-27 16:45:55 +080082 f"{sys.version_info[0]}.{sys.version_info[1]}")
pxinwrab74c012020-12-21 06:27:42 +080083
84 return joinuser("~", ".local")
85
86_HAS_USER_BASE = (_getuserbase() is not None)
87
88if _HAS_USER_BASE:
89 _INSTALL_SCHEMES |= {
90 # NOTE: When modifying "purelib" scheme, update site._get_path() too.
91 'nt_user': {
92 'stdlib': '{userbase}/Python{py_version_nodot_plat}',
93 'platstdlib': '{userbase}/Python{py_version_nodot_plat}',
94 'purelib': '{userbase}/Python{py_version_nodot_plat}/site-packages',
95 'platlib': '{userbase}/Python{py_version_nodot_plat}/site-packages',
96 'include': '{userbase}/Python{py_version_nodot_plat}/Include',
97 'scripts': '{userbase}/Python{py_version_nodot_plat}/Scripts',
98 'data': '{userbase}',
99 },
100 'posix_user': {
101 'stdlib': '{userbase}/{platlibdir}/python{py_version_short}',
102 'platstdlib': '{userbase}/{platlibdir}/python{py_version_short}',
103 'purelib': '{userbase}/lib/python{py_version_short}/site-packages',
104 'platlib': '{userbase}/{platlibdir}/python{py_version_short}/site-packages',
105 'include': '{userbase}/include/python{py_version_short}',
106 'scripts': '{userbase}/bin',
107 'data': '{userbase}',
108 },
109 'osx_framework_user': {
110 'stdlib': '{userbase}/lib/python',
111 'platstdlib': '{userbase}/lib/python',
112 'purelib': '{userbase}/lib/python/site-packages',
113 'platlib': '{userbase}/lib/python/site-packages',
114 'include': '{userbase}/include',
115 'scripts': '{userbase}/bin',
116 'data': '{userbase}',
117 },
Éric Araujoec177c12012-06-24 03:27:43 -0400118 }
Tarek Ziadéedacea32010-01-29 11:41:03 +0000119
Éric Araujoec177c12012-06-24 03:27:43 -0400120_SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include',
121 'scripts', 'data')
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200122
Tarek Ziadéedacea32010-01-29 11:41:03 +0000123_PY_VERSION = sys.version.split()[0]
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800124_PY_VERSION_SHORT = f'{sys.version_info[0]}.{sys.version_info[1]}'
125_PY_VERSION_SHORT_NO_DOT = f'{sys.version_info[0]}{sys.version_info[1]}'
Tarek Ziadéedacea32010-01-29 11:41:03 +0000126_PREFIX = os.path.normpath(sys.prefix)
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100127_BASE_PREFIX = os.path.normpath(sys.base_prefix)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000128_EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100129_BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000130_CONFIG_VARS = None
131_USER_BASE = None
Victor Stinnerb103a932010-10-12 22:23:23 +0000132
Lumír 'Frenzy' Balhar90d02e52021-04-23 14:02:41 +0200133# Regexes needed for parsing Makefile (and similar syntaxes,
134# like old-style Setup files).
135_variable_rx = r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)"
136_findvar1_rx = r"\$\(([A-Za-z][A-Za-z0-9_]*)\)"
137_findvar2_rx = r"\${([A-Za-z][A-Za-z0-9_]*)}"
138
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200139
Victor Stinnerb103a932010-10-12 22:23:23 +0000140def _safe_realpath(path):
141 try:
142 return realpath(path)
143 except OSError:
144 return path
145
Victor Stinner171ba052010-03-12 14:20:59 +0000146if sys.executable:
Victor Stinnerb103a932010-10-12 22:23:23 +0000147 _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable))
Victor Stinner171ba052010-03-12 14:20:59 +0000148else:
149 # sys.executable can be empty if argv[0] has been changed and Python is
150 # unable to retrieve the real program name
Victor Stinnerb103a932010-10-12 22:23:23 +0000151 _PROJECT_BASE = _safe_realpath(os.getcwd())
Tarek Ziadéedacea32010-01-29 11:41:03 +0000152
Steve Dower65e4cb12014-11-22 12:54:57 -0800153if (os.name == 'nt' and
154 _PROJECT_BASE.lower().endswith(('\\pcbuild\\win32', '\\pcbuild\\amd64'))):
Victor Stinnerb103a932010-10-12 22:23:23 +0000155 _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
Tarek Ziadéedacea32010-01-29 11:41:03 +0000156
doko@ubuntu.com1abe1c52012-06-30 20:42:45 +0200157# set for cross builds
doko@ubuntu.com7e6c2e22012-06-30 22:35:00 +0200158if "_PYTHON_PROJECT_BASE" in os.environ:
159 _PROJECT_BASE = _safe_realpath(os.environ["_PYTHON_PROJECT_BASE"])
doko@ubuntu.com1abe1c52012-06-30 20:42:45 +0200160
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100161def _is_python_source_dir(d):
Antoine Pitrou961d54c2018-07-16 19:03:03 +0200162 for fn in ("Setup", "Setup.local"):
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100163 if os.path.isfile(os.path.join(d, "Modules", fn)):
Tarek Ziadéedacea32010-01-29 11:41:03 +0000164 return True
165 return False
166
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100167_sys_home = getattr(sys, '_home', None)
Steve Dower85e102a2019-02-04 17:15:13 -0800168
169if os.name == 'nt':
170 def _fix_pcbuild(d):
171 if d and os.path.normcase(d).startswith(
172 os.path.normcase(os.path.join(_PREFIX, "PCbuild"))):
173 return _PREFIX
174 return d
175 _PROJECT_BASE = _fix_pcbuild(_PROJECT_BASE)
176 _sys_home = _fix_pcbuild(_sys_home)
177
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100178def is_python_build(check_home=False):
179 if check_home and _sys_home:
180 return _is_python_source_dir(_sys_home)
181 return _is_python_source_dir(_PROJECT_BASE)
182
183_PYTHON_BUILD = is_python_build(True)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000184
Miss Islington (bot)1c454eb2021-05-24 16:13:19 -0700185if _PYTHON_BUILD:
186 for scheme in ('posix_prefix', 'posix_home'):
187 # On POSIX-y platofrms, Python will:
188 # - Build from .h files in 'headers' (which is only added to the
189 # scheme when building CPython)
190 # - Install .h files to 'include'
191 scheme = _INSTALL_SCHEMES[scheme]
192 scheme['headers'] = scheme['include']
193 scheme['include'] = '{srcdir}/Include'
194 scheme['platinclude'] = '{projectbase}/.'
195
196
Éric Araujoec177c12012-06-24 03:27:43 -0400197def _subst_vars(s, local_vars):
198 try:
199 return s.format(**local_vars)
Steve Dowerdd180012020-09-05 00:45:54 +0100200 except KeyError as var:
Éric Araujoec177c12012-06-24 03:27:43 -0400201 try:
202 return s.format(**os.environ)
Steve Dowerdd180012020-09-05 00:45:54 +0100203 except KeyError:
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800204 raise AttributeError(f'{var}') from None
Tarek Ziadéedacea32010-01-29 11:41:03 +0000205
206def _extend_dict(target_dict, other_dict):
207 target_keys = target_dict.keys()
208 for key, value in other_dict.items():
209 if key in target_keys:
210 continue
211 target_dict[key] = value
212
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200213
Tarek Ziadéedacea32010-01-29 11:41:03 +0000214def _expand_vars(scheme, vars):
215 res = {}
216 if vars is None:
217 vars = {}
218 _extend_dict(vars, get_config_vars())
219
Éric Araujoec177c12012-06-24 03:27:43 -0400220 for key, value in _INSTALL_SCHEMES[scheme].items():
Tarek Ziadéedacea32010-01-29 11:41:03 +0000221 if os.name in ('posix', 'nt'):
222 value = os.path.expanduser(value)
223 res[key] = os.path.normpath(_subst_vars(value, vars))
224 return res
225
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200226
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800227def _get_preferred_schemes():
228 if os.name == 'nt':
229 return {
230 'prefix': 'nt',
231 'home': 'posix_home',
232 'user': 'nt_user',
233 }
234 if sys.platform == 'darwin' and sys._framework:
235 return {
236 'prefix': 'posix_prefix',
237 'home': 'posix_home',
238 'user': 'osx_framework_user',
239 }
240 return {
241 'prefix': 'posix_prefix',
242 'home': 'posix_home',
243 'user': 'posix_user',
244 }
Tarek Ziadéedacea32010-01-29 11:41:03 +0000245
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200246
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800247def get_preferred_scheme(key):
248 scheme = _get_preferred_schemes()[key]
249 if scheme not in _INSTALL_SCHEMES:
250 raise ValueError(
251 f"{key!r} returned {scheme!r}, which is not a valid scheme "
252 f"on this platform"
253 )
254 return scheme
255
256
257def get_default_scheme():
258 return get_preferred_scheme('prefix')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000259
260
Lumír 'Frenzy' Balhar90d02e52021-04-23 14:02:41 +0200261def _parse_makefile(filename, vars=None, keep_unresolved=True):
Tarek Ziadéedacea32010-01-29 11:41:03 +0000262 """Parse a Makefile-style file.
263
264 A dictionary containing name/value pairs is returned. If an
265 optional dictionary is passed in as the second argument, it is
266 used instead of a new dictionary.
267 """
Christian Heimes8c9cd5a2013-10-12 00:24:55 +0200268 import re
Tarek Ziadéedacea32010-01-29 11:41:03 +0000269
270 if vars is None:
271 vars = {}
272 done = {}
273 notdone = {}
274
Inada Naoki3d4af4a2021-04-06 10:01:11 +0900275 with open(filename, encoding=sys.getfilesystemencoding(),
276 errors="surrogateescape") as f:
Tarek Ziadéedacea32010-01-29 11:41:03 +0000277 lines = f.readlines()
278
279 for line in lines:
280 if line.startswith('#') or line.strip() == '':
281 continue
Lumír 'Frenzy' Balhar90d02e52021-04-23 14:02:41 +0200282 m = re.match(_variable_rx, line)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000283 if m:
284 n, v = m.group(1, 2)
285 v = v.strip()
286 # `$$' is a literal `$' in make
287 tmpv = v.replace('$$', '')
288
289 if "$" in tmpv:
290 notdone[n] = v
291 else:
292 try:
Ronald Oussoren49926cf2021-02-01 04:29:44 +0100293 if n in _ALWAYS_STR:
294 raise ValueError
295
Tarek Ziadéedacea32010-01-29 11:41:03 +0000296 v = int(v)
297 except ValueError:
298 # insert literal `$'
299 done[n] = v.replace('$$', '$')
300 else:
301 done[n] = v
302
303 # do variable interpolation here
304 variables = list(notdone.keys())
305
Ronald Oussorend21886c2010-07-20 16:07:10 +0000306 # Variables with a 'PY_' prefix in the makefile. These need to
307 # be made available without that prefix through sysconfig.
308 # Special care is needed to ensure that variable expansion works, even
309 # if the expansion uses the name without a prefix.
310 renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')
311
Tarek Ziadéedacea32010-01-29 11:41:03 +0000312 while len(variables) > 0:
313 for name in tuple(variables):
314 value = notdone[name]
Lumír 'Frenzy' Balhar90d02e52021-04-23 14:02:41 +0200315 m1 = re.search(_findvar1_rx, value)
316 m2 = re.search(_findvar2_rx, value)
doko@ubuntu.comb2b12172016-01-11 21:41:40 +0100317 if m1 and m2:
318 m = m1 if m1.start() < m2.start() else m2
319 else:
320 m = m1 if m1 else m2
Tarek Ziadéedacea32010-01-29 11:41:03 +0000321 if m is not None:
322 n = m.group(1)
323 found = True
324 if n in done:
325 item = str(done[n])
326 elif n in notdone:
327 # get it on a subsequent round
328 found = False
329 elif n in os.environ:
330 # do it like make: fall back to environment
331 item = os.environ[n]
Ronald Oussorend21886c2010-07-20 16:07:10 +0000332
333 elif n in renamed_variables:
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200334 if (name.startswith('PY_') and
335 name[3:] in renamed_variables):
Ronald Oussorend21886c2010-07-20 16:07:10 +0000336 item = ""
337
338 elif 'PY_' + n in notdone:
339 found = False
340
341 else:
342 item = str(done['PY_' + n])
343
Tarek Ziadéedacea32010-01-29 11:41:03 +0000344 else:
345 done[n] = item = ""
Ronald Oussorend21886c2010-07-20 16:07:10 +0000346
Tarek Ziadéedacea32010-01-29 11:41:03 +0000347 if found:
348 after = value[m.end():]
349 value = value[:m.start()] + item + after
350 if "$" in after:
351 notdone[name] = value
352 else:
353 try:
Ronald Oussoren49926cf2021-02-01 04:29:44 +0100354 if name in _ALWAYS_STR:
355 raise ValueError
Tarek Ziadéedacea32010-01-29 11:41:03 +0000356 value = int(value)
357 except ValueError:
358 done[name] = value.strip()
359 else:
360 done[name] = value
361 variables.remove(name)
Ronald Oussorend21886c2010-07-20 16:07:10 +0000362
363 if name.startswith('PY_') \
Victor Stinner1273b7c2011-05-24 23:37:07 +0200364 and name[3:] in renamed_variables:
Ronald Oussorend21886c2010-07-20 16:07:10 +0000365
366 name = name[3:]
367 if name not in done:
368 done[name] = value
369
Tarek Ziadéedacea32010-01-29 11:41:03 +0000370 else:
Lumír 'Frenzy' Balhar90d02e52021-04-23 14:02:41 +0200371 # Adds unresolved variables to the done dict.
372 # This is disabled when called from distutils.sysconfig
373 if keep_unresolved:
374 done[name] = value
Victor Stinner1273b7c2011-05-24 23:37:07 +0200375 # bogus variable reference (e.g. "prefix=$/opt/python");
376 # just drop it since we can't deal
Tarek Ziadéedacea32010-01-29 11:41:03 +0000377 variables.remove(name)
378
Antoine Pitroudbec7802010-10-10 09:37:12 +0000379 # strip spurious spaces
380 for k, v in done.items():
381 if isinstance(v, str):
382 done[k] = v.strip()
383
Tarek Ziadéedacea32010-01-29 11:41:03 +0000384 # save the results in the global dictionary
385 vars.update(done)
386 return vars
387
Tarek Ziadéedacea32010-01-29 11:41:03 +0000388
Barry Warsawebbef6f2010-09-20 15:29:53 +0000389def get_makefile_filename():
Éric Araujo300623d2010-11-22 01:19:20 +0000390 """Return the path of the Makefile."""
Tarek Ziadéedacea32010-01-29 11:41:03 +0000391 if _PYTHON_BUILD:
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100392 return os.path.join(_sys_home or _PROJECT_BASE, "Makefile")
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200393 if hasattr(sys, 'abiflags'):
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800394 config_dir_name = f'config-{_PY_VERSION_SHORT}{sys.abiflags}'
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200395 else:
396 config_dir_name = 'config'
doko@ubuntu.com55532312016-06-14 08:55:19 +0200397 if hasattr(sys.implementation, '_multiarch'):
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800398 config_dir_name += f'-{sys.implementation._multiarch}'
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200399 return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000400
Zachary Warec4b53af2016-09-09 17:59:49 -0700401
Xavier de Gaye92dec542016-09-11 22:22:24 +0200402def _get_sysconfigdata_name():
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800403 multiarch = getattr(sys.implementation, '_multiarch', '')
404 return os.environ.get(
405 '_PYTHON_SYSCONFIGDATA_NAME',
406 f'_sysconfigdata_{sys.abiflags}_{sys.platform}_{multiarch}',
407 )
Zachary Warec4b53af2016-09-09 17:59:49 -0700408
409
Antoine Pitrou1e73a242011-10-18 17:52:24 +0200410def _generate_posix_vars():
411 """Generate the Python module containing build-time variables."""
412 import pprint
413 vars = {}
Tarek Ziadéedacea32010-01-29 11:41:03 +0000414 # load the installed Makefile:
Barry Warsawebbef6f2010-09-20 15:29:53 +0000415 makefile = get_makefile_filename()
Tarek Ziadéedacea32010-01-29 11:41:03 +0000416 try:
417 _parse_makefile(makefile, vars)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200418 except OSError as e:
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800419 msg = f"invalid Python installation: unable to open {makefile}"
Tarek Ziadéedacea32010-01-29 11:41:03 +0000420 if hasattr(e, "strerror"):
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800421 msg = f"{msg} ({e.strerror})"
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200422 raise OSError(msg)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000423 # load the installed pyconfig.h:
424 config_h = get_config_h_filename()
425 try:
Inada Naoki3d4af4a2021-04-06 10:01:11 +0900426 with open(config_h, encoding="utf-8") as f:
Antoine Pitroub86680e2010-10-14 21:15:17 +0000427 parse_config_h(f, vars)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200428 except OSError as e:
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800429 msg = f"invalid Python installation: unable to open {config_h}"
Tarek Ziadéedacea32010-01-29 11:41:03 +0000430 if hasattr(e, "strerror"):
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800431 msg = f"{msg} ({e.strerror})"
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200432 raise OSError(msg)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000433 # On AIX, there are wrong paths to the linker scripts in the Makefile
434 # -- these paths are relative to the Python source, but when installed
435 # the scripts are in another directory.
436 if _PYTHON_BUILD:
Antoine Pitrou0abb2182013-10-19 22:05:05 +0200437 vars['BLDSHARED'] = vars['LDSHARED']
Victor Stinner65651ea2011-10-20 00:41:21 +0200438
Trent Nelsonee528cc2012-10-17 04:23:50 -0400439 # There's a chicken-and-egg situation on OS X with regards to the
440 # _sysconfigdata module after the changes introduced by #15298:
441 # get_config_vars() is called by get_platform() as part of the
442 # `make pybuilddir.txt` target -- which is a precursor to the
443 # _sysconfigdata.py module being constructed. Unfortunately,
444 # get_config_vars() eventually calls _init_posix(), which attempts
Trent Nelsonecbe2a92012-10-17 18:03:24 -0400445 # to import _sysconfigdata, which we won't have built yet. In order
446 # for _init_posix() to work, if we're on Darwin, just mock up the
447 # _sysconfigdata module manually and populate it with the build vars.
448 # This is more than sufficient for ensuring the subsequent call to
449 # get_platform() succeeds.
Xavier de Gaye92dec542016-09-11 22:22:24 +0200450 name = _get_sysconfigdata_name()
Trent Nelsonecbe2a92012-10-17 18:03:24 -0400451 if 'darwin' in sys.platform:
Brett Cannonf15a59f2013-06-15 14:32:11 -0400452 import types
453 module = types.ModuleType(name)
Trent Nelsonecbe2a92012-10-17 18:03:24 -0400454 module.build_time_vars = vars
455 sys.modules[name] = module
Tarek Ziadéedacea32010-01-29 11:41:03 +0000456
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800457 pybuilddir = f'build/lib.{get_platform()}-{_PY_VERSION_SHORT}'
Trent Nelsonee528cc2012-10-17 04:23:50 -0400458 if hasattr(sys, "gettotalrefcount"):
459 pybuilddir += '-pydebug'
460 os.makedirs(pybuilddir, exist_ok=True)
Trent Nelsonecbe2a92012-10-17 18:03:24 -0400461 destfile = os.path.join(pybuilddir, name + '.py')
Trent Nelsonee528cc2012-10-17 04:23:50 -0400462
Trent Nelsonecbe2a92012-10-17 18:03:24 -0400463 with open(destfile, 'w', encoding='utf8') as f:
464 f.write('# system configuration generated and used by'
465 ' the sysconfig module\n')
466 f.write('build_time_vars = ')
467 pprint.pprint(vars, stream=f)
Trent Nelsonee528cc2012-10-17 04:23:50 -0400468
Trent Nelsonc101bf32012-10-16 08:13:12 -0400469 # Create file used for sys.path fixup -- see Modules/getpath.c
Victor Stinner52ad33a2019-09-25 02:10:35 +0200470 with open('pybuilddir.txt', 'w', encoding='utf8') as f:
Trent Nelsonc101bf32012-10-16 08:13:12 -0400471 f.write(pybuilddir)
472
Antoine Pitrou1e73a242011-10-18 17:52:24 +0200473def _init_posix(vars):
474 """Initialize the module as appropriate for POSIX systems."""
475 # _sysconfigdata is generated at build time, see _generate_posix_vars()
Zachary Warec4b53af2016-09-09 17:59:49 -0700476 name = _get_sysconfigdata_name()
doko@ubuntu.com55532312016-06-14 08:55:19 +0200477 _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0)
478 build_time_vars = _temp.build_time_vars
Antoine Pitrou1e73a242011-10-18 17:52:24 +0200479 vars.update(build_time_vars)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200480
Tarek Ziadéedacea32010-01-29 11:41:03 +0000481def _init_non_posix(vars):
482 """Initialize the module as appropriate for NT"""
483 # set basic install directories
Matti Picusc0afb7f2020-12-07 19:33:20 +0200484 import _imp
Tarek Ziadéedacea32010-01-29 11:41:03 +0000485 vars['LIBDEST'] = get_path('stdlib')
486 vars['BINLIBDEST'] = get_path('platstdlib')
487 vars['INCLUDEPY'] = get_path('include')
Matti Picusc0afb7f2020-12-07 19:33:20 +0200488 vars['EXT_SUFFIX'] = _imp.extension_suffixes()[0]
Tarek Ziadéedacea32010-01-29 11:41:03 +0000489 vars['EXE'] = '.exe'
490 vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
Victor Stinnerb103a932010-10-12 22:23:23 +0000491 vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))
Steve Dowerdd180012020-09-05 00:45:54 +0100492 vars['TZPATH'] = ''
Tarek Ziadéedacea32010-01-29 11:41:03 +0000493
494#
495# public APIs
496#
497
Tarek Ziadébd797682010-02-02 23:16:13 +0000498
499def parse_config_h(fp, vars=None):
500 """Parse a config.h-style file.
501
502 A dictionary containing name/value pairs is returned. If an
503 optional dictionary is passed in as the second argument, it is
504 used instead of a new dictionary.
505 """
Tarek Ziadébd797682010-02-02 23:16:13 +0000506 if vars is None:
507 vars = {}
Christian Heimes8c9cd5a2013-10-12 00:24:55 +0200508 import re
Tarek Ziadébd797682010-02-02 23:16:13 +0000509 define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
510 undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
511
512 while True:
513 line = fp.readline()
514 if not line:
515 break
516 m = define_rx.match(line)
517 if m:
518 n, v = m.group(1, 2)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200519 try:
Ronald Oussoren49926cf2021-02-01 04:29:44 +0100520 if n in _ALWAYS_STR:
521 raise ValueError
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200522 v = int(v)
523 except ValueError:
524 pass
Tarek Ziadébd797682010-02-02 23:16:13 +0000525 vars[n] = v
526 else:
527 m = undef_rx.match(line)
528 if m:
529 vars[m.group(1)] = 0
530 return vars
531
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200532
Tarek Ziadébd797682010-02-02 23:16:13 +0000533def get_config_h_filename():
Éric Araujo300623d2010-11-22 01:19:20 +0000534 """Return the path of pyconfig.h."""
Tarek Ziadébd797682010-02-02 23:16:13 +0000535 if _PYTHON_BUILD:
536 if os.name == "nt":
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100537 inc_dir = os.path.join(_sys_home or _PROJECT_BASE, "PC")
Tarek Ziadébd797682010-02-02 23:16:13 +0000538 else:
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100539 inc_dir = _sys_home or _PROJECT_BASE
Tarek Ziadébd797682010-02-02 23:16:13 +0000540 else:
541 inc_dir = get_path('platinclude')
542 return os.path.join(inc_dir, 'pyconfig.h')
543
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200544
Tarek Ziadéedacea32010-01-29 11:41:03 +0000545def get_scheme_names():
Éric Araujo300623d2010-11-22 01:19:20 +0000546 """Return a tuple containing the schemes names."""
Éric Araujoec177c12012-06-24 03:27:43 -0400547 return tuple(sorted(_INSTALL_SCHEMES))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200548
Tarek Ziadéedacea32010-01-29 11:41:03 +0000549
550def get_path_names():
Éric Araujo300623d2010-11-22 01:19:20 +0000551 """Return a tuple containing the paths names."""
Éric Araujoec177c12012-06-24 03:27:43 -0400552 return _SCHEME_KEYS
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200553
Tarek Ziadéedacea32010-01-29 11:41:03 +0000554
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800555def get_paths(scheme=get_default_scheme(), vars=None, expand=True):
Éric Araujo300623d2010-11-22 01:19:20 +0000556 """Return a mapping containing an install scheme.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000557
558 ``scheme`` is the install scheme name. If not provided, it will
559 return the default scheme for the current platform.
560 """
561 if expand:
562 return _expand_vars(scheme, vars)
563 else:
Éric Araujoec177c12012-06-24 03:27:43 -0400564 return _INSTALL_SCHEMES[scheme]
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200565
Tarek Ziadéedacea32010-01-29 11:41:03 +0000566
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800567def get_path(name, scheme=get_default_scheme(), vars=None, expand=True):
Éric Araujo300623d2010-11-22 01:19:20 +0000568 """Return a path corresponding to the scheme.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000569
570 ``scheme`` is the install scheme name.
571 """
572 return get_paths(scheme, vars, expand)[name]
573
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200574
Tarek Ziadéedacea32010-01-29 11:41:03 +0000575def get_config_vars(*args):
576 """With no arguments, return a dictionary of all configuration
577 variables relevant for the current platform.
578
579 On Unix, this means every variable defined in Python's installed Makefile;
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700580 On Windows it's a much smaller set.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000581
582 With arguments, return a list of values that result from looking up
583 each argument in the configuration variable dictionary.
584 """
Tarek Ziadéedacea32010-01-29 11:41:03 +0000585 global _CONFIG_VARS
586 if _CONFIG_VARS is None:
587 _CONFIG_VARS = {}
588 # Normalized versions of prefix and exec_prefix are handy to have;
589 # in fact, these are the standard versions used most places in the
Éric Araujo859aad62012-06-24 00:07:41 -0400590 # Distutils.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000591 _CONFIG_VARS['prefix'] = _PREFIX
592 _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX
593 _CONFIG_VARS['py_version'] = _PY_VERSION
594 _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT
Serhiy Storchaka885bdc42016-02-11 13:10:36 +0200595 _CONFIG_VARS['py_version_nodot'] = _PY_VERSION_SHORT_NO_DOT
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100596 _CONFIG_VARS['installed_base'] = _BASE_PREFIX
Tarek Ziadéedacea32010-01-29 11:41:03 +0000597 _CONFIG_VARS['base'] = _PREFIX
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100598 _CONFIG_VARS['installed_platbase'] = _BASE_EXEC_PREFIX
Tarek Ziadéedacea32010-01-29 11:41:03 +0000599 _CONFIG_VARS['platbase'] = _EXEC_PREFIX
Tarek Ziadéedacea32010-01-29 11:41:03 +0000600 _CONFIG_VARS['projectbase'] = _PROJECT_BASE
Victor Stinner8510f432020-03-10 09:53:09 +0100601 _CONFIG_VARS['platlibdir'] = sys.platlibdir
Barry Warsawd5eaa5f2010-11-25 01:34:47 +0000602 try:
603 _CONFIG_VARS['abiflags'] = sys.abiflags
604 except AttributeError:
605 # sys.abiflags may not be defined on all platforms.
606 _CONFIG_VARS['abiflags'] = ''
Steve Dowerdd180012020-09-05 00:45:54 +0100607 try:
608 _CONFIG_VARS['py_version_nodot_plat'] = sys.winver.replace('.', '')
609 except AttributeError:
610 _CONFIG_VARS['py_version_nodot_plat'] = ''
Tarek Ziadéedacea32010-01-29 11:41:03 +0000611
Jesus Cea4791a242012-10-05 03:15:39 +0200612 if os.name == 'nt':
Tarek Ziadéedacea32010-01-29 11:41:03 +0000613 _init_non_posix(_CONFIG_VARS)
614 if os.name == 'posix':
615 _init_posix(_CONFIG_VARS)
Barry Warsaw87b96372013-11-22 11:08:05 -0500616 # For backward compatibility, see issue19555
617 SO = _CONFIG_VARS.get('EXT_SUFFIX')
618 if SO is not None:
619 _CONFIG_VARS['SO'] = SO
pxinwrab74c012020-12-21 06:27:42 +0800620 if _HAS_USER_BASE:
621 # Setting 'userbase' is done below the call to the
622 # init function to enable using 'get_config_var' in
623 # the init-function.
624 _CONFIG_VARS['userbase'] = _getuserbase()
Ronald Oussoren4cda46a2010-05-08 10:49:43 +0000625
Richard Oudkerk46874ad2012-07-27 12:06:55 +0100626 # Always convert srcdir to an absolute path
627 srcdir = _CONFIG_VARS.get('srcdir', _PROJECT_BASE)
628 if os.name == 'posix':
629 if _PYTHON_BUILD:
630 # If srcdir is a relative path (typically '.' or '..')
631 # then it should be interpreted relative to the directory
632 # containing Makefile.
633 base = os.path.dirname(get_makefile_filename())
634 srcdir = os.path.join(base, srcdir)
635 else:
636 # srcdir is not meaningful since the installation is
637 # spread about the filesystem. We choose the
638 # directory containing the Makefile since we know it
639 # exists.
640 srcdir = os.path.dirname(get_makefile_filename())
641 _CONFIG_VARS['srcdir'] = _safe_realpath(srcdir)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000642
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700643 # OS X platforms require special customization to handle
644 # multi-architecture, multi-os-version installers
Tarek Ziadéedacea32010-01-29 11:41:03 +0000645 if sys.platform == 'darwin':
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700646 import _osx_support
647 _osx_support.customize_config_vars(_CONFIG_VARS)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000648
649 if args:
650 vals = []
651 for name in args:
652 vals.append(_CONFIG_VARS.get(name))
653 return vals
654 else:
655 return _CONFIG_VARS
656
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200657
Tarek Ziadéedacea32010-01-29 11:41:03 +0000658def get_config_var(name):
659 """Return the value of a single variable using the dictionary returned by
660 'get_config_vars()'.
661
662 Equivalent to get_config_vars().get(name)
663 """
Barry Warsaw197a7702013-11-21 18:57:14 -0500664 if name == 'SO':
665 import warnings
Serhiy Storchakaeaec3592013-11-26 17:08:24 +0200666 warnings.warn('SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000667 return get_config_vars().get(name)
668
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200669
Tarek Ziadéedacea32010-01-29 11:41:03 +0000670def get_platform():
671 """Return a string that identifies the current platform.
672
673 This is used mainly to distinguish platform-specific build directories and
Benjamin Peterson06930632017-09-04 16:36:05 -0700674 platform-specific built distributions. Typically includes the OS name and
675 version and the architecture (as supplied by 'os.uname()'), although the
676 exact information included depends on the OS; on Linux, the kernel version
677 isn't particularly important.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000678
679 Examples of returned values:
680 linux-i586
681 linux-alpha (?)
682 solaris-2.6-sun4u
Tarek Ziadéedacea32010-01-29 11:41:03 +0000683
684 Windows will return one of:
685 win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000686 win32 (all others - specifically, sys.platform is returned)
687
688 For other non-POSIX platforms, currently just returns 'sys.platform'.
Benjamin Peterson06930632017-09-04 16:36:05 -0700689
Tarek Ziadéedacea32010-01-29 11:41:03 +0000690 """
Tarek Ziadéedacea32010-01-29 11:41:03 +0000691 if os.name == 'nt':
Zachary Ware49ce74e2017-09-06 15:45:25 -0700692 if 'amd64' in sys.version.lower():
Tarek Ziadéedacea32010-01-29 11:41:03 +0000693 return 'win-amd64'
Paul Monson62dfd7d2019-04-25 11:36:45 -0700694 if '(arm)' in sys.version.lower():
695 return 'win-arm32'
Paul Monsondaf62622019-06-12 10:16:49 -0700696 if '(arm64)' in sys.version.lower():
697 return 'win-arm64'
Tarek Ziadéedacea32010-01-29 11:41:03 +0000698 return sys.platform
699
700 if os.name != "posix" or not hasattr(os, 'uname'):
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700701 # XXX what about the architecture? NT is Intel or Alpha
Tarek Ziadéedacea32010-01-29 11:41:03 +0000702 return sys.platform
703
doko@ubuntu.com1abe1c52012-06-30 20:42:45 +0200704 # Set for cross builds explicitly
705 if "_PYTHON_HOST_PLATFORM" in os.environ:
706 return os.environ["_PYTHON_HOST_PLATFORM"]
707
Tarek Ziadéedacea32010-01-29 11:41:03 +0000708 # Try to distinguish various flavours of Unix
709 osname, host, release, version, machine = os.uname()
710
Benjamin Peterson288d1da2017-09-28 22:44:27 -0700711 # Convert the OS name to lowercase, remove '/' characters, and translate
712 # spaces (for "Power Macintosh")
Tarek Ziadéedacea32010-01-29 11:41:03 +0000713 osname = osname.lower().replace('/', '')
714 machine = machine.replace(' ', '_')
715 machine = machine.replace('/', '-')
716
717 if osname[:5] == "linux":
718 # At least on Linux/Intel, 'machine' is the processor --
719 # i386, etc.
720 # XXX what about Alpha, SPARC, etc?
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800721 return f"{osname}-{machine}"
Tarek Ziadéedacea32010-01-29 11:41:03 +0000722 elif osname[:5] == "sunos":
723 if release[0] >= "5": # SunOS 5 == Solaris 2
724 osname = "solaris"
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800725 release = f"{int(release[0]) - 3}.{release[2:]}"
Jesus Cea1aa1cf32012-01-18 04:49:26 +0100726 # We can't use "platform.architecture()[0]" because a
727 # bootstrap problem. We use a dict to get an error
728 # if some suspicious happens.
729 bitness = {2147483647:"32bit", 9223372036854775807:"64bit"}
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800730 machine += f".{bitness[sys.maxsize]}"
Tarek Ziadéedacea32010-01-29 11:41:03 +0000731 # fall through to standard osname-release-machine representation
Tarek Ziadéedacea32010-01-29 11:41:03 +0000732 elif osname[:3] == "aix":
Michael Felt39afa2d2019-12-15 15:17:53 +0100733 from _aix_support import aix_platform
734 return aix_platform()
Tarek Ziadéedacea32010-01-29 11:41:03 +0000735 elif osname[:6] == "cygwin":
736 osname = "cygwin"
Christian Heimes8c9cd5a2013-10-12 00:24:55 +0200737 import re
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200738 rel_re = re.compile(r'[\d.]+')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000739 m = rel_re.match(release)
740 if m:
741 release = m.group()
742 elif osname[:6] == "darwin":
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700743 import _osx_support
744 osname, release, machine = _osx_support.get_platform_osx(
745 get_config_vars(),
746 osname, release, machine)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000747
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800748 return f"{osname}-{release}-{machine}"
Tarek Ziadéedacea32010-01-29 11:41:03 +0000749
750
751def get_python_version():
752 return _PY_VERSION_SHORT
Tarek Ziadéa7514992010-05-25 09:44:36 +0000753
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200754
Lumír 'Frenzy' Balhar90d02e52021-04-23 14:02:41 +0200755def expand_makefile_vars(s, vars):
756 """Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in
757 'string' according to 'vars' (a dictionary mapping variable names to
758 values). Variables not present in 'vars' are silently expanded to the
759 empty string. The variable values in 'vars' should not contain further
760 variable expansions; if 'vars' is the output of 'parse_makefile()',
761 you're fine. Returns a variable-expanded version of 's'.
762 """
763 import re
764
765 # This algorithm does multiple expansion, so if vars['foo'] contains
766 # "${bar}", it will expand ${foo} to ${bar}, and then expand
767 # ${bar}... and so forth. This is fine as long as 'vars' comes from
768 # 'parse_makefile()', which takes care of such expansions eagerly,
769 # according to make's variable expansion semantics.
770
771 while True:
772 m = re.search(_findvar1_rx, s) or re.search(_findvar2_rx, s)
773 if m:
774 (beg, end) = m.span()
775 s = s[0:beg] + vars.get(m.group(1)) + s[end:]
776 else:
777 break
778 return s
779
780
Tarek Ziadéa7514992010-05-25 09:44:36 +0000781def _print_dict(title, data):
782 for index, (key, value) in enumerate(sorted(data.items())):
783 if index == 0:
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800784 print(f'{title}: ')
785 print(f'\t{key} = "{value}"')
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200786
Tarek Ziadéa7514992010-05-25 09:44:36 +0000787
788def _main():
Éric Araujo300623d2010-11-22 01:19:20 +0000789 """Display all information sysconfig detains."""
Antoine Pitrou1e73a242011-10-18 17:52:24 +0200790 if '--generate-posix-vars' in sys.argv:
791 _generate_posix_vars()
792 return
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800793 print(f'Platform: "{get_platform()}"')
794 print(f'Python version: "{get_python_version()}"')
795 print(f'Current installation scheme: "{get_default_scheme()}"')
Éric Araujo559b5f12011-05-25 18:21:43 +0200796 print()
Tarek Ziadéa7514992010-05-25 09:44:36 +0000797 _print_dict('Paths', get_paths())
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200798 print()
Tarek Ziadéa7514992010-05-25 09:44:36 +0000799 _print_dict('Variables', get_config_vars())
800
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200801
Tarek Ziadéa7514992010-05-25 09:44:36 +0000802if __name__ == '__main__':
803 _main()