You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

786 lines
27 KiB

  1. """Access to Python's configuration information."""
  2. import os
  3. import re
  4. import sys
  5. from os.path import pardir, realpath
  6. from configparser import RawConfigParser
  7. __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',
  19. ]
  20. # let's read the configuration file
  21. # XXX _CONFIG_DIR will be set by the Makefile later
  22. _CONFIG_DIR = os.path.normpath(os.path.dirname(__file__))
  23. _CONFIG_FILE = os.path.join(_CONFIG_DIR, 'sysconfig.cfg')
  24. _SCHEMES = RawConfigParser(dict_type=dict) # Faster than OrderedDict
  25. _SCHEMES.read(_CONFIG_FILE)
  26. _VAR_REPL = re.compile(r'\{([^{]*?)\}')
  27. def _expand_globals(config):
  28. if config.has_section('globals'):
  29. globals = config.items('globals')
  30. else:
  31. globals = tuple()
  32. sections = config.sections()
  33. for section in sections:
  34. if section == 'globals':
  35. continue
  36. for option, value in globals:
  37. if config.has_option(section, option):
  38. continue
  39. config.set(section, option, value)
  40. config.remove_section('globals')
  41. # now expanding local variables defined in the cfg file
  42. #
  43. for section in config.sections():
  44. variables = dict(config.items(section))
  45. def _replacer(matchobj):
  46. name = matchobj.group(1)
  47. if name in variables:
  48. return variables[name]
  49. return matchobj.group(0)
  50. for option, value in config.items(section):
  51. config.set(section, option, _VAR_REPL.sub(_replacer, value))
  52. _expand_globals(_SCHEMES)
  53. # FIXME don't rely on sys.version here, its format is an implementatin detail
  54. # of CPython, use sys.version_info or sys.hexversion
  55. _PY_VERSION = sys.version.split()[0]
  56. _PY_VERSION_SHORT = sys.version[:3]
  57. _PY_VERSION_SHORT_NO_DOT = _PY_VERSION[0] + _PY_VERSION[2]
  58. _PREFIX = os.path.normpath(sys.prefix)
  59. _EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
  60. _CONFIG_VARS = None
  61. _USER_BASE = None
  62. def _safe_realpath(path):
  63. try:
  64. return realpath(path)
  65. except OSError:
  66. return path
  67. if sys.executable:
  68. _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable))
  69. else:
  70. # sys.executable can be empty if argv[0] has been changed and Python is
  71. # unable to retrieve the real program name
  72. _PROJECT_BASE = _safe_realpath(os.getcwd())
  73. if os.name == "nt" and "pcbuild" in _PROJECT_BASE[-8:].lower():
  74. _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir))
  75. # PC/VS7.1
  76. if os.name == "nt" and "\\pc\\v" in _PROJECT_BASE[-10:].lower():
  77. _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
  78. # PC/AMD64
  79. if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower():
  80. _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
  81. def is_python_build():
  82. for fn in ("Setup.dist", "Setup.local"):
  83. if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)):
  84. return True
  85. return False
  86. _PYTHON_BUILD = is_python_build()
  87. if _PYTHON_BUILD:
  88. for scheme in ('posix_prefix', 'posix_home'):
  89. _SCHEMES.set(scheme, 'include', '{srcdir}/Include')
  90. _SCHEMES.set(scheme, 'platinclude', '{projectbase}/.')
  91. def _subst_vars(path, local_vars):
  92. """In the string `path`, replace tokens like {some.thing} with the
  93. corresponding value from the map `local_vars`.
  94. If there is no corresponding value, leave the token unchanged.
  95. """
  96. def _replacer(matchobj):
  97. name = matchobj.group(1)
  98. if name in local_vars:
  99. return local_vars[name]
  100. elif name in os.environ:
  101. return os.environ[name]
  102. return matchobj.group(0)
  103. return _VAR_REPL.sub(_replacer, path)
  104. def _extend_dict(target_dict, other_dict):
  105. target_keys = target_dict.keys()
  106. for key, value in other_dict.items():
  107. if key in target_keys:
  108. continue
  109. target_dict[key] = value
  110. def _expand_vars(scheme, vars):
  111. res = {}
  112. if vars is None:
  113. vars = {}
  114. _extend_dict(vars, get_config_vars())
  115. for key, value in _SCHEMES.items(scheme):
  116. if os.name in ('posix', 'nt'):
  117. value = os.path.expanduser(value)
  118. res[key] = os.path.normpath(_subst_vars(value, vars))
  119. return res
  120. def format_value(value, vars):
  121. def _replacer(matchobj):
  122. name = matchobj.group(1)
  123. if name in vars:
  124. return vars[name]
  125. return matchobj.group(0)
  126. return _VAR_REPL.sub(_replacer, value)
  127. def _get_default_scheme():
  128. if os.name == 'posix':
  129. # the default scheme for posix is posix_prefix
  130. return 'posix_prefix'
  131. return os.name
  132. def _getuserbase():
  133. env_base = os.environ.get("PYTHONUSERBASE", None)
  134. def joinuser(*args):
  135. return os.path.expanduser(os.path.join(*args))
  136. # what about 'os2emx', 'riscos' ?
  137. if os.name == "nt":
  138. base = os.environ.get("APPDATA") or "~"
  139. if env_base:
  140. return env_base
  141. else:
  142. return joinuser(base, "Python")
  143. if sys.platform == "darwin":
  144. framework = get_config_var("PYTHONFRAMEWORK")
  145. if framework:
  146. if env_base:
  147. return env_base
  148. else:
  149. return joinuser("~", "Library", framework, "%d.%d" %
  150. sys.version_info[:2])
  151. if env_base:
  152. return env_base
  153. else:
  154. return joinuser("~", ".local")
  155. def _parse_makefile(filename, vars=None):
  156. """Parse a Makefile-style file.
  157. A dictionary containing name/value pairs is returned. If an
  158. optional dictionary is passed in as the second argument, it is
  159. used instead of a new dictionary.
  160. """
  161. # Regexes needed for parsing Makefile (and similar syntaxes,
  162. # like old-style Setup files).
  163. _variable_rx = re.compile("([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)")
  164. _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")
  165. _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")
  166. if vars is None:
  167. vars = {}
  168. done = {}
  169. notdone = {}
  170. with open(filename, errors="surrogateescape") as f:
  171. lines = f.readlines()
  172. for line in lines:
  173. if line.startswith('#') or line.strip() == '':
  174. continue
  175. m = _variable_rx.match(line)
  176. if m:
  177. n, v = m.group(1, 2)
  178. v = v.strip()
  179. # `$$' is a literal `$' in make
  180. tmpv = v.replace('$$', '')
  181. if "$" in tmpv:
  182. notdone[n] = v
  183. else:
  184. try:
  185. v = int(v)
  186. except ValueError:
  187. # insert literal `$'
  188. done[n] = v.replace('$$', '$')
  189. else:
  190. done[n] = v
  191. # do variable interpolation here
  192. variables = list(notdone.keys())
  193. # Variables with a 'PY_' prefix in the makefile. These need to
  194. # be made available without that prefix through sysconfig.
  195. # Special care is needed to ensure that variable expansion works, even
  196. # if the expansion uses the name without a prefix.
  197. renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')
  198. while len(variables) > 0:
  199. for name in tuple(variables):
  200. value = notdone[name]
  201. m = _findvar1_rx.search(value) or _findvar2_rx.search(value)
  202. if m is not None:
  203. n = m.group(1)
  204. found = True
  205. if n in done:
  206. item = str(done[n])
  207. elif n in notdone:
  208. # get it on a subsequent round
  209. found = False
  210. elif n in os.environ:
  211. # do it like make: fall back to environment
  212. item = os.environ[n]
  213. elif n in renamed_variables:
  214. if (name.startswith('PY_') and
  215. name[3:] in renamed_variables):
  216. item = ""
  217. elif 'PY_' + n in notdone:
  218. found = False
  219. else:
  220. item = str(done['PY_' + n])
  221. else:
  222. done[n] = item = ""
  223. if found:
  224. after = value[m.end():]
  225. value = value[:m.start()] + item + after
  226. if "$" in after:
  227. notdone[name] = value
  228. else:
  229. try:
  230. value = int(value)
  231. except ValueError:
  232. done[name] = value.strip()
  233. else:
  234. done[name] = value
  235. variables.remove(name)
  236. if name.startswith('PY_') \
  237. and name[3:] in renamed_variables:
  238. name = name[3:]
  239. if name not in done:
  240. done[name] = value
  241. else:
  242. # bogus variable reference (e.g. "prefix=$/opt/python");
  243. # just drop it since we can't deal
  244. done[name] = value
  245. variables.remove(name)
  246. # strip spurious spaces
  247. for k, v in done.items():
  248. if isinstance(v, str):
  249. done[k] = v.strip()
  250. # save the results in the global dictionary
  251. vars.update(done)
  252. return vars
  253. def get_makefile_filename():
  254. """Return the path of the Makefile."""
  255. if _PYTHON_BUILD:
  256. return os.path.join(_PROJECT_BASE, "Makefile")
  257. if hasattr(sys, 'abiflags'):
  258. config_dir_name = 'config-%s%s' % (_PY_VERSION_SHORT, sys.abiflags)
  259. else:
  260. config_dir_name = 'config'
  261. return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile')
  262. def _generate_posix_vars():
  263. """Generate the Python module containing build-time variables."""
  264. import pprint
  265. vars = {}
  266. # load the installed Makefile:
  267. makefile = get_makefile_filename()
  268. try:
  269. _parse_makefile(makefile, vars)
  270. except IOError as e:
  271. msg = "invalid Python installation: unable to open %s" % makefile
  272. if hasattr(e, "strerror"):
  273. msg = msg + " (%s)" % e.strerror
  274. raise IOError(msg)
  275. # load the installed pyconfig.h:
  276. config_h = get_config_h_filename()
  277. try:
  278. with open(config_h) as f:
  279. parse_config_h(f, vars)
  280. except IOError as e:
  281. msg = "invalid Python installation: unable to open %s" % config_h
  282. if hasattr(e, "strerror"):
  283. msg = msg + " (%s)" % e.strerror
  284. raise IOError(msg)
  285. # On AIX, there are wrong paths to the linker scripts in the Makefile
  286. # -- these paths are relative to the Python source, but when installed
  287. # the scripts are in another directory.
  288. if _PYTHON_BUILD:
  289. vars['LDSHARED'] = vars['BLDSHARED']
  290. destfile = os.path.join(os.path.dirname(__file__), '_sysconfigdata.py')
  291. with open(destfile, 'w', encoding='utf8') as f:
  292. f.write('# system configuration generated and used by'
  293. ' the sysconfig module\n')
  294. f.write('build_time_vars = ')
  295. pprint.pprint(vars, stream=f)
  296. def _init_posix(vars):
  297. """Initialize the module as appropriate for POSIX systems."""
  298. # _sysconfigdata is generated at build time, see _generate_posix_vars()
  299. from _sysconfigdata import build_time_vars
  300. vars.update(build_time_vars)
  301. def _init_non_posix(vars):
  302. """Initialize the module as appropriate for NT"""
  303. # set basic install directories
  304. vars['LIBDEST'] = get_path('stdlib')
  305. vars['BINLIBDEST'] = get_path('platstdlib')
  306. vars['INCLUDEPY'] = get_path('include')
  307. vars['SO'] = '.pyd'
  308. vars['EXE'] = '.exe'
  309. vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
  310. vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))
  311. #
  312. # public APIs
  313. #
  314. def parse_config_h(fp, vars=None):
  315. """Parse a config.h-style file.
  316. A dictionary containing name/value pairs is returned. If an
  317. optional dictionary is passed in as the second argument, it is
  318. used instead of a new dictionary.
  319. """
  320. if vars is None:
  321. vars = {}
  322. define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
  323. undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
  324. while True:
  325. line = fp.readline()
  326. if not line:
  327. break
  328. m = define_rx.match(line)
  329. if m:
  330. n, v = m.group(1, 2)
  331. try:
  332. v = int(v)
  333. except ValueError:
  334. pass
  335. vars[n] = v
  336. else:
  337. m = undef_rx.match(line)
  338. if m:
  339. vars[m.group(1)] = 0
  340. return vars
  341. def get_config_h_filename():
  342. """Return the path of pyconfig.h."""
  343. if _PYTHON_BUILD:
  344. if os.name == "nt":
  345. inc_dir = os.path.join(_PROJECT_BASE, "PC")
  346. else:
  347. inc_dir = _PROJECT_BASE
  348. else:
  349. inc_dir = get_path('platinclude')
  350. return os.path.join(inc_dir, 'pyconfig.h')
  351. def get_scheme_names():
  352. """Return a tuple containing the schemes names."""
  353. return tuple(sorted(_SCHEMES.sections()))
  354. def get_path_names():
  355. """Return a tuple containing the paths names."""
  356. # xxx see if we want a static list
  357. return _SCHEMES.options('posix_prefix')
  358. def get_paths(scheme=_get_default_scheme(), vars=None, expand=True):
  359. """Return a mapping containing an install scheme.
  360. ``scheme`` is the install scheme name. If not provided, it will
  361. return the default scheme for the current platform.
  362. """
  363. if expand:
  364. return _expand_vars(scheme, vars)
  365. else:
  366. return dict(_SCHEMES.items(scheme))
  367. def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True):
  368. """Return a path corresponding to the scheme.
  369. ``scheme`` is the install scheme name.
  370. """
  371. return get_paths(scheme, vars, expand)[name]
  372. def get_config_vars(*args):
  373. """With no arguments, return a dictionary of all configuration
  374. variables relevant for the current platform.
  375. On Unix, this means every variable defined in Python's installed Makefile;
  376. On Windows and Mac OS it's a much smaller set.
  377. With arguments, return a list of values that result from looking up
  378. each argument in the configuration variable dictionary.
  379. """
  380. global _CONFIG_VARS
  381. if _CONFIG_VARS is None:
  382. _CONFIG_VARS = {}
  383. # Normalized versions of prefix and exec_prefix are handy to have;
  384. # in fact, these are the standard versions used most places in the
  385. # packaging module.
  386. _CONFIG_VARS['prefix'] = _PREFIX
  387. _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX
  388. _CONFIG_VARS['py_version'] = _PY_VERSION
  389. _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT
  390. _CONFIG_VARS['py_version_nodot'] = _PY_VERSION[0] + _PY_VERSION[2]
  391. _CONFIG_VARS['base'] = _PREFIX
  392. _CONFIG_VARS['platbase'] = _EXEC_PREFIX
  393. _CONFIG_VARS['projectbase'] = _PROJECT_BASE
  394. try:
  395. _CONFIG_VARS['abiflags'] = sys.abiflags
  396. except AttributeError:
  397. # sys.abiflags may not be defined on all platforms.
  398. _CONFIG_VARS['abiflags'] = ''
  399. if os.name in ('nt', 'os2'):
  400. _init_non_posix(_CONFIG_VARS)
  401. if os.name == 'posix':
  402. _init_posix(_CONFIG_VARS)
  403. # Setting 'userbase' is done below the call to the
  404. # init function to enable using 'get_config_var' in
  405. # the init-function.
  406. _CONFIG_VARS['userbase'] = _getuserbase()
  407. if 'srcdir' not in _CONFIG_VARS:
  408. _CONFIG_VARS['srcdir'] = _PROJECT_BASE
  409. else:
  410. _CONFIG_VARS['srcdir'] = _safe_realpath(_CONFIG_VARS['srcdir'])
  411. # Convert srcdir into an absolute path if it appears necessary.
  412. # Normally it is relative to the build directory. However, during
  413. # testing, for example, we might be running a non-installed python
  414. # from a different directory.
  415. if _PYTHON_BUILD and os.name == "posix":
  416. base = _PROJECT_BASE
  417. try:
  418. cwd = os.getcwd()
  419. except OSError:
  420. cwd = None
  421. if (not os.path.isabs(_CONFIG_VARS['srcdir']) and
  422. base != cwd):
  423. # srcdir is relative and we are not in the same directory
  424. # as the executable. Assume executable is in the build
  425. # directory and make srcdir absolute.
  426. srcdir = os.path.join(base, _CONFIG_VARS['srcdir'])
  427. _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir)
  428. if sys.platform == 'darwin':
  429. kernel_version = os.uname()[2] # Kernel version (8.4.3)
  430. major_version = int(kernel_version.split('.')[0])
  431. if major_version < 8:
  432. # On Mac OS X before 10.4, check if -arch and -isysroot
  433. # are in CFLAGS or LDFLAGS and remove them if they are.
  434. # This is needed when building extensions on a 10.3 system
  435. # using a universal build of python.
  436. for key in ('LDFLAGS', 'BASECFLAGS',
  437. # a number of derived variables. These need to be
  438. # patched up as well.
  439. 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
  440. flags = _CONFIG_VARS[key]
  441. flags = re.sub('-arch\s+\w+\s', ' ', flags)
  442. flags = re.sub('-isysroot [^ \t]*', ' ', flags)
  443. _CONFIG_VARS[key] = flags
  444. else:
  445. # Allow the user to override the architecture flags using
  446. # an environment variable.
  447. # NOTE: This name was introduced by Apple in OSX 10.5 and
  448. # is used by several scripting languages distributed with
  449. # that OS release.
  450. if 'ARCHFLAGS' in os.environ:
  451. arch = os.environ['ARCHFLAGS']
  452. for key in ('LDFLAGS', 'BASECFLAGS',
  453. # a number of derived variables. These need to be
  454. # patched up as well.
  455. 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
  456. flags = _CONFIG_VARS[key]
  457. flags = re.sub('-arch\s+\w+\s', ' ', flags)
  458. flags = flags + ' ' + arch
  459. _CONFIG_VARS[key] = flags
  460. # If we're on OSX 10.5 or later and the user tries to
  461. # compiles an extension using an SDK that is not present
  462. # on the current machine it is better to not use an SDK
  463. # than to fail.
  464. #
  465. # The major usecase for this is users using a Python.org
  466. # binary installer on OSX 10.6: that installer uses
  467. # the 10.4u SDK, but that SDK is not installed by default
  468. # when you install Xcode.
  469. #
  470. CFLAGS = _CONFIG_VARS.get('CFLAGS', '')
  471. m = re.search('-isysroot\s+(\S+)', CFLAGS)
  472. if m is not None:
  473. sdk = m.group(1)
  474. if not os.path.exists(sdk):
  475. for key in ('LDFLAGS', 'BASECFLAGS',
  476. # a number of derived variables. These need to be
  477. # patched up as well.
  478. 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
  479. flags = _CONFIG_VARS[key]
  480. flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags)
  481. _CONFIG_VARS[key] = flags
  482. if args:
  483. vals = []
  484. for name in args:
  485. vals.append(_CONFIG_VARS.get(name))
  486. return vals
  487. else:
  488. return _CONFIG_VARS
  489. def get_config_var(name):
  490. """Return the value of a single variable using the dictionary returned by
  491. 'get_config_vars()'.
  492. Equivalent to get_config_vars().get(name)
  493. """
  494. return get_config_vars().get(name)
  495. def get_platform():
  496. """Return a string that identifies the current platform.
  497. This is used mainly to distinguish platform-specific build directories and
  498. platform-specific built distributions. Typically includes the OS name
  499. and version and the architecture (as supplied by 'os.uname()'),
  500. although the exact information included depends on the OS; eg. for IRIX
  501. the architecture isn't particularly important (IRIX only runs on SGI
  502. hardware), but for Linux the kernel version isn't particularly
  503. important.
  504. Examples of returned values:
  505. linux-i586
  506. linux-alpha (?)
  507. solaris-2.6-sun4u
  508. irix-5.3
  509. irix64-6.2
  510. Windows will return one of:
  511. win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
  512. win-ia64 (64bit Windows on Itanium)
  513. win32 (all others - specifically, sys.platform is returned)
  514. For other non-POSIX platforms, currently just returns 'sys.platform'.
  515. """
  516. if os.name == 'nt':
  517. # sniff sys.version for architecture.
  518. prefix = " bit ("
  519. i = sys.version.find(prefix)
  520. if i == -1:
  521. return sys.platform
  522. j = sys.version.find(")", i)
  523. look = sys.version[i+len(prefix):j].lower()
  524. if look == 'amd64':
  525. return 'win-amd64'
  526. if look == 'itanium':
  527. return 'win-ia64'
  528. return sys.platform
  529. if os.name != "posix" or not hasattr(os, 'uname'):
  530. # XXX what about the architecture? NT is Intel or Alpha,
  531. # Mac OS is M68k or PPC, etc.
  532. return sys.platform
  533. # Try to distinguish various flavours of Unix
  534. osname, host, release, version, machine = os.uname()
  535. # Convert the OS name to lowercase, remove '/' characters
  536. # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh")
  537. osname = osname.lower().replace('/', '')
  538. machine = machine.replace(' ', '_')
  539. machine = machine.replace('/', '-')
  540. if osname[:5] == "linux":
  541. # At least on Linux/Intel, 'machine' is the processor --
  542. # i386, etc.
  543. # XXX what about Alpha, SPARC, etc?
  544. return "%s-%s" % (osname, machine)
  545. elif osname[:5] == "sunos":
  546. if release[0] >= "5": # SunOS 5 == Solaris 2
  547. osname = "solaris"
  548. release = "%d.%s" % (int(release[0]) - 3, release[2:])
  549. # We can't use "platform.architecture()[0]" because a
  550. # bootstrap problem. We use a dict to get an error
  551. # if some suspicious happens.
  552. bitness = {2147483647:"32bit", 9223372036854775807:"64bit"}
  553. machine += ".%s" % bitness[sys.maxsize]
  554. # fall through to standard osname-release-machine representation
  555. elif osname[:4] == "irix": # could be "irix64"!
  556. return "%s-%s" % (osname, release)
  557. elif osname[:3] == "aix":
  558. return "%s-%s.%s" % (osname, version, release)
  559. elif osname[:6] == "cygwin":
  560. osname = "cygwin"
  561. rel_re = re.compile(r'[\d.]+')
  562. m = rel_re.match(release)
  563. if m:
  564. release = m.group()
  565. elif osname[:6] == "darwin":
  566. #
  567. # For our purposes, we'll assume that the system version from
  568. # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set
  569. # to. This makes the compatibility story a bit more sane because the
  570. # machine is going to compile and link as if it were
  571. # MACOSX_DEPLOYMENT_TARGET.
  572. cfgvars = get_config_vars()
  573. macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET')
  574. if True:
  575. # Always calculate the release of the running machine,
  576. # needed to determine if we can build fat binaries or not.
  577. macrelease = macver
  578. # Get the system version. Reading this plist is a documented
  579. # way to get the system version (see the documentation for
  580. # the Gestalt Manager)
  581. try:
  582. f = open('/System/Library/CoreServices/SystemVersion.plist')
  583. except IOError:
  584. # We're on a plain darwin box, fall back to the default
  585. # behaviour.
  586. pass
  587. else:
  588. try:
  589. m = re.search(r'<key>ProductUserVisibleVersion</key>\s*'
  590. r'<string>(.*?)</string>', f.read())
  591. finally:
  592. f.close()
  593. if m is not None:
  594. macrelease = '.'.join(m.group(1).split('.')[:2])
  595. # else: fall back to the default behaviour
  596. if not macver:
  597. macver = macrelease
  598. if macver:
  599. release = macver
  600. osname = "macosx"
  601. if ((macrelease + '.') >= '10.4.' and
  602. '-arch' in get_config_vars().get('CFLAGS', '').strip()):
  603. # The universal build will build fat binaries, but not on
  604. # systems before 10.4
  605. #
  606. # Try to detect 4-way universal builds, those have machine-type
  607. # 'universal' instead of 'fat'.
  608. machine = 'fat'
  609. cflags = get_config_vars().get('CFLAGS')
  610. archs = re.findall('-arch\s+(\S+)', cflags)
  611. archs = tuple(sorted(set(archs)))
  612. if len(archs) == 1:
  613. machine = archs[0]
  614. elif archs == ('i386', 'ppc'):
  615. machine = 'fat'
  616. elif archs == ('i386', 'x86_64'):
  617. machine = 'intel'
  618. elif archs == ('i386', 'ppc', 'x86_64'):
  619. machine = 'fat3'
  620. elif archs == ('ppc64', 'x86_64'):
  621. machine = 'fat64'
  622. elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'):
  623. machine = 'universal'
  624. else:
  625. raise ValueError(
  626. "Don't know machine value for archs=%r" % (archs,))
  627. elif machine == 'i386':
  628. # On OSX the machine type returned by uname is always the
  629. # 32-bit variant, even if the executable architecture is
  630. # the 64-bit variant
  631. if sys.maxsize >= 2**32:
  632. machine = 'x86_64'
  633. elif machine in ('PowerPC', 'Power_Macintosh'):
  634. # Pick a sane name for the PPC architecture.
  635. # See 'i386' case
  636. if sys.maxsize >= 2**32:
  637. machine = 'ppc64'
  638. else:
  639. machine = 'ppc'
  640. return "%s-%s-%s" % (osname, release, machine)
  641. def get_python_version():
  642. return _PY_VERSION_SHORT
  643. def _print_dict(title, data):
  644. for index, (key, value) in enumerate(sorted(data.items())):
  645. if index == 0:
  646. print('%s: ' % (title))
  647. print('\t%s = "%s"' % (key, value))
  648. def _main():
  649. """Display all information sysconfig detains."""
  650. if '--generate-posix-vars' in sys.argv:
  651. _generate_posix_vars()
  652. return
  653. print('Platform: "%s"' % get_platform())
  654. print('Python version: "%s"' % get_python_version())
  655. print('Current installation scheme: "%s"' % _get_default_scheme())
  656. print()
  657. _print_dict('Paths', get_paths())
  658. print()
  659. _print_dict('Variables', get_config_vars())
  660. if __name__ == '__main__':
  661. _main()