blob: e8869af0b5cc9422038c8c0fe33e1796745ef8a7 [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
Éric Araujoec177c12012-06-24 03:27:43 -0400185def _subst_vars(s, local_vars):
186 try:
187 return s.format(**local_vars)
Steve Dowerdd180012020-09-05 00:45:54 +0100188 except KeyError as var:
Éric Araujoec177c12012-06-24 03:27:43 -0400189 try:
190 return s.format(**os.environ)
Steve Dowerdd180012020-09-05 00:45:54 +0100191 except KeyError:
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800192 raise AttributeError(f'{var}') from None
Tarek Ziadéedacea32010-01-29 11:41:03 +0000193
194def _extend_dict(target_dict, other_dict):
195 target_keys = target_dict.keys()
196 for key, value in other_dict.items():
197 if key in target_keys:
198 continue
199 target_dict[key] = value
200
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200201
Tarek Ziadéedacea32010-01-29 11:41:03 +0000202def _expand_vars(scheme, vars):
203 res = {}
204 if vars is None:
205 vars = {}
206 _extend_dict(vars, get_config_vars())
207
Éric Araujoec177c12012-06-24 03:27:43 -0400208 for key, value in _INSTALL_SCHEMES[scheme].items():
Tarek Ziadéedacea32010-01-29 11:41:03 +0000209 if os.name in ('posix', 'nt'):
210 value = os.path.expanduser(value)
211 res[key] = os.path.normpath(_subst_vars(value, vars))
212 return res
213
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200214
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800215def _get_preferred_schemes():
216 if os.name == 'nt':
217 return {
218 'prefix': 'nt',
219 'home': 'posix_home',
220 'user': 'nt_user',
221 }
222 if sys.platform == 'darwin' and sys._framework:
223 return {
224 'prefix': 'posix_prefix',
225 'home': 'posix_home',
226 'user': 'osx_framework_user',
227 }
228 return {
229 'prefix': 'posix_prefix',
230 'home': 'posix_home',
231 'user': 'posix_user',
232 }
Tarek Ziadéedacea32010-01-29 11:41:03 +0000233
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200234
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800235def get_preferred_scheme(key):
236 scheme = _get_preferred_schemes()[key]
237 if scheme not in _INSTALL_SCHEMES:
238 raise ValueError(
239 f"{key!r} returned {scheme!r}, which is not a valid scheme "
240 f"on this platform"
241 )
242 return scheme
243
244
245def get_default_scheme():
246 return get_preferred_scheme('prefix')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000247
248
Lumír 'Frenzy' Balhar90d02e52021-04-23 14:02:41 +0200249def _parse_makefile(filename, vars=None, keep_unresolved=True):
Tarek Ziadéedacea32010-01-29 11:41:03 +0000250 """Parse a Makefile-style file.
251
252 A dictionary containing name/value pairs is returned. If an
253 optional dictionary is passed in as the second argument, it is
254 used instead of a new dictionary.
255 """
Christian Heimes8c9cd5a2013-10-12 00:24:55 +0200256 import re
Tarek Ziadéedacea32010-01-29 11:41:03 +0000257
258 if vars is None:
259 vars = {}
260 done = {}
261 notdone = {}
262
Inada Naoki3d4af4a2021-04-06 10:01:11 +0900263 with open(filename, encoding=sys.getfilesystemencoding(),
264 errors="surrogateescape") as f:
Tarek Ziadéedacea32010-01-29 11:41:03 +0000265 lines = f.readlines()
266
267 for line in lines:
268 if line.startswith('#') or line.strip() == '':
269 continue
Lumír 'Frenzy' Balhar90d02e52021-04-23 14:02:41 +0200270 m = re.match(_variable_rx, line)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000271 if m:
272 n, v = m.group(1, 2)
273 v = v.strip()
274 # `$$' is a literal `$' in make
275 tmpv = v.replace('$$', '')
276
277 if "$" in tmpv:
278 notdone[n] = v
279 else:
280 try:
Ronald Oussoren49926cf2021-02-01 04:29:44 +0100281 if n in _ALWAYS_STR:
282 raise ValueError
283
Tarek Ziadéedacea32010-01-29 11:41:03 +0000284 v = int(v)
285 except ValueError:
286 # insert literal `$'
287 done[n] = v.replace('$$', '$')
288 else:
289 done[n] = v
290
291 # do variable interpolation here
292 variables = list(notdone.keys())
293
Ronald Oussorend21886c2010-07-20 16:07:10 +0000294 # Variables with a 'PY_' prefix in the makefile. These need to
295 # be made available without that prefix through sysconfig.
296 # Special care is needed to ensure that variable expansion works, even
297 # if the expansion uses the name without a prefix.
298 renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')
299
Tarek Ziadéedacea32010-01-29 11:41:03 +0000300 while len(variables) > 0:
301 for name in tuple(variables):
302 value = notdone[name]
Lumír 'Frenzy' Balhar90d02e52021-04-23 14:02:41 +0200303 m1 = re.search(_findvar1_rx, value)
304 m2 = re.search(_findvar2_rx, value)
doko@ubuntu.comb2b12172016-01-11 21:41:40 +0100305 if m1 and m2:
306 m = m1 if m1.start() < m2.start() else m2
307 else:
308 m = m1 if m1 else m2
Tarek Ziadéedacea32010-01-29 11:41:03 +0000309 if m is not None:
310 n = m.group(1)
311 found = True
312 if n in done:
313 item = str(done[n])
314 elif n in notdone:
315 # get it on a subsequent round
316 found = False
317 elif n in os.environ:
318 # do it like make: fall back to environment
319 item = os.environ[n]
Ronald Oussorend21886c2010-07-20 16:07:10 +0000320
321 elif n in renamed_variables:
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200322 if (name.startswith('PY_') and
323 name[3:] in renamed_variables):
Ronald Oussorend21886c2010-07-20 16:07:10 +0000324 item = ""
325
326 elif 'PY_' + n in notdone:
327 found = False
328
329 else:
330 item = str(done['PY_' + n])
331
Tarek Ziadéedacea32010-01-29 11:41:03 +0000332 else:
333 done[n] = item = ""
Ronald Oussorend21886c2010-07-20 16:07:10 +0000334
Tarek Ziadéedacea32010-01-29 11:41:03 +0000335 if found:
336 after = value[m.end():]
337 value = value[:m.start()] + item + after
338 if "$" in after:
339 notdone[name] = value
340 else:
341 try:
Ronald Oussoren49926cf2021-02-01 04:29:44 +0100342 if name in _ALWAYS_STR:
343 raise ValueError
Tarek Ziadéedacea32010-01-29 11:41:03 +0000344 value = int(value)
345 except ValueError:
346 done[name] = value.strip()
347 else:
348 done[name] = value
349 variables.remove(name)
Ronald Oussorend21886c2010-07-20 16:07:10 +0000350
351 if name.startswith('PY_') \
Victor Stinner1273b7c2011-05-24 23:37:07 +0200352 and name[3:] in renamed_variables:
Ronald Oussorend21886c2010-07-20 16:07:10 +0000353
354 name = name[3:]
355 if name not in done:
356 done[name] = value
357
Tarek Ziadéedacea32010-01-29 11:41:03 +0000358 else:
Lumír 'Frenzy' Balhar90d02e52021-04-23 14:02:41 +0200359 # Adds unresolved variables to the done dict.
360 # This is disabled when called from distutils.sysconfig
361 if keep_unresolved:
362 done[name] = value
Victor Stinner1273b7c2011-05-24 23:37:07 +0200363 # bogus variable reference (e.g. "prefix=$/opt/python");
364 # just drop it since we can't deal
Tarek Ziadéedacea32010-01-29 11:41:03 +0000365 variables.remove(name)
366
Antoine Pitroudbec7802010-10-10 09:37:12 +0000367 # strip spurious spaces
368 for k, v in done.items():
369 if isinstance(v, str):
370 done[k] = v.strip()
371
Tarek Ziadéedacea32010-01-29 11:41:03 +0000372 # save the results in the global dictionary
373 vars.update(done)
374 return vars
375
Tarek Ziadéedacea32010-01-29 11:41:03 +0000376
Barry Warsawebbef6f2010-09-20 15:29:53 +0000377def get_makefile_filename():
Éric Araujo300623d2010-11-22 01:19:20 +0000378 """Return the path of the Makefile."""
Tarek Ziadéedacea32010-01-29 11:41:03 +0000379 if _PYTHON_BUILD:
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100380 return os.path.join(_sys_home or _PROJECT_BASE, "Makefile")
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200381 if hasattr(sys, 'abiflags'):
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800382 config_dir_name = f'config-{_PY_VERSION_SHORT}{sys.abiflags}'
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200383 else:
384 config_dir_name = 'config'
doko@ubuntu.com55532312016-06-14 08:55:19 +0200385 if hasattr(sys.implementation, '_multiarch'):
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800386 config_dir_name += f'-{sys.implementation._multiarch}'
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200387 return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000388
Zachary Warec4b53af2016-09-09 17:59:49 -0700389
Xavier de Gaye92dec542016-09-11 22:22:24 +0200390def _get_sysconfigdata_name():
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800391 multiarch = getattr(sys.implementation, '_multiarch', '')
392 return os.environ.get(
393 '_PYTHON_SYSCONFIGDATA_NAME',
394 f'_sysconfigdata_{sys.abiflags}_{sys.platform}_{multiarch}',
395 )
Zachary Warec4b53af2016-09-09 17:59:49 -0700396
397
Antoine Pitrou1e73a242011-10-18 17:52:24 +0200398def _generate_posix_vars():
399 """Generate the Python module containing build-time variables."""
400 import pprint
401 vars = {}
Tarek Ziadéedacea32010-01-29 11:41:03 +0000402 # load the installed Makefile:
Barry Warsawebbef6f2010-09-20 15:29:53 +0000403 makefile = get_makefile_filename()
Tarek Ziadéedacea32010-01-29 11:41:03 +0000404 try:
405 _parse_makefile(makefile, vars)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200406 except OSError as e:
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800407 msg = f"invalid Python installation: unable to open {makefile}"
Tarek Ziadéedacea32010-01-29 11:41:03 +0000408 if hasattr(e, "strerror"):
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800409 msg = f"{msg} ({e.strerror})"
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200410 raise OSError(msg)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000411 # load the installed pyconfig.h:
412 config_h = get_config_h_filename()
413 try:
Inada Naoki3d4af4a2021-04-06 10:01:11 +0900414 with open(config_h, encoding="utf-8") as f:
Antoine Pitroub86680e2010-10-14 21:15:17 +0000415 parse_config_h(f, vars)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200416 except OSError as e:
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800417 msg = f"invalid Python installation: unable to open {config_h}"
Tarek Ziadéedacea32010-01-29 11:41:03 +0000418 if hasattr(e, "strerror"):
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800419 msg = f"{msg} ({e.strerror})"
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200420 raise OSError(msg)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000421 # On AIX, there are wrong paths to the linker scripts in the Makefile
422 # -- these paths are relative to the Python source, but when installed
423 # the scripts are in another directory.
424 if _PYTHON_BUILD:
Antoine Pitrou0abb2182013-10-19 22:05:05 +0200425 vars['BLDSHARED'] = vars['LDSHARED']
Victor Stinner65651ea2011-10-20 00:41:21 +0200426
Trent Nelsonee528cc2012-10-17 04:23:50 -0400427 # There's a chicken-and-egg situation on OS X with regards to the
428 # _sysconfigdata module after the changes introduced by #15298:
429 # get_config_vars() is called by get_platform() as part of the
430 # `make pybuilddir.txt` target -- which is a precursor to the
431 # _sysconfigdata.py module being constructed. Unfortunately,
432 # get_config_vars() eventually calls _init_posix(), which attempts
Trent Nelsonecbe2a92012-10-17 18:03:24 -0400433 # to import _sysconfigdata, which we won't have built yet. In order
434 # for _init_posix() to work, if we're on Darwin, just mock up the
435 # _sysconfigdata module manually and populate it with the build vars.
436 # This is more than sufficient for ensuring the subsequent call to
437 # get_platform() succeeds.
Xavier de Gaye92dec542016-09-11 22:22:24 +0200438 name = _get_sysconfigdata_name()
Trent Nelsonecbe2a92012-10-17 18:03:24 -0400439 if 'darwin' in sys.platform:
Brett Cannonf15a59f2013-06-15 14:32:11 -0400440 import types
441 module = types.ModuleType(name)
Trent Nelsonecbe2a92012-10-17 18:03:24 -0400442 module.build_time_vars = vars
443 sys.modules[name] = module
Tarek Ziadéedacea32010-01-29 11:41:03 +0000444
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800445 pybuilddir = f'build/lib.{get_platform()}-{_PY_VERSION_SHORT}'
Trent Nelsonee528cc2012-10-17 04:23:50 -0400446 if hasattr(sys, "gettotalrefcount"):
447 pybuilddir += '-pydebug'
448 os.makedirs(pybuilddir, exist_ok=True)
Trent Nelsonecbe2a92012-10-17 18:03:24 -0400449 destfile = os.path.join(pybuilddir, name + '.py')
Trent Nelsonee528cc2012-10-17 04:23:50 -0400450
Trent Nelsonecbe2a92012-10-17 18:03:24 -0400451 with open(destfile, 'w', encoding='utf8') as f:
452 f.write('# system configuration generated and used by'
453 ' the sysconfig module\n')
454 f.write('build_time_vars = ')
455 pprint.pprint(vars, stream=f)
Trent Nelsonee528cc2012-10-17 04:23:50 -0400456
Trent Nelsonc101bf32012-10-16 08:13:12 -0400457 # Create file used for sys.path fixup -- see Modules/getpath.c
Victor Stinner52ad33a2019-09-25 02:10:35 +0200458 with open('pybuilddir.txt', 'w', encoding='utf8') as f:
Trent Nelsonc101bf32012-10-16 08:13:12 -0400459 f.write(pybuilddir)
460
Antoine Pitrou1e73a242011-10-18 17:52:24 +0200461def _init_posix(vars):
462 """Initialize the module as appropriate for POSIX systems."""
463 # _sysconfigdata is generated at build time, see _generate_posix_vars()
Zachary Warec4b53af2016-09-09 17:59:49 -0700464 name = _get_sysconfigdata_name()
doko@ubuntu.com55532312016-06-14 08:55:19 +0200465 _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0)
466 build_time_vars = _temp.build_time_vars
Antoine Pitrou1e73a242011-10-18 17:52:24 +0200467 vars.update(build_time_vars)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200468
Tarek Ziadéedacea32010-01-29 11:41:03 +0000469def _init_non_posix(vars):
470 """Initialize the module as appropriate for NT"""
471 # set basic install directories
Matti Picusc0afb7f2020-12-07 19:33:20 +0200472 import _imp
Tarek Ziadéedacea32010-01-29 11:41:03 +0000473 vars['LIBDEST'] = get_path('stdlib')
474 vars['BINLIBDEST'] = get_path('platstdlib')
475 vars['INCLUDEPY'] = get_path('include')
Matti Picusc0afb7f2020-12-07 19:33:20 +0200476 vars['EXT_SUFFIX'] = _imp.extension_suffixes()[0]
Tarek Ziadéedacea32010-01-29 11:41:03 +0000477 vars['EXE'] = '.exe'
478 vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
Victor Stinnerb103a932010-10-12 22:23:23 +0000479 vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))
Steve Dowerdd180012020-09-05 00:45:54 +0100480 vars['TZPATH'] = ''
Tarek Ziadéedacea32010-01-29 11:41:03 +0000481
482#
483# public APIs
484#
485
Tarek Ziadébd797682010-02-02 23:16:13 +0000486
487def parse_config_h(fp, vars=None):
488 """Parse a config.h-style file.
489
490 A dictionary containing name/value pairs is returned. If an
491 optional dictionary is passed in as the second argument, it is
492 used instead of a new dictionary.
493 """
Tarek Ziadébd797682010-02-02 23:16:13 +0000494 if vars is None:
495 vars = {}
Christian Heimes8c9cd5a2013-10-12 00:24:55 +0200496 import re
Tarek Ziadébd797682010-02-02 23:16:13 +0000497 define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
498 undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
499
500 while True:
501 line = fp.readline()
502 if not line:
503 break
504 m = define_rx.match(line)
505 if m:
506 n, v = m.group(1, 2)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200507 try:
Ronald Oussoren49926cf2021-02-01 04:29:44 +0100508 if n in _ALWAYS_STR:
509 raise ValueError
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200510 v = int(v)
511 except ValueError:
512 pass
Tarek Ziadébd797682010-02-02 23:16:13 +0000513 vars[n] = v
514 else:
515 m = undef_rx.match(line)
516 if m:
517 vars[m.group(1)] = 0
518 return vars
519
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200520
Tarek Ziadébd797682010-02-02 23:16:13 +0000521def get_config_h_filename():
Éric Araujo300623d2010-11-22 01:19:20 +0000522 """Return the path of pyconfig.h."""
Tarek Ziadébd797682010-02-02 23:16:13 +0000523 if _PYTHON_BUILD:
524 if os.name == "nt":
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100525 inc_dir = os.path.join(_sys_home or _PROJECT_BASE, "PC")
Tarek Ziadébd797682010-02-02 23:16:13 +0000526 else:
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100527 inc_dir = _sys_home or _PROJECT_BASE
Tarek Ziadébd797682010-02-02 23:16:13 +0000528 else:
529 inc_dir = get_path('platinclude')
530 return os.path.join(inc_dir, 'pyconfig.h')
531
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200532
Tarek Ziadéedacea32010-01-29 11:41:03 +0000533def get_scheme_names():
Éric Araujo300623d2010-11-22 01:19:20 +0000534 """Return a tuple containing the schemes names."""
Éric Araujoec177c12012-06-24 03:27:43 -0400535 return tuple(sorted(_INSTALL_SCHEMES))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200536
Tarek Ziadéedacea32010-01-29 11:41:03 +0000537
538def get_path_names():
Éric Araujo300623d2010-11-22 01:19:20 +0000539 """Return a tuple containing the paths names."""
Éric Araujoec177c12012-06-24 03:27:43 -0400540 return _SCHEME_KEYS
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200541
Tarek Ziadéedacea32010-01-29 11:41:03 +0000542
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800543def get_paths(scheme=get_default_scheme(), vars=None, expand=True):
Éric Araujo300623d2010-11-22 01:19:20 +0000544 """Return a mapping containing an install scheme.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000545
546 ``scheme`` is the install scheme name. If not provided, it will
547 return the default scheme for the current platform.
548 """
549 if expand:
550 return _expand_vars(scheme, vars)
551 else:
Éric Araujoec177c12012-06-24 03:27:43 -0400552 return _INSTALL_SCHEMES[scheme]
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_path(name, scheme=get_default_scheme(), vars=None, expand=True):
Éric Araujo300623d2010-11-22 01:19:20 +0000556 """Return a path corresponding to the scheme.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000557
558 ``scheme`` is the install scheme name.
559 """
560 return get_paths(scheme, vars, expand)[name]
561
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200562
Tarek Ziadéedacea32010-01-29 11:41:03 +0000563def get_config_vars(*args):
564 """With no arguments, return a dictionary of all configuration
565 variables relevant for the current platform.
566
567 On Unix, this means every variable defined in Python's installed Makefile;
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700568 On Windows it's a much smaller set.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000569
570 With arguments, return a list of values that result from looking up
571 each argument in the configuration variable dictionary.
572 """
Tarek Ziadéedacea32010-01-29 11:41:03 +0000573 global _CONFIG_VARS
574 if _CONFIG_VARS is None:
575 _CONFIG_VARS = {}
576 # Normalized versions of prefix and exec_prefix are handy to have;
577 # in fact, these are the standard versions used most places in the
Éric Araujo859aad62012-06-24 00:07:41 -0400578 # Distutils.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000579 _CONFIG_VARS['prefix'] = _PREFIX
580 _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX
581 _CONFIG_VARS['py_version'] = _PY_VERSION
582 _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT
Serhiy Storchaka885bdc42016-02-11 13:10:36 +0200583 _CONFIG_VARS['py_version_nodot'] = _PY_VERSION_SHORT_NO_DOT
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100584 _CONFIG_VARS['installed_base'] = _BASE_PREFIX
Tarek Ziadéedacea32010-01-29 11:41:03 +0000585 _CONFIG_VARS['base'] = _PREFIX
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100586 _CONFIG_VARS['installed_platbase'] = _BASE_EXEC_PREFIX
Tarek Ziadéedacea32010-01-29 11:41:03 +0000587 _CONFIG_VARS['platbase'] = _EXEC_PREFIX
Tarek Ziadéedacea32010-01-29 11:41:03 +0000588 _CONFIG_VARS['projectbase'] = _PROJECT_BASE
Victor Stinner8510f432020-03-10 09:53:09 +0100589 _CONFIG_VARS['platlibdir'] = sys.platlibdir
Barry Warsawd5eaa5f2010-11-25 01:34:47 +0000590 try:
591 _CONFIG_VARS['abiflags'] = sys.abiflags
592 except AttributeError:
593 # sys.abiflags may not be defined on all platforms.
594 _CONFIG_VARS['abiflags'] = ''
Steve Dowerdd180012020-09-05 00:45:54 +0100595 try:
596 _CONFIG_VARS['py_version_nodot_plat'] = sys.winver.replace('.', '')
597 except AttributeError:
598 _CONFIG_VARS['py_version_nodot_plat'] = ''
Tarek Ziadéedacea32010-01-29 11:41:03 +0000599
Jesus Cea4791a242012-10-05 03:15:39 +0200600 if os.name == 'nt':
Tarek Ziadéedacea32010-01-29 11:41:03 +0000601 _init_non_posix(_CONFIG_VARS)
602 if os.name == 'posix':
603 _init_posix(_CONFIG_VARS)
Barry Warsaw87b96372013-11-22 11:08:05 -0500604 # For backward compatibility, see issue19555
605 SO = _CONFIG_VARS.get('EXT_SUFFIX')
606 if SO is not None:
607 _CONFIG_VARS['SO'] = SO
pxinwrab74c012020-12-21 06:27:42 +0800608 if _HAS_USER_BASE:
609 # Setting 'userbase' is done below the call to the
610 # init function to enable using 'get_config_var' in
611 # the init-function.
612 _CONFIG_VARS['userbase'] = _getuserbase()
Ronald Oussoren4cda46a2010-05-08 10:49:43 +0000613
Richard Oudkerk46874ad2012-07-27 12:06:55 +0100614 # Always convert srcdir to an absolute path
615 srcdir = _CONFIG_VARS.get('srcdir', _PROJECT_BASE)
616 if os.name == 'posix':
617 if _PYTHON_BUILD:
618 # If srcdir is a relative path (typically '.' or '..')
619 # then it should be interpreted relative to the directory
620 # containing Makefile.
621 base = os.path.dirname(get_makefile_filename())
622 srcdir = os.path.join(base, srcdir)
623 else:
624 # srcdir is not meaningful since the installation is
625 # spread about the filesystem. We choose the
626 # directory containing the Makefile since we know it
627 # exists.
628 srcdir = os.path.dirname(get_makefile_filename())
629 _CONFIG_VARS['srcdir'] = _safe_realpath(srcdir)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000630
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700631 # OS X platforms require special customization to handle
632 # multi-architecture, multi-os-version installers
Tarek Ziadéedacea32010-01-29 11:41:03 +0000633 if sys.platform == 'darwin':
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700634 import _osx_support
635 _osx_support.customize_config_vars(_CONFIG_VARS)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000636
637 if args:
638 vals = []
639 for name in args:
640 vals.append(_CONFIG_VARS.get(name))
641 return vals
642 else:
643 return _CONFIG_VARS
644
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200645
Tarek Ziadéedacea32010-01-29 11:41:03 +0000646def get_config_var(name):
647 """Return the value of a single variable using the dictionary returned by
648 'get_config_vars()'.
649
650 Equivalent to get_config_vars().get(name)
651 """
Barry Warsaw197a7702013-11-21 18:57:14 -0500652 if name == 'SO':
653 import warnings
Serhiy Storchakaeaec3592013-11-26 17:08:24 +0200654 warnings.warn('SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000655 return get_config_vars().get(name)
656
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200657
Tarek Ziadéedacea32010-01-29 11:41:03 +0000658def get_platform():
659 """Return a string that identifies the current platform.
660
661 This is used mainly to distinguish platform-specific build directories and
Benjamin Peterson06930632017-09-04 16:36:05 -0700662 platform-specific built distributions. Typically includes the OS name and
663 version and the architecture (as supplied by 'os.uname()'), although the
664 exact information included depends on the OS; on Linux, the kernel version
665 isn't particularly important.
Tarek Ziadéedacea32010-01-29 11:41:03 +0000666
667 Examples of returned values:
668 linux-i586
669 linux-alpha (?)
670 solaris-2.6-sun4u
Tarek Ziadéedacea32010-01-29 11:41:03 +0000671
672 Windows will return one of:
673 win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000674 win32 (all others - specifically, sys.platform is returned)
675
676 For other non-POSIX platforms, currently just returns 'sys.platform'.
Benjamin Peterson06930632017-09-04 16:36:05 -0700677
Tarek Ziadéedacea32010-01-29 11:41:03 +0000678 """
Tarek Ziadéedacea32010-01-29 11:41:03 +0000679 if os.name == 'nt':
Zachary Ware49ce74e2017-09-06 15:45:25 -0700680 if 'amd64' in sys.version.lower():
Tarek Ziadéedacea32010-01-29 11:41:03 +0000681 return 'win-amd64'
Paul Monson62dfd7d2019-04-25 11:36:45 -0700682 if '(arm)' in sys.version.lower():
683 return 'win-arm32'
Paul Monsondaf62622019-06-12 10:16:49 -0700684 if '(arm64)' in sys.version.lower():
685 return 'win-arm64'
Tarek Ziadéedacea32010-01-29 11:41:03 +0000686 return sys.platform
687
688 if os.name != "posix" or not hasattr(os, 'uname'):
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700689 # XXX what about the architecture? NT is Intel or Alpha
Tarek Ziadéedacea32010-01-29 11:41:03 +0000690 return sys.platform
691
doko@ubuntu.com1abe1c52012-06-30 20:42:45 +0200692 # Set for cross builds explicitly
693 if "_PYTHON_HOST_PLATFORM" in os.environ:
694 return os.environ["_PYTHON_HOST_PLATFORM"]
695
Tarek Ziadéedacea32010-01-29 11:41:03 +0000696 # Try to distinguish various flavours of Unix
697 osname, host, release, version, machine = os.uname()
698
Benjamin Peterson288d1da2017-09-28 22:44:27 -0700699 # Convert the OS name to lowercase, remove '/' characters, and translate
700 # spaces (for "Power Macintosh")
Tarek Ziadéedacea32010-01-29 11:41:03 +0000701 osname = osname.lower().replace('/', '')
702 machine = machine.replace(' ', '_')
703 machine = machine.replace('/', '-')
704
705 if osname[:5] == "linux":
706 # At least on Linux/Intel, 'machine' is the processor --
707 # i386, etc.
708 # XXX what about Alpha, SPARC, etc?
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800709 return f"{osname}-{machine}"
Tarek Ziadéedacea32010-01-29 11:41:03 +0000710 elif osname[:5] == "sunos":
711 if release[0] >= "5": # SunOS 5 == Solaris 2
712 osname = "solaris"
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800713 release = f"{int(release[0]) - 3}.{release[2:]}"
Jesus Cea1aa1cf32012-01-18 04:49:26 +0100714 # We can't use "platform.architecture()[0]" because a
715 # bootstrap problem. We use a dict to get an error
716 # if some suspicious happens.
717 bitness = {2147483647:"32bit", 9223372036854775807:"64bit"}
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800718 machine += f".{bitness[sys.maxsize]}"
Tarek Ziadéedacea32010-01-29 11:41:03 +0000719 # fall through to standard osname-release-machine representation
Tarek Ziadéedacea32010-01-29 11:41:03 +0000720 elif osname[:3] == "aix":
Michael Felt39afa2d2019-12-15 15:17:53 +0100721 from _aix_support import aix_platform
722 return aix_platform()
Tarek Ziadéedacea32010-01-29 11:41:03 +0000723 elif osname[:6] == "cygwin":
724 osname = "cygwin"
Christian Heimes8c9cd5a2013-10-12 00:24:55 +0200725 import re
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200726 rel_re = re.compile(r'[\d.]+')
Tarek Ziadéedacea32010-01-29 11:41:03 +0000727 m = rel_re.match(release)
728 if m:
729 release = m.group()
730 elif osname[:6] == "darwin":
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700731 import _osx_support
732 osname, release, machine = _osx_support.get_platform_osx(
733 get_config_vars(),
734 osname, release, machine)
Tarek Ziadéedacea32010-01-29 11:41:03 +0000735
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800736 return f"{osname}-{release}-{machine}"
Tarek Ziadéedacea32010-01-29 11:41:03 +0000737
738
739def get_python_version():
740 return _PY_VERSION_SHORT
Tarek Ziadéa7514992010-05-25 09:44:36 +0000741
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200742
Lumír 'Frenzy' Balhar90d02e52021-04-23 14:02:41 +0200743def expand_makefile_vars(s, vars):
744 """Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in
745 'string' according to 'vars' (a dictionary mapping variable names to
746 values). Variables not present in 'vars' are silently expanded to the
747 empty string. The variable values in 'vars' should not contain further
748 variable expansions; if 'vars' is the output of 'parse_makefile()',
749 you're fine. Returns a variable-expanded version of 's'.
750 """
751 import re
752
753 # This algorithm does multiple expansion, so if vars['foo'] contains
754 # "${bar}", it will expand ${foo} to ${bar}, and then expand
755 # ${bar}... and so forth. This is fine as long as 'vars' comes from
756 # 'parse_makefile()', which takes care of such expansions eagerly,
757 # according to make's variable expansion semantics.
758
759 while True:
760 m = re.search(_findvar1_rx, s) or re.search(_findvar2_rx, s)
761 if m:
762 (beg, end) = m.span()
763 s = s[0:beg] + vars.get(m.group(1)) + s[end:]
764 else:
765 break
766 return s
767
768
Tarek Ziadéa7514992010-05-25 09:44:36 +0000769def _print_dict(title, data):
770 for index, (key, value) in enumerate(sorted(data.items())):
771 if index == 0:
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800772 print(f'{title}: ')
773 print(f'\t{key} = "{value}"')
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200774
Tarek Ziadéa7514992010-05-25 09:44:36 +0000775
776def _main():
Éric Araujo300623d2010-11-22 01:19:20 +0000777 """Display all information sysconfig detains."""
Antoine Pitrou1e73a242011-10-18 17:52:24 +0200778 if '--generate-posix-vars' in sys.argv:
779 _generate_posix_vars()
780 return
Tzu-ping Chungd9251332021-04-27 16:45:55 +0800781 print(f'Platform: "{get_platform()}"')
782 print(f'Python version: "{get_python_version()}"')
783 print(f'Current installation scheme: "{get_default_scheme()}"')
Éric Araujo559b5f12011-05-25 18:21:43 +0200784 print()
Tarek Ziadéa7514992010-05-25 09:44:36 +0000785 _print_dict('Paths', get_paths())
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200786 print()
Tarek Ziadéa7514992010-05-25 09:44:36 +0000787 _print_dict('Variables', get_config_vars())
788
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200789
Tarek Ziadéa7514992010-05-25 09:44:36 +0000790if __name__ == '__main__':
791 _main()