logo

oasis-root

Compiled tree of Oasis Linux based on own branch at <https://hacktivis.me/git/oasis/> git clone https://anongit.hacktivis.me/git/oasis-root.git

sysconfig.py (27609B)


  1. """Access to Python's configuration information."""
  2. import os
  3. import sys
  4. from os.path import pardir, realpath
  5. __all__ = [
  6. 'get_config_h_filename',
  7. 'get_config_var',
  8. 'get_config_vars',
  9. 'get_makefile_filename',
  10. 'get_path',
  11. 'get_path_names',
  12. 'get_paths',
  13. 'get_platform',
  14. 'get_python_version',
  15. 'get_scheme_names',
  16. 'parse_config_h',
  17. ]
  18. # Keys for get_config_var() that are never converted to Python integers.
  19. _ALWAYS_STR = {
  20. 'MACOSX_DEPLOYMENT_TARGET',
  21. }
  22. _INSTALL_SCHEMES = {
  23. 'posix_prefix': {
  24. 'stdlib': '{installed_base}/{platlibdir}/python{py_version_short}',
  25. 'platstdlib': '{platbase}/{platlibdir}/python{py_version_short}',
  26. 'purelib': '{base}/lib/python{py_version_short}/site-packages',
  27. 'platlib': '{platbase}/{platlibdir}/python{py_version_short}/site-packages',
  28. 'include':
  29. '{installed_base}/include/python{py_version_short}{abiflags}',
  30. 'platinclude':
  31. '{installed_platbase}/include/python{py_version_short}{abiflags}',
  32. 'scripts': '{base}/bin',
  33. 'data': '{base}',
  34. },
  35. 'posix_home': {
  36. 'stdlib': '{installed_base}/lib/python',
  37. 'platstdlib': '{base}/lib/python',
  38. 'purelib': '{base}/lib/python',
  39. 'platlib': '{base}/lib/python',
  40. 'include': '{installed_base}/include/python',
  41. 'platinclude': '{installed_base}/include/python',
  42. 'scripts': '{base}/bin',
  43. 'data': '{base}',
  44. },
  45. 'nt': {
  46. 'stdlib': '{installed_base}/Lib',
  47. 'platstdlib': '{base}/Lib',
  48. 'purelib': '{base}/Lib/site-packages',
  49. 'platlib': '{base}/Lib/site-packages',
  50. 'include': '{installed_base}/Include',
  51. 'platinclude': '{installed_base}/Include',
  52. 'scripts': '{base}/Scripts',
  53. 'data': '{base}',
  54. },
  55. }
  56. # NOTE: site.py has copy of this function.
  57. # Sync it when modify this function.
  58. def _getuserbase():
  59. env_base = os.environ.get("PYTHONUSERBASE", None)
  60. if env_base:
  61. return env_base
  62. # VxWorks has no home directories
  63. if sys.platform == "vxworks":
  64. return None
  65. def joinuser(*args):
  66. return os.path.expanduser(os.path.join(*args))
  67. if os.name == "nt":
  68. base = os.environ.get("APPDATA") or "~"
  69. return joinuser(base, "Python")
  70. if sys.platform == "darwin" and sys._framework:
  71. return joinuser("~", "Library", sys._framework,
  72. f"{sys.version_info[0]}.{sys.version_info[1]}")
  73. return joinuser("~", ".local")
  74. _HAS_USER_BASE = (_getuserbase() is not None)
  75. if _HAS_USER_BASE:
  76. _INSTALL_SCHEMES |= {
  77. # NOTE: When modifying "purelib" scheme, update site._get_path() too.
  78. 'nt_user': {
  79. 'stdlib': '{userbase}/Python{py_version_nodot_plat}',
  80. 'platstdlib': '{userbase}/Python{py_version_nodot_plat}',
  81. 'purelib': '{userbase}/Python{py_version_nodot_plat}/site-packages',
  82. 'platlib': '{userbase}/Python{py_version_nodot_plat}/site-packages',
  83. 'include': '{userbase}/Python{py_version_nodot_plat}/Include',
  84. 'scripts': '{userbase}/Python{py_version_nodot_plat}/Scripts',
  85. 'data': '{userbase}',
  86. },
  87. 'posix_user': {
  88. 'stdlib': '{userbase}/{platlibdir}/python{py_version_short}',
  89. 'platstdlib': '{userbase}/{platlibdir}/python{py_version_short}',
  90. 'purelib': '{userbase}/lib/python{py_version_short}/site-packages',
  91. 'platlib': '{userbase}/lib/python{py_version_short}/site-packages',
  92. 'include': '{userbase}/include/python{py_version_short}',
  93. 'scripts': '{userbase}/bin',
  94. 'data': '{userbase}',
  95. },
  96. 'osx_framework_user': {
  97. 'stdlib': '{userbase}/lib/python',
  98. 'platstdlib': '{userbase}/lib/python',
  99. 'purelib': '{userbase}/lib/python/site-packages',
  100. 'platlib': '{userbase}/lib/python/site-packages',
  101. 'include': '{userbase}/include/python{py_version_short}',
  102. 'scripts': '{userbase}/bin',
  103. 'data': '{userbase}',
  104. },
  105. }
  106. _SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include',
  107. 'scripts', 'data')
  108. _PY_VERSION = sys.version.split()[0]
  109. _PY_VERSION_SHORT = f'{sys.version_info[0]}.{sys.version_info[1]}'
  110. _PY_VERSION_SHORT_NO_DOT = f'{sys.version_info[0]}{sys.version_info[1]}'
  111. _PREFIX = os.path.normpath(sys.prefix)
  112. _BASE_PREFIX = os.path.normpath(sys.base_prefix)
  113. _EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
  114. _BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix)
  115. _CONFIG_VARS = None
  116. _USER_BASE = None
  117. # Regexes needed for parsing Makefile (and similar syntaxes,
  118. # like old-style Setup files).
  119. _variable_rx = r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)"
  120. _findvar1_rx = r"\$\(([A-Za-z][A-Za-z0-9_]*)\)"
  121. _findvar2_rx = r"\${([A-Za-z][A-Za-z0-9_]*)}"
  122. def _safe_realpath(path):
  123. try:
  124. return realpath(path)
  125. except OSError:
  126. return path
  127. if sys.executable:
  128. _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable))
  129. else:
  130. # sys.executable can be empty if argv[0] has been changed and Python is
  131. # unable to retrieve the real program name
  132. _PROJECT_BASE = _safe_realpath(os.getcwd())
  133. if (os.name == 'nt' and
  134. _PROJECT_BASE.lower().endswith(('\\pcbuild\\win32', '\\pcbuild\\amd64'))):
  135. _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
  136. # set for cross builds
  137. if "_PYTHON_PROJECT_BASE" in os.environ:
  138. _PROJECT_BASE = _safe_realpath(os.environ["_PYTHON_PROJECT_BASE"])
  139. def _is_python_source_dir(d):
  140. for fn in ("Setup", "Setup.local"):
  141. if os.path.isfile(os.path.join(d, "Modules", fn)):
  142. return True
  143. return False
  144. _sys_home = getattr(sys, '_home', None)
  145. if os.name == 'nt':
  146. def _fix_pcbuild(d):
  147. if d and os.path.normcase(d).startswith(
  148. os.path.normcase(os.path.join(_PREFIX, "PCbuild"))):
  149. return _PREFIX
  150. return d
  151. _PROJECT_BASE = _fix_pcbuild(_PROJECT_BASE)
  152. _sys_home = _fix_pcbuild(_sys_home)
  153. def is_python_build(check_home=False):
  154. if check_home and _sys_home:
  155. return _is_python_source_dir(_sys_home)
  156. return _is_python_source_dir(_PROJECT_BASE)
  157. _PYTHON_BUILD = is_python_build(True)
  158. if _PYTHON_BUILD:
  159. for scheme in ('posix_prefix', 'posix_home'):
  160. # On POSIX-y platofrms, Python will:
  161. # - Build from .h files in 'headers' (which is only added to the
  162. # scheme when building CPython)
  163. # - Install .h files to 'include'
  164. scheme = _INSTALL_SCHEMES[scheme]
  165. scheme['headers'] = scheme['include']
  166. scheme['include'] = '{srcdir}/Include'
  167. scheme['platinclude'] = '{projectbase}/.'
  168. def _subst_vars(s, local_vars):
  169. try:
  170. return s.format(**local_vars)
  171. except KeyError as var:
  172. try:
  173. return s.format(**os.environ)
  174. except KeyError:
  175. raise AttributeError(f'{var}') from None
  176. def _extend_dict(target_dict, other_dict):
  177. target_keys = target_dict.keys()
  178. for key, value in other_dict.items():
  179. if key in target_keys:
  180. continue
  181. target_dict[key] = value
  182. def _expand_vars(scheme, vars):
  183. res = {}
  184. if vars is None:
  185. vars = {}
  186. _extend_dict(vars, get_config_vars())
  187. for key, value in _INSTALL_SCHEMES[scheme].items():
  188. if os.name in ('posix', 'nt'):
  189. value = os.path.expanduser(value)
  190. res[key] = os.path.normpath(_subst_vars(value, vars))
  191. return res
  192. def _get_preferred_schemes():
  193. if os.name == 'nt':
  194. return {
  195. 'prefix': 'nt',
  196. 'home': 'posix_home',
  197. 'user': 'nt_user',
  198. }
  199. if sys.platform == 'darwin' and sys._framework:
  200. return {
  201. 'prefix': 'posix_prefix',
  202. 'home': 'posix_home',
  203. 'user': 'osx_framework_user',
  204. }
  205. return {
  206. 'prefix': 'posix_prefix',
  207. 'home': 'posix_home',
  208. 'user': 'posix_user',
  209. }
  210. def get_preferred_scheme(key):
  211. scheme = _get_preferred_schemes()[key]
  212. if scheme not in _INSTALL_SCHEMES:
  213. raise ValueError(
  214. f"{key!r} returned {scheme!r}, which is not a valid scheme "
  215. f"on this platform"
  216. )
  217. return scheme
  218. def get_default_scheme():
  219. return get_preferred_scheme('prefix')
  220. def _parse_makefile(filename, vars=None, keep_unresolved=True):
  221. """Parse a Makefile-style file.
  222. A dictionary containing name/value pairs is returned. If an
  223. optional dictionary is passed in as the second argument, it is
  224. used instead of a new dictionary.
  225. """
  226. import re
  227. if vars is None:
  228. vars = {}
  229. done = {}
  230. notdone = {}
  231. with open(filename, encoding=sys.getfilesystemencoding(),
  232. errors="surrogateescape") as f:
  233. lines = f.readlines()
  234. for line in lines:
  235. if line.startswith('#') or line.strip() == '':
  236. continue
  237. m = re.match(_variable_rx, line)
  238. if m:
  239. n, v = m.group(1, 2)
  240. v = v.strip()
  241. # `$$' is a literal `$' in make
  242. tmpv = v.replace('$$', '')
  243. if "$" in tmpv:
  244. notdone[n] = v
  245. else:
  246. try:
  247. if n in _ALWAYS_STR:
  248. raise ValueError
  249. v = int(v)
  250. except ValueError:
  251. # insert literal `$'
  252. done[n] = v.replace('$$', '$')
  253. else:
  254. done[n] = v
  255. # do variable interpolation here
  256. variables = list(notdone.keys())
  257. # Variables with a 'PY_' prefix in the makefile. These need to
  258. # be made available without that prefix through sysconfig.
  259. # Special care is needed to ensure that variable expansion works, even
  260. # if the expansion uses the name without a prefix.
  261. renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')
  262. while len(variables) > 0:
  263. for name in tuple(variables):
  264. value = notdone[name]
  265. m1 = re.search(_findvar1_rx, value)
  266. m2 = re.search(_findvar2_rx, value)
  267. if m1 and m2:
  268. m = m1 if m1.start() < m2.start() else m2
  269. else:
  270. m = m1 if m1 else m2
  271. if m is not None:
  272. n = m.group(1)
  273. found = True
  274. if n in done:
  275. item = str(done[n])
  276. elif n in notdone:
  277. # get it on a subsequent round
  278. found = False
  279. elif n in os.environ:
  280. # do it like make: fall back to environment
  281. item = os.environ[n]
  282. elif n in renamed_variables:
  283. if (name.startswith('PY_') and
  284. name[3:] in renamed_variables):
  285. item = ""
  286. elif 'PY_' + n in notdone:
  287. found = False
  288. else:
  289. item = str(done['PY_' + n])
  290. else:
  291. done[n] = item = ""
  292. if found:
  293. after = value[m.end():]
  294. value = value[:m.start()] + item + after
  295. if "$" in after:
  296. notdone[name] = value
  297. else:
  298. try:
  299. if name in _ALWAYS_STR:
  300. raise ValueError
  301. value = int(value)
  302. except ValueError:
  303. done[name] = value.strip()
  304. else:
  305. done[name] = value
  306. variables.remove(name)
  307. if name.startswith('PY_') \
  308. and name[3:] in renamed_variables:
  309. name = name[3:]
  310. if name not in done:
  311. done[name] = value
  312. else:
  313. # Adds unresolved variables to the done dict.
  314. # This is disabled when called from distutils.sysconfig
  315. if keep_unresolved:
  316. done[name] = value
  317. # bogus variable reference (e.g. "prefix=$/opt/python");
  318. # just drop it since we can't deal
  319. variables.remove(name)
  320. # strip spurious spaces
  321. for k, v in done.items():
  322. if isinstance(v, str):
  323. done[k] = v.strip()
  324. # save the results in the global dictionary
  325. vars.update(done)
  326. return vars
  327. def get_makefile_filename():
  328. """Return the path of the Makefile."""
  329. if _PYTHON_BUILD:
  330. return os.path.join(_sys_home or _PROJECT_BASE, "Makefile")
  331. if hasattr(sys, 'abiflags'):
  332. config_dir_name = f'config-{_PY_VERSION_SHORT}{sys.abiflags}'
  333. else:
  334. config_dir_name = 'config'
  335. if hasattr(sys.implementation, '_multiarch'):
  336. config_dir_name += f'-{sys.implementation._multiarch}'
  337. return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile')
  338. def _get_sysconfigdata_name():
  339. multiarch = getattr(sys.implementation, '_multiarch', '')
  340. return os.environ.get(
  341. '_PYTHON_SYSCONFIGDATA_NAME',
  342. f'_sysconfigdata_{sys.abiflags}_{sys.platform}_{multiarch}',
  343. )
  344. def _generate_posix_vars():
  345. """Generate the Python module containing build-time variables."""
  346. import pprint
  347. vars = {}
  348. # load the installed Makefile:
  349. makefile = get_makefile_filename()
  350. try:
  351. _parse_makefile(makefile, vars)
  352. except OSError as e:
  353. msg = f"invalid Python installation: unable to open {makefile}"
  354. if hasattr(e, "strerror"):
  355. msg = f"{msg} ({e.strerror})"
  356. raise OSError(msg)
  357. # load the installed pyconfig.h:
  358. config_h = get_config_h_filename()
  359. try:
  360. with open(config_h, encoding="utf-8") as f:
  361. parse_config_h(f, vars)
  362. except OSError as e:
  363. msg = f"invalid Python installation: unable to open {config_h}"
  364. if hasattr(e, "strerror"):
  365. msg = f"{msg} ({e.strerror})"
  366. raise OSError(msg)
  367. # On AIX, there are wrong paths to the linker scripts in the Makefile
  368. # -- these paths are relative to the Python source, but when installed
  369. # the scripts are in another directory.
  370. if _PYTHON_BUILD:
  371. vars['BLDSHARED'] = vars['LDSHARED']
  372. # There's a chicken-and-egg situation on OS X with regards to the
  373. # _sysconfigdata module after the changes introduced by #15298:
  374. # get_config_vars() is called by get_platform() as part of the
  375. # `make pybuilddir.txt` target -- which is a precursor to the
  376. # _sysconfigdata.py module being constructed. Unfortunately,
  377. # get_config_vars() eventually calls _init_posix(), which attempts
  378. # to import _sysconfigdata, which we won't have built yet. In order
  379. # for _init_posix() to work, if we're on Darwin, just mock up the
  380. # _sysconfigdata module manually and populate it with the build vars.
  381. # This is more than sufficient for ensuring the subsequent call to
  382. # get_platform() succeeds.
  383. name = _get_sysconfigdata_name()
  384. if 'darwin' in sys.platform:
  385. import types
  386. module = types.ModuleType(name)
  387. module.build_time_vars = vars
  388. sys.modules[name] = module
  389. pybuilddir = f'build/lib.{get_platform()}-{_PY_VERSION_SHORT}'
  390. if hasattr(sys, "gettotalrefcount"):
  391. pybuilddir += '-pydebug'
  392. os.makedirs(pybuilddir, exist_ok=True)
  393. destfile = os.path.join(pybuilddir, name + '.py')
  394. with open(destfile, 'w', encoding='utf8') as f:
  395. f.write('# system configuration generated and used by'
  396. ' the sysconfig module\n')
  397. f.write('build_time_vars = ')
  398. pprint.pprint(vars, stream=f)
  399. # Create file used for sys.path fixup -- see Modules/getpath.c
  400. with open('pybuilddir.txt', 'w', encoding='utf8') as f:
  401. f.write(pybuilddir)
  402. def _init_posix(vars):
  403. """Initialize the module as appropriate for POSIX systems."""
  404. # _sysconfigdata is generated at build time, see _generate_posix_vars()
  405. name = _get_sysconfigdata_name()
  406. _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0)
  407. build_time_vars = _temp.build_time_vars
  408. vars.update(build_time_vars)
  409. def _init_non_posix(vars):
  410. """Initialize the module as appropriate for NT"""
  411. # set basic install directories
  412. import _imp
  413. vars['LIBDEST'] = get_path('stdlib')
  414. vars['BINLIBDEST'] = get_path('platstdlib')
  415. vars['INCLUDEPY'] = get_path('include')
  416. vars['EXT_SUFFIX'] = _imp.extension_suffixes()[0]
  417. vars['EXE'] = '.exe'
  418. vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
  419. vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))
  420. vars['TZPATH'] = ''
  421. #
  422. # public APIs
  423. #
  424. def parse_config_h(fp, vars=None):
  425. """Parse a config.h-style file.
  426. A dictionary containing name/value pairs is returned. If an
  427. optional dictionary is passed in as the second argument, it is
  428. used instead of a new dictionary.
  429. """
  430. if vars is None:
  431. vars = {}
  432. import re
  433. define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
  434. undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
  435. while True:
  436. line = fp.readline()
  437. if not line:
  438. break
  439. m = define_rx.match(line)
  440. if m:
  441. n, v = m.group(1, 2)
  442. try:
  443. if n in _ALWAYS_STR:
  444. raise ValueError
  445. v = int(v)
  446. except ValueError:
  447. pass
  448. vars[n] = v
  449. else:
  450. m = undef_rx.match(line)
  451. if m:
  452. vars[m.group(1)] = 0
  453. return vars
  454. def get_config_h_filename():
  455. """Return the path of pyconfig.h."""
  456. if _PYTHON_BUILD:
  457. if os.name == "nt":
  458. inc_dir = os.path.join(_sys_home or _PROJECT_BASE, "PC")
  459. else:
  460. inc_dir = _sys_home or _PROJECT_BASE
  461. else:
  462. inc_dir = get_path('platinclude')
  463. return os.path.join(inc_dir, 'pyconfig.h')
  464. def get_scheme_names():
  465. """Return a tuple containing the schemes names."""
  466. return tuple(sorted(_INSTALL_SCHEMES))
  467. def get_path_names():
  468. """Return a tuple containing the paths names."""
  469. return _SCHEME_KEYS
  470. def get_paths(scheme=get_default_scheme(), vars=None, expand=True):
  471. """Return a mapping containing an install scheme.
  472. ``scheme`` is the install scheme name. If not provided, it will
  473. return the default scheme for the current platform.
  474. """
  475. if expand:
  476. return _expand_vars(scheme, vars)
  477. else:
  478. return _INSTALL_SCHEMES[scheme]
  479. def get_path(name, scheme=get_default_scheme(), vars=None, expand=True):
  480. """Return a path corresponding to the scheme.
  481. ``scheme`` is the install scheme name.
  482. """
  483. return get_paths(scheme, vars, expand)[name]
  484. def get_config_vars(*args):
  485. """With no arguments, return a dictionary of all configuration
  486. variables relevant for the current platform.
  487. On Unix, this means every variable defined in Python's installed Makefile;
  488. On Windows it's a much smaller set.
  489. With arguments, return a list of values that result from looking up
  490. each argument in the configuration variable dictionary.
  491. """
  492. global _CONFIG_VARS
  493. if _CONFIG_VARS is None:
  494. _CONFIG_VARS = {}
  495. # Normalized versions of prefix and exec_prefix are handy to have;
  496. # in fact, these are the standard versions used most places in the
  497. # Distutils.
  498. _CONFIG_VARS['prefix'] = _PREFIX
  499. _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX
  500. _CONFIG_VARS['py_version'] = _PY_VERSION
  501. _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT
  502. _CONFIG_VARS['py_version_nodot'] = _PY_VERSION_SHORT_NO_DOT
  503. _CONFIG_VARS['installed_base'] = _BASE_PREFIX
  504. _CONFIG_VARS['base'] = _PREFIX
  505. _CONFIG_VARS['installed_platbase'] = _BASE_EXEC_PREFIX
  506. _CONFIG_VARS['platbase'] = _EXEC_PREFIX
  507. _CONFIG_VARS['projectbase'] = _PROJECT_BASE
  508. _CONFIG_VARS['platlibdir'] = sys.platlibdir
  509. try:
  510. _CONFIG_VARS['abiflags'] = sys.abiflags
  511. except AttributeError:
  512. # sys.abiflags may not be defined on all platforms.
  513. _CONFIG_VARS['abiflags'] = ''
  514. try:
  515. _CONFIG_VARS['py_version_nodot_plat'] = sys.winver.replace('.', '')
  516. except AttributeError:
  517. _CONFIG_VARS['py_version_nodot_plat'] = ''
  518. if os.name == 'nt':
  519. _init_non_posix(_CONFIG_VARS)
  520. if os.name == 'posix':
  521. _init_posix(_CONFIG_VARS)
  522. # For backward compatibility, see issue19555
  523. SO = _CONFIG_VARS.get('EXT_SUFFIX')
  524. if SO is not None:
  525. _CONFIG_VARS['SO'] = SO
  526. if _HAS_USER_BASE:
  527. # Setting 'userbase' is done below the call to the
  528. # init function to enable using 'get_config_var' in
  529. # the init-function.
  530. _CONFIG_VARS['userbase'] = _getuserbase()
  531. # Always convert srcdir to an absolute path
  532. srcdir = _CONFIG_VARS.get('srcdir', _PROJECT_BASE)
  533. if os.name == 'posix':
  534. if _PYTHON_BUILD:
  535. # If srcdir is a relative path (typically '.' or '..')
  536. # then it should be interpreted relative to the directory
  537. # containing Makefile.
  538. base = os.path.dirname(get_makefile_filename())
  539. srcdir = os.path.join(base, srcdir)
  540. else:
  541. # srcdir is not meaningful since the installation is
  542. # spread about the filesystem. We choose the
  543. # directory containing the Makefile since we know it
  544. # exists.
  545. srcdir = os.path.dirname(get_makefile_filename())
  546. _CONFIG_VARS['srcdir'] = _safe_realpath(srcdir)
  547. # OS X platforms require special customization to handle
  548. # multi-architecture, multi-os-version installers
  549. if sys.platform == 'darwin':
  550. import _osx_support
  551. _osx_support.customize_config_vars(_CONFIG_VARS)
  552. if args:
  553. vals = []
  554. for name in args:
  555. vals.append(_CONFIG_VARS.get(name))
  556. return vals
  557. else:
  558. return _CONFIG_VARS
  559. def get_config_var(name):
  560. """Return the value of a single variable using the dictionary returned by
  561. 'get_config_vars()'.
  562. Equivalent to get_config_vars().get(name)
  563. """
  564. if name == 'SO':
  565. import warnings
  566. warnings.warn('SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2)
  567. return get_config_vars().get(name)
  568. def get_platform():
  569. """Return a string that identifies the current platform.
  570. This is used mainly to distinguish platform-specific build directories and
  571. platform-specific built distributions. Typically includes the OS name and
  572. version and the architecture (as supplied by 'os.uname()'), although the
  573. exact information included depends on the OS; on Linux, the kernel version
  574. isn't particularly important.
  575. Examples of returned values:
  576. linux-i586
  577. linux-alpha (?)
  578. solaris-2.6-sun4u
  579. Windows will return one of:
  580. win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
  581. win32 (all others - specifically, sys.platform is returned)
  582. For other non-POSIX platforms, currently just returns 'sys.platform'.
  583. """
  584. if os.name == 'nt':
  585. if 'amd64' in sys.version.lower():
  586. return 'win-amd64'
  587. if '(arm)' in sys.version.lower():
  588. return 'win-arm32'
  589. if '(arm64)' in sys.version.lower():
  590. return 'win-arm64'
  591. return sys.platform
  592. if os.name != "posix" or not hasattr(os, 'uname'):
  593. # XXX what about the architecture? NT is Intel or Alpha
  594. return sys.platform
  595. # Set for cross builds explicitly
  596. if "_PYTHON_HOST_PLATFORM" in os.environ:
  597. return os.environ["_PYTHON_HOST_PLATFORM"]
  598. # Try to distinguish various flavours of Unix
  599. osname, host, release, version, machine = os.uname()
  600. # Convert the OS name to lowercase, remove '/' characters, and translate
  601. # spaces (for "Power Macintosh")
  602. osname = osname.lower().replace('/', '')
  603. machine = machine.replace(' ', '_')
  604. machine = machine.replace('/', '-')
  605. if osname[:5] == "linux":
  606. # At least on Linux/Intel, 'machine' is the processor --
  607. # i386, etc.
  608. # XXX what about Alpha, SPARC, etc?
  609. return f"{osname}-{machine}"
  610. elif osname[:5] == "sunos":
  611. if release[0] >= "5": # SunOS 5 == Solaris 2
  612. osname = "solaris"
  613. release = f"{int(release[0]) - 3}.{release[2:]}"
  614. # We can't use "platform.architecture()[0]" because a
  615. # bootstrap problem. We use a dict to get an error
  616. # if some suspicious happens.
  617. bitness = {2147483647:"32bit", 9223372036854775807:"64bit"}
  618. machine += f".{bitness[sys.maxsize]}"
  619. # fall through to standard osname-release-machine representation
  620. elif osname[:3] == "aix":
  621. from _aix_support import aix_platform
  622. return aix_platform()
  623. elif osname[:6] == "cygwin":
  624. osname = "cygwin"
  625. import re
  626. rel_re = re.compile(r'[\d.]+')
  627. m = rel_re.match(release)
  628. if m:
  629. release = m.group()
  630. elif osname[:6] == "darwin":
  631. import _osx_support
  632. osname, release, machine = _osx_support.get_platform_osx(
  633. get_config_vars(),
  634. osname, release, machine)
  635. return f"{osname}-{release}-{machine}"
  636. def get_python_version():
  637. return _PY_VERSION_SHORT
  638. def expand_makefile_vars(s, vars):
  639. """Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in
  640. 'string' according to 'vars' (a dictionary mapping variable names to
  641. values). Variables not present in 'vars' are silently expanded to the
  642. empty string. The variable values in 'vars' should not contain further
  643. variable expansions; if 'vars' is the output of 'parse_makefile()',
  644. you're fine. Returns a variable-expanded version of 's'.
  645. """
  646. import re
  647. # This algorithm does multiple expansion, so if vars['foo'] contains
  648. # "${bar}", it will expand ${foo} to ${bar}, and then expand
  649. # ${bar}... and so forth. This is fine as long as 'vars' comes from
  650. # 'parse_makefile()', which takes care of such expansions eagerly,
  651. # according to make's variable expansion semantics.
  652. while True:
  653. m = re.search(_findvar1_rx, s) or re.search(_findvar2_rx, s)
  654. if m:
  655. (beg, end) = m.span()
  656. s = s[0:beg] + vars.get(m.group(1)) + s[end:]
  657. else:
  658. break
  659. return s
  660. def _print_dict(title, data):
  661. for index, (key, value) in enumerate(sorted(data.items())):
  662. if index == 0:
  663. print(f'{title}: ')
  664. print(f'\t{key} = "{value}"')
  665. def _main():
  666. """Display all information sysconfig detains."""
  667. if '--generate-posix-vars' in sys.argv:
  668. _generate_posix_vars()
  669. return
  670. print(f'Platform: "{get_platform()}"')
  671. print(f'Python version: "{get_python_version()}"')
  672. print(f'Current installation scheme: "{get_default_scheme()}"')
  673. print()
  674. _print_dict('Paths', get_paths())
  675. print()
  676. _print_dict('Variables', get_config_vars())
  677. if __name__ == '__main__':
  678. _main()