diff options
Diffstat (limited to 'Lib/sysconfig.py')
-rw-r--r-- | Lib/sysconfig.py | 307 |
1 files changed, 161 insertions, 146 deletions
diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index 2279a51d5e..36c7aa49a5 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -1,9 +1,10 @@ -"""Provide access to Python's configuration information. +"""Access to Python's configuration information.""" -""" -import sys import os +import re +import sys from os.path import pardir, realpath +from configparser import RawConfigParser __all__ = [ 'get_config_h_filename', @@ -17,91 +18,51 @@ __all__ = [ 'get_python_version', 'get_scheme_names', 'parse_config_h', - ] - -_INSTALL_SCHEMES = { - 'posix_prefix': { - 'stdlib': '{base}/lib/python{py_version_short}', - 'platstdlib': '{platbase}/lib/python{py_version_short}', - 'purelib': '{base}/lib/python{py_version_short}/site-packages', - 'platlib': '{platbase}/lib/python{py_version_short}/site-packages', - 'include': - '{base}/include/python{py_version_short}{abiflags}', - 'platinclude': - '{platbase}/include/python{py_version_short}{abiflags}', - 'scripts': '{base}/bin', - 'data': '{base}', - }, - 'posix_home': { - 'stdlib': '{base}/lib/python', - 'platstdlib': '{base}/lib/python', - 'purelib': '{base}/lib/python', - 'platlib': '{base}/lib/python', - 'include': '{base}/include/python', - 'platinclude': '{base}/include/python', - 'scripts': '{base}/bin', - 'data' : '{base}', - }, - 'nt': { - 'stdlib': '{base}/Lib', - 'platstdlib': '{base}/Lib', - 'purelib': '{base}/Lib/site-packages', - 'platlib': '{base}/Lib/site-packages', - 'include': '{base}/Include', - 'platinclude': '{base}/Include', - 'scripts': '{base}/Scripts', - 'data' : '{base}', - }, - 'os2': { - 'stdlib': '{base}/Lib', - 'platstdlib': '{base}/Lib', - 'purelib': '{base}/Lib/site-packages', - 'platlib': '{base}/Lib/site-packages', - 'include': '{base}/Include', - 'platinclude': '{base}/Include', - 'scripts': '{base}/Scripts', - 'data' : '{base}', - }, - 'os2_home': { - 'stdlib': '{userbase}/lib/python{py_version_short}', - 'platstdlib': '{userbase}/lib/python{py_version_short}', - 'purelib': '{userbase}/lib/python{py_version_short}/site-packages', - 'platlib': '{userbase}/lib/python{py_version_short}/site-packages', - 'include': '{userbase}/include/python{py_version_short}', - 'scripts': '{userbase}/bin', - 'data' : '{userbase}', - }, - 'nt_user': { - 'stdlib': '{userbase}/Python{py_version_nodot}', - 'platstdlib': '{userbase}/Python{py_version_nodot}', - 'purelib': '{userbase}/Python{py_version_nodot}/site-packages', - 'platlib': '{userbase}/Python{py_version_nodot}/site-packages', - 'include': '{userbase}/Python{py_version_nodot}/Include', - 'scripts': '{userbase}/Scripts', - 'data' : '{userbase}', - }, - 'posix_user': { - 'stdlib': '{userbase}/lib/python{py_version_short}', - 'platstdlib': '{userbase}/lib/python{py_version_short}', - 'purelib': '{userbase}/lib/python{py_version_short}/site-packages', - 'platlib': '{userbase}/lib/python{py_version_short}/site-packages', - 'include': '{userbase}/include/python{py_version_short}', - 'scripts': '{userbase}/bin', - 'data' : '{userbase}', - }, - 'osx_framework_user': { - 'stdlib': '{userbase}/lib/python', - 'platstdlib': '{userbase}/lib/python', - 'purelib': '{userbase}/lib/python/site-packages', - 'platlib': '{userbase}/lib/python/site-packages', - 'include': '{userbase}/include', - 'scripts': '{userbase}/bin', - 'data' : '{userbase}', - }, - } - -_SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include', - 'scripts', 'data') +] + +# let's read the configuration file +# XXX _CONFIG_DIR will be set by the Makefile later +_CONFIG_DIR = os.path.normpath(os.path.dirname(__file__)) +_CONFIG_FILE = os.path.join(_CONFIG_DIR, 'sysconfig.cfg') +_SCHEMES = RawConfigParser(dict_type=dict) # Faster than OrderedDict +_SCHEMES.read(_CONFIG_FILE) +_VAR_REPL = re.compile(r'\{([^{]*?)\}') + + +def _expand_globals(config): + if config.has_section('globals'): + globals = config.items('globals') + else: + globals = tuple() + + sections = config.sections() + for section in sections: + if section == 'globals': + continue + for option, value in globals: + if config.has_option(section, option): + continue + config.set(section, option, value) + config.remove_section('globals') + + # now expanding local variables defined in the cfg file + # + for section in config.sections(): + variables = dict(config.items(section)) + + def _replacer(matchobj): + name = matchobj.group(1) + if name in variables: + return variables[name] + return matchobj.group(0) + + for option, value in config.items(section): + config.set(section, option, _VAR_REPL.sub(_replacer, value)) + +_expand_globals(_SCHEMES) + + # FIXME don't rely on sys.version here, its format is an implementatin detail + # of CPython, use sys.version_info or sys.hexversion _PY_VERSION = sys.version.split()[0] _PY_VERSION_SHORT = sys.version[:3] _PY_VERSION_SHORT_NO_DOT = _PY_VERSION[0] + _PY_VERSION[2] @@ -110,6 +71,7 @@ _EXEC_PREFIX = os.path.normpath(sys.exec_prefix) _CONFIG_VARS = None _USER_BASE = None + def _safe_realpath(path): try: return realpath(path) @@ -132,6 +94,7 @@ if os.name == "nt" and "\\pc\\v" in _PROJECT_BASE[-10:].lower(): if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower(): _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir)) + def is_python_build(): for fn in ("Setup.dist", "Setup.local"): if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)): @@ -142,17 +105,25 @@ _PYTHON_BUILD = is_python_build() if _PYTHON_BUILD: for scheme in ('posix_prefix', 'posix_home'): - _INSTALL_SCHEMES[scheme]['include'] = '{srcdir}/Include' - _INSTALL_SCHEMES[scheme]['platinclude'] = '{projectbase}/.' + _SCHEMES.set(scheme, 'include', '{srcdir}/Include') + _SCHEMES.set(scheme, 'platinclude', '{projectbase}/.') + + +def _subst_vars(path, local_vars): + """In the string `path`, replace tokens like {some.thing} with the + corresponding value from the map `local_vars`. + + If there is no corresponding value, leave the token unchanged. + """ + def _replacer(matchobj): + name = matchobj.group(1) + if name in local_vars: + return local_vars[name] + elif name in os.environ: + return os.environ[name] + return matchobj.group(0) + return _VAR_REPL.sub(_replacer, path) -def _subst_vars(s, local_vars): - try: - return s.format(**local_vars) - except KeyError: - try: - return s.format(**os.environ) - except KeyError as var: - raise AttributeError('{%s}' % var) def _extend_dict(target_dict, other_dict): target_keys = target_dict.keys() @@ -161,41 +132,63 @@ def _extend_dict(target_dict, other_dict): continue target_dict[key] = value + def _expand_vars(scheme, vars): res = {} if vars is None: vars = {} _extend_dict(vars, get_config_vars()) - for key, value in _INSTALL_SCHEMES[scheme].items(): + for key, value in _SCHEMES.items(scheme): if os.name in ('posix', 'nt'): value = os.path.expanduser(value) res[key] = os.path.normpath(_subst_vars(value, vars)) return res + +def format_value(value, vars): + def _replacer(matchobj): + name = matchobj.group(1) + if name in vars: + return vars[name] + return matchobj.group(0) + return _VAR_REPL.sub(_replacer, value) + + def _get_default_scheme(): if os.name == 'posix': # the default scheme for posix is posix_prefix return 'posix_prefix' return os.name + def _getuserbase(): env_base = os.environ.get("PYTHONUSERBASE", None) + def joinuser(*args): return os.path.expanduser(os.path.join(*args)) # what about 'os2emx', 'riscos' ? if os.name == "nt": base = os.environ.get("APPDATA") or "~" - return env_base if env_base else joinuser(base, "Python") + if env_base: + return env_base + else: + return joinuser(base, "Python") if sys.platform == "darwin": framework = get_config_var("PYTHONFRAMEWORK") if framework: - return env_base if env_base else joinuser("~", "Library", framework, "%d.%d"%( - sys.version_info[:2])) + if env_base: + return env_base + else: + return joinuser("~", "Library", framework, "%d.%d" % + sys.version_info[:2]) - return env_base if env_base else joinuser("~", ".local") + if env_base: + return env_base + else: + return joinuser("~", ".local") def _parse_makefile(filename, vars=None): @@ -205,7 +198,6 @@ def _parse_makefile(filename, vars=None): optional dictionary is passed in as the second argument, it is used instead of a new dictionary. """ - import re # Regexes needed for parsing Makefile (and similar syntaxes, # like old-style Setup files). _variable_rx = re.compile("([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") @@ -267,7 +259,8 @@ def _parse_makefile(filename, vars=None): item = os.environ[n] elif n in renamed_variables: - if name.startswith('PY_') and name[3:] in renamed_variables: + if (name.startswith('PY_') and + name[3:] in renamed_variables): item = "" elif 'PY_' + n in notdone: @@ -300,7 +293,6 @@ def _parse_makefile(filename, vars=None): if name not in done: done[name] = value - else: # bogus variable reference (e.g. "prefix=$/opt/python"); # just drop it since we can't deal @@ -321,13 +313,17 @@ def get_makefile_filename(): """Return the path of the Makefile.""" if _PYTHON_BUILD: return os.path.join(_PROJECT_BASE, "Makefile") - return os.path.join(get_path('stdlib'), - 'config-{}{}'.format(_PY_VERSION_SHORT, sys.abiflags), - 'Makefile') - - -def _init_posix(vars): - """Initialize the module as appropriate for POSIX systems.""" + if hasattr(sys, 'abiflags'): + config_dir_name = 'config-%s%s' % (_PY_VERSION_SHORT, sys.abiflags) + else: + config_dir_name = 'config' + return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile') + +def _generate_posix_vars(): + """Generate the Python module containing build-time variables.""" + import pprint + vars = {} + destfile = os.path.join(os.path.dirname(__file__), '_sysconfigdata.py') # load the installed Makefile: makefile = get_makefile_filename() try: @@ -352,6 +348,15 @@ def _init_posix(vars): # the scripts are in another directory. if _PYTHON_BUILD: vars['LDSHARED'] = vars['BLDSHARED'] + with open(destfile, 'w', encoding='utf8') as f: + f.write('build_time_vars = ') + pprint.pprint(vars, stream=f) + +def _init_posix(vars): + """Initialize the module as appropriate for POSIX systems.""" + # _sysconfigdata is generated at build time, see _generate_posix_vars() + from _sysconfigdata import build_time_vars + vars.update(build_time_vars) def _init_non_posix(vars): """Initialize the module as appropriate for NT""" @@ -376,7 +381,6 @@ def parse_config_h(fp, vars=None): optional dictionary is passed in as the second argument, it is used instead of a new dictionary. """ - import re if vars is None: vars = {} define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n") @@ -389,8 +393,10 @@ def parse_config_h(fp, vars=None): m = define_rx.match(line) if m: n, v = m.group(1, 2) - try: v = int(v) - except ValueError: pass + try: + v = int(v) + except ValueError: + pass vars[n] = v else: m = undef_rx.match(line) @@ -398,6 +404,7 @@ def parse_config_h(fp, vars=None): vars[m.group(1)] = 0 return vars + def get_config_h_filename(): """Return the path of pyconfig.h.""" if _PYTHON_BUILD: @@ -409,15 +416,17 @@ def get_config_h_filename(): inc_dir = get_path('platinclude') return os.path.join(inc_dir, 'pyconfig.h') + def get_scheme_names(): """Return a tuple containing the schemes names.""" - schemes = list(_INSTALL_SCHEMES.keys()) - schemes.sort() - return tuple(schemes) + return tuple(sorted(_SCHEMES.sections())) + def get_path_names(): """Return a tuple containing the paths names.""" - return _SCHEME_KEYS + # xxx see if we want a static list + return _SCHEMES.options('posix_prefix') + def get_paths(scheme=_get_default_scheme(), vars=None, expand=True): """Return a mapping containing an install scheme. @@ -428,7 +437,8 @@ def get_paths(scheme=_get_default_scheme(), vars=None, expand=True): if expand: return _expand_vars(scheme, vars) else: - return _INSTALL_SCHEMES[scheme] + return dict(_SCHEMES.items(scheme)) + def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True): """Return a path corresponding to the scheme. @@ -437,6 +447,7 @@ def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True): """ return get_paths(scheme, vars, expand)[name] + def get_config_vars(*args): """With no arguments, return a dictionary of all configuration variables relevant for the current platform. @@ -447,13 +458,12 @@ def get_config_vars(*args): With arguments, return a list of values that result from looking up each argument in the configuration variable dictionary. """ - import re global _CONFIG_VARS if _CONFIG_VARS is None: _CONFIG_VARS = {} # Normalized versions of prefix and exec_prefix are handy to have; # in fact, these are the standard versions used most places in the - # Distutils. + # packaging module. _CONFIG_VARS['prefix'] = _PREFIX _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX _CONFIG_VARS['py_version'] = _PY_VERSION @@ -475,14 +485,14 @@ def get_config_vars(*args): # Setting 'userbase' is done below the call to the # init function to enable using 'get_config_var' in # the init-function. - _CONFIG_VARS['userbase'] = _getuserbase() + if sys.version >= '2.6': + _CONFIG_VARS['userbase'] = _getuserbase() if 'srcdir' not in _CONFIG_VARS: _CONFIG_VARS['srcdir'] = _PROJECT_BASE else: _CONFIG_VARS['srcdir'] = _safe_realpath(_CONFIG_VARS['srcdir']) - # Convert srcdir into an absolute path if it appears necessary. # Normally it is relative to the build directory. However, during # testing, for example, we might be running a non-installed python @@ -502,7 +512,7 @@ def get_config_vars(*args): _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir) if sys.platform == 'darwin': - kernel_version = os.uname()[2] # Kernel version (8.4.3) + kernel_version = os.uname()[2] # Kernel version (8.4.3) major_version = int(kernel_version.split('.')[0]) if major_version < 8: @@ -568,6 +578,7 @@ def get_config_vars(*args): else: return _CONFIG_VARS + def get_config_var(name): """Return the value of a single variable using the dictionary returned by 'get_config_vars()'. @@ -576,6 +587,7 @@ def get_config_var(name): """ return get_config_vars().get(name) + def get_platform(): """Return a string that identifies the current platform. @@ -601,7 +613,6 @@ def get_platform(): For other non-POSIX platforms, currently just returns 'sys.platform'. """ - import re if os.name == 'nt': # sniff sys.version for architecture. prefix = " bit (" @@ -646,7 +657,7 @@ def get_platform(): return "%s-%s.%s" % (osname, version, release) elif osname[:6] == "cygwin": osname = "cygwin" - rel_re = re.compile (r'[\d.]+') + rel_re = re.compile(r'[\d.]+') m = rel_re.match(release) if m: release = m.group() @@ -657,11 +668,10 @@ def get_platform(): # to. This makes the compatibility story a bit more sane because the # machine is going to compile and link as if it were # MACOSX_DEPLOYMENT_TARGET. - # cfgvars = get_config_vars() macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') - if 1: + if True: # Always calculate the release of the running machine, # needed to determine if we can build fat binaries or not. @@ -677,14 +687,13 @@ def get_platform(): pass else: try: - m = re.search( - r'<key>ProductUserVisibleVersion</key>\s*' + - r'<string>(.*?)</string>', f.read()) - if m is not None: - macrelease = '.'.join(m.group(1).split('.')[:2]) - # else: fall back to the default behaviour + m = re.search(r'<key>ProductUserVisibleVersion</key>\s*' + r'<string>(.*?)</string>', f.read()) finally: f.close() + if m is not None: + macrelease = '.'.join(m.group(1).split('.')[:2]) + # else: fall back to the default behaviour if not macver: macver = macrelease @@ -693,8 +702,8 @@ def get_platform(): release = macver osname = "macosx" - if (macrelease + '.') >= '10.4.' and \ - '-arch' in get_config_vars().get('CFLAGS', '').strip(): + if ((macrelease + '.') >= '10.4.' and + '-arch' in get_config_vars().get('CFLAGS', '').strip()): # The universal build will build fat binaries, but not on # systems before 10.4 # @@ -721,7 +730,7 @@ def get_platform(): machine = 'universal' else: raise ValueError( - "Don't know machine value for archs=%r"%(archs,)) + "Don't know machine value for archs=%r" % (archs,)) elif machine == 'i386': # On OSX the machine type returned by uname is always the @@ -744,21 +753,27 @@ def get_platform(): def get_python_version(): return _PY_VERSION_SHORT + def _print_dict(title, data): for index, (key, value) in enumerate(sorted(data.items())): if index == 0: - print('{0}: '.format(title)) - print('\t{0} = "{1}"'.format(key, value)) + print('%s: ' % (title)) + print('\t%s = "%s"' % (key, value)) + def _main(): """Display all information sysconfig detains.""" - print('Platform: "{0}"'.format(get_platform())) - print('Python version: "{0}"'.format(get_python_version())) - print('Current installation scheme: "{0}"'.format(_get_default_scheme())) - print('') + if '--generate-posix-vars' in sys.argv: + _generate_posix_vars() + return + print('Platform: "%s"' % get_platform()) + print('Python version: "%s"' % get_python_version()) + print('Current installation scheme: "%s"' % _get_default_scheme()) + print() _print_dict('Paths', get_paths()) - print('') + print() _print_dict('Variables', get_config_vars()) + if __name__ == '__main__': _main() |