1"""Provide access to Python's configuration information. The specific 2configuration variables available depend heavily on the platform and 3configuration. The values may be retrieved using 4get_config_var(name), and the list of variables is available via 5get_config_vars().keys(). Additional convenience functions are also 6available. 7 8Written by: Fred L. Drake, Jr. 9Email: <fdrake@acm.org> 10""" 11 12import _imp 13import os 14import re 15import sys 16import warnings 17 18from functools import partial 19 20from .errors import DistutilsPlatformError 21 22from sysconfig import ( 23 _PREFIX as PREFIX, 24 _BASE_PREFIX as BASE_PREFIX, 25 _EXEC_PREFIX as EXEC_PREFIX, 26 _BASE_EXEC_PREFIX as BASE_EXEC_PREFIX, 27 _PROJECT_BASE as project_base, 28 _PYTHON_BUILD as python_build, 29 _init_posix as sysconfig_init_posix, 30 parse_config_h as sysconfig_parse_config_h, 31 32 _init_non_posix, 33 _is_python_source_dir, 34 _sys_home, 35 36 _variable_rx, 37 _findvar1_rx, 38 _findvar2_rx, 39 40 expand_makefile_vars, 41 is_python_build, 42 get_config_h_filename, 43 get_config_var, 44 get_config_vars, 45 get_makefile_filename, 46 get_python_version, 47) 48 49# This is better than 50# from sysconfig import _CONFIG_VARS as _config_vars 51# because it makes sure that the global dictionary is initialized 52# which might not be true in the time of import. 53_config_vars = get_config_vars() 54 55if os.name == "nt": 56 from sysconfig import _fix_pcbuild 57 58warnings.warn( 59 'The distutils.sysconfig module is deprecated, use sysconfig instead', 60 DeprecationWarning, 61 stacklevel=2 62) 63 64 65# Following functions are the same as in sysconfig but with different API 66def parse_config_h(fp, g=None): 67 return sysconfig_parse_config_h(fp, vars=g) 68 69 70_python_build = partial(is_python_build, check_home=True) 71_init_posix = partial(sysconfig_init_posix, _config_vars) 72_init_nt = partial(_init_non_posix, _config_vars) 73 74 75# Similar function is also implemented in sysconfig as _parse_makefile 76# but without the parsing capabilities of distutils.text_file.TextFile. 77def parse_makefile(fn, g=None): 78 """Parse a Makefile-style file. 79 A dictionary containing name/value pairs is returned. If an 80 optional dictionary is passed in as the second argument, it is 81 used instead of a new dictionary. 82 """ 83 from distutils.text_file import TextFile 84 fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1, errors="surrogateescape") 85 86 if g is None: 87 g = {} 88 done = {} 89 notdone = {} 90 91 while True: 92 line = fp.readline() 93 if line is None: # eof 94 break 95 m = re.match(_variable_rx, line) 96 if m: 97 n, v = m.group(1, 2) 98 v = v.strip() 99 # `$$' is a literal `$' in make 100 tmpv = v.replace('$$', '') 101 102 if "$" in tmpv: 103 notdone[n] = v 104 else: 105 try: 106 v = int(v) 107 except ValueError: 108 # insert literal `$' 109 done[n] = v.replace('$$', '$') 110 else: 111 done[n] = v 112 113 # Variables with a 'PY_' prefix in the makefile. These need to 114 # be made available without that prefix through sysconfig. 115 # Special care is needed to ensure that variable expansion works, even 116 # if the expansion uses the name without a prefix. 117 renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS') 118 119 # do variable interpolation here 120 while notdone: 121 for name in list(notdone): 122 value = notdone[name] 123 m = re.search(_findvar1_rx, value) or re.search(_findvar2_rx, value) 124 if m: 125 n = m.group(1) 126 found = True 127 if n in done: 128 item = str(done[n]) 129 elif n in notdone: 130 # get it on a subsequent round 131 found = False 132 elif n in os.environ: 133 # do it like make: fall back to environment 134 item = os.environ[n] 135 136 elif n in renamed_variables: 137 if name.startswith('PY_') and name[3:] in renamed_variables: 138 item = "" 139 140 elif 'PY_' + n in notdone: 141 found = False 142 143 else: 144 item = str(done['PY_' + n]) 145 else: 146 done[n] = item = "" 147 if found: 148 after = value[m.end():] 149 value = value[:m.start()] + item + after 150 if "$" in after: 151 notdone[name] = value 152 else: 153 try: value = int(value) 154 except ValueError: 155 done[name] = value.strip() 156 else: 157 done[name] = value 158 del notdone[name] 159 160 if name.startswith('PY_') \ 161 and name[3:] in renamed_variables: 162 163 name = name[3:] 164 if name not in done: 165 done[name] = value 166 else: 167 # bogus variable reference; just drop it since we can't deal 168 del notdone[name] 169 170 fp.close() 171 172 # strip spurious spaces 173 for k, v in done.items(): 174 if isinstance(v, str): 175 done[k] = v.strip() 176 177 # save the results in the global dictionary 178 g.update(done) 179 return g 180 181 182# Following functions are deprecated together with this module and they 183# have no direct replacement 184 185# Calculate the build qualifier flags if they are defined. Adding the flags 186# to the include and lib directories only makes sense for an installation, not 187# an in-source build. 188build_flags = '' 189try: 190 if not python_build: 191 build_flags = sys.abiflags 192except AttributeError: 193 # It's not a configure-based build, so the sys module doesn't have 194 # this attribute, which is fine. 195 pass 196 197 198def customize_compiler(compiler): 199 """Do any platform-specific customization of a CCompiler instance. 200 201 Mainly needed on Unix, so we can plug in the information that 202 varies across Unices and is stored in Python's Makefile. 203 """ 204 if compiler.compiler_type == "unix": 205 if sys.platform == "darwin": 206 # Perform first-time customization of compiler-related 207 # config vars on OS X now that we know we need a compiler. 208 # This is primarily to support Pythons from binary 209 # installers. The kind and paths to build tools on 210 # the user system may vary significantly from the system 211 # that Python itself was built on. Also the user OS 212 # version and build tools may not support the same set 213 # of CPU architectures for universal builds. 214 if not _config_vars.get('CUSTOMIZED_OSX_COMPILER'): 215 import _osx_support 216 _osx_support.customize_compiler(_config_vars) 217 _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True' 218 219 (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \ 220 get_config_vars('CC', 'CXX', 'CFLAGS', 221 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') 222 223 if 'CC' in os.environ: 224 newcc = os.environ['CC'] 225 if (sys.platform == 'darwin' 226 and 'LDSHARED' not in os.environ 227 and ldshared.startswith(cc)): 228 # On OS X, if CC is overridden, use that as the default 229 # command for LDSHARED as well 230 ldshared = newcc + ldshared[len(cc):] 231 cc = newcc 232 if 'CXX' in os.environ: 233 cxx = os.environ['CXX'] 234 if 'LDSHARED' in os.environ: 235 ldshared = os.environ['LDSHARED'] 236 if 'CPP' in os.environ: 237 cpp = os.environ['CPP'] 238 else: 239 cpp = cc + " -E" # not always 240 if 'LDFLAGS' in os.environ: 241 ldshared = ldshared + ' ' + os.environ['LDFLAGS'] 242 if 'CFLAGS' in os.environ: 243 cflags = cflags + ' ' + os.environ['CFLAGS'] 244 ldshared = ldshared + ' ' + os.environ['CFLAGS'] 245 if 'CPPFLAGS' in os.environ: 246 cpp = cpp + ' ' + os.environ['CPPFLAGS'] 247 cflags = cflags + ' ' + os.environ['CPPFLAGS'] 248 ldshared = ldshared + ' ' + os.environ['CPPFLAGS'] 249 if 'AR' in os.environ: 250 ar = os.environ['AR'] 251 if 'ARFLAGS' in os.environ: 252 archiver = ar + ' ' + os.environ['ARFLAGS'] 253 else: 254 archiver = ar + ' ' + ar_flags 255 256 cc_cmd = cc + ' ' + cflags 257 compiler.set_executables( 258 preprocessor=cpp, 259 compiler=cc_cmd, 260 compiler_so=cc_cmd + ' ' + ccshared, 261 compiler_cxx=cxx, 262 linker_so=ldshared, 263 linker_exe=cc, 264 archiver=archiver) 265 266 compiler.shared_lib_extension = shlib_suffix 267 268 269def get_python_inc(plat_specific=0, prefix=None): 270 """Return the directory containing installed Python header files. 271 272 If 'plat_specific' is false (the default), this is the path to the 273 non-platform-specific header files, i.e. Python.h and so on; 274 otherwise, this is the path to platform-specific header files 275 (namely pyconfig.h). 276 277 If 'prefix' is supplied, use it instead of sys.base_prefix or 278 sys.base_exec_prefix -- i.e., ignore 'plat_specific'. 279 """ 280 if prefix is None: 281 prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX 282 if os.name == "posix": 283 if python_build: 284 # Assume the executable is in the build directory. The 285 # pyconfig.h file should be in the same directory. Since 286 # the build directory may not be the source directory, we 287 # must use "srcdir" from the makefile to find the "Include" 288 # directory. 289 if plat_specific: 290 return _sys_home or project_base 291 else: 292 incdir = os.path.join(get_config_var('srcdir'), 'Include') 293 return os.path.normpath(incdir) 294 python_dir = 'python' + get_python_version() + build_flags 295 return os.path.join(prefix, "include", python_dir) 296 elif os.name == "nt": 297 if python_build: 298 # Include both the include and PC dir to ensure we can find 299 # pyconfig.h 300 return (os.path.join(prefix, "include") + os.path.pathsep + 301 os.path.join(prefix, "PC")) 302 return os.path.join(prefix, "include") 303 else: 304 raise DistutilsPlatformError( 305 "I don't know where Python installs its C header files " 306 "on platform '%s'" % os.name) 307 308 309def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): 310 """Return the directory containing the Python library (standard or 311 site additions). 312 313 If 'plat_specific' is true, return the directory containing 314 platform-specific modules, i.e. any module from a non-pure-Python 315 module distribution; otherwise, return the platform-shared library 316 directory. If 'standard_lib' is true, return the directory 317 containing standard Python library modules; otherwise, return the 318 directory for site-specific modules. 319 320 If 'prefix' is supplied, use it instead of sys.base_prefix or 321 sys.base_exec_prefix -- i.e., ignore 'plat_specific'. 322 """ 323 if prefix is None: 324 if standard_lib: 325 prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX 326 else: 327 prefix = plat_specific and EXEC_PREFIX or PREFIX 328 329 if os.name == "posix": 330 if plat_specific or standard_lib: 331 # Platform-specific modules (any module from a non-pure-Python 332 # module distribution) or standard Python library modules. 333 libdir = sys.platlibdir 334 else: 335 # Pure Python 336 libdir = "lib" 337 libpython = os.path.join(prefix, libdir, 338 "python" + get_python_version()) 339 if standard_lib: 340 return libpython 341 else: 342 return os.path.join(libpython, "site-packages") 343 elif os.name == "nt": 344 if standard_lib: 345 return os.path.join(prefix, "Lib") 346 else: 347 return os.path.join(prefix, "Lib", "site-packages") 348 else: 349 raise DistutilsPlatformError( 350 "I don't know where Python installs its library " 351 "on platform '%s'" % os.name) 352