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 16 17from .errors import DistutilsPlatformError 18 19# These are needed in a couple of spots, so just compute them once. 20PREFIX = os.path.normpath(sys.prefix) 21EXEC_PREFIX = os.path.normpath(sys.exec_prefix) 22BASE_PREFIX = os.path.normpath(sys.base_prefix) 23BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix) 24 25# Path to the base directory of the project. On Windows the binary may 26# live in project/PCbuild/win32 or project/PCbuild/amd64. 27# set for cross builds 28if "_PYTHON_PROJECT_BASE" in os.environ: 29 project_base = os.path.abspath(os.environ["_PYTHON_PROJECT_BASE"]) 30else: 31 project_base = os.path.dirname(os.path.abspath(sys.executable)) 32 33 34# python_build: (Boolean) if true, we're either building Python or 35# building an extension with an un-installed Python, so we use 36# different (hard-wired) directories. 37# Setup.local is available for Makefile builds including VPATH builds, 38# Setup.dist is available on Windows 39def _is_python_source_dir(d): 40 for fn in ("Setup.dist", "Setup.local"): 41 if os.path.isfile(os.path.join(d, "Modules", fn)): 42 return True 43 return False 44 45_sys_home = getattr(sys, '_home', None) 46 47if os.name == 'nt': 48 def _fix_pcbuild(d): 49 if d and os.path.normcase(d).startswith( 50 os.path.normcase(os.path.join(PREFIX, "PCbuild"))): 51 return PREFIX 52 return d 53 project_base = _fix_pcbuild(project_base) 54 _sys_home = _fix_pcbuild(_sys_home) 55 56def _python_build(): 57 if _sys_home: 58 return _is_python_source_dir(_sys_home) 59 return _is_python_source_dir(project_base) 60 61python_build = _python_build() 62 63 64# Calculate the build qualifier flags if they are defined. Adding the flags 65# to the include and lib directories only makes sense for an installation, not 66# an in-source build. 67build_flags = '' 68try: 69 if not python_build: 70 build_flags = sys.abiflags 71except AttributeError: 72 # It's not a configure-based build, so the sys module doesn't have 73 # this attribute, which is fine. 74 pass 75 76def get_python_version(): 77 """Return a string containing the major and minor Python version, 78 leaving off the patchlevel. Sample return values could be '1.5' 79 or '2.2'. 80 """ 81 return '%d.%d' % sys.version_info[:2] 82 83 84def get_python_inc(plat_specific=0, prefix=None): 85 """Return the directory containing installed Python header files. 86 87 If 'plat_specific' is false (the default), this is the path to the 88 non-platform-specific header files, i.e. Python.h and so on; 89 otherwise, this is the path to platform-specific header files 90 (namely pyconfig.h). 91 92 If 'prefix' is supplied, use it instead of sys.base_prefix or 93 sys.base_exec_prefix -- i.e., ignore 'plat_specific'. 94 """ 95 if prefix is None: 96 prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX 97 if os.name == "posix": 98 if python_build: 99 # Assume the executable is in the build directory. The 100 # pyconfig.h file should be in the same directory. Since 101 # the build directory may not be the source directory, we 102 # must use "srcdir" from the makefile to find the "Include" 103 # directory. 104 if plat_specific: 105 return _sys_home or project_base 106 else: 107 incdir = os.path.join(get_config_var('srcdir'), 'Include') 108 return os.path.normpath(incdir) 109 python_dir = 'python' + get_python_version() + build_flags 110 return os.path.join(prefix, "include", python_dir) 111 elif os.name == "nt": 112 if python_build: 113 # Include both the include and PC dir to ensure we can find 114 # pyconfig.h 115 return (os.path.join(prefix, "include") + os.path.pathsep + 116 os.path.join(prefix, "PC")) 117 return os.path.join(prefix, "include") 118 else: 119 raise DistutilsPlatformError( 120 "I don't know where Python installs its C header files " 121 "on platform '%s'" % os.name) 122 123 124def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): 125 """Return the directory containing the Python library (standard or 126 site additions). 127 128 If 'plat_specific' is true, return the directory containing 129 platform-specific modules, i.e. any module from a non-pure-Python 130 module distribution; otherwise, return the platform-shared library 131 directory. If 'standard_lib' is true, return the directory 132 containing standard Python library modules; otherwise, return the 133 directory for site-specific modules. 134 135 If 'prefix' is supplied, use it instead of sys.base_prefix or 136 sys.base_exec_prefix -- i.e., ignore 'plat_specific'. 137 """ 138 if prefix is None: 139 if standard_lib: 140 prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX 141 else: 142 prefix = plat_specific and EXEC_PREFIX or PREFIX 143 144 if os.name == "posix": 145 libpython = os.path.join(prefix, 146 "lib", "python" + get_python_version()) 147 if standard_lib: 148 return libpython 149 else: 150 return os.path.join(libpython, "site-packages") 151 elif os.name == "nt": 152 if standard_lib: 153 return os.path.join(prefix, "Lib") 154 else: 155 return os.path.join(prefix, "Lib", "site-packages") 156 else: 157 raise DistutilsPlatformError( 158 "I don't know where Python installs its library " 159 "on platform '%s'" % os.name) 160 161 162 163def customize_compiler(compiler): 164 """Do any platform-specific customization of a CCompiler instance. 165 166 Mainly needed on Unix, so we can plug in the information that 167 varies across Unices and is stored in Python's Makefile. 168 """ 169 if compiler.compiler_type == "unix": 170 if sys.platform == "darwin": 171 # Perform first-time customization of compiler-related 172 # config vars on OS X now that we know we need a compiler. 173 # This is primarily to support Pythons from binary 174 # installers. The kind and paths to build tools on 175 # the user system may vary significantly from the system 176 # that Python itself was built on. Also the user OS 177 # version and build tools may not support the same set 178 # of CPU architectures for universal builds. 179 global _config_vars 180 # Use get_config_var() to ensure _config_vars is initialized. 181 if not get_config_var('CUSTOMIZED_OSX_COMPILER'): 182 import _osx_support 183 _osx_support.customize_compiler(_config_vars) 184 _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True' 185 186 (cc, cxx, opt, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \ 187 get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS', 188 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') 189 190 if 'CC' in os.environ: 191 newcc = os.environ['CC'] 192 if (sys.platform == 'darwin' 193 and 'LDSHARED' not in os.environ 194 and ldshared.startswith(cc)): 195 # On OS X, if CC is overridden, use that as the default 196 # command for LDSHARED as well 197 ldshared = newcc + ldshared[len(cc):] 198 cc = newcc 199 if 'CXX' in os.environ: 200 cxx = os.environ['CXX'] 201 if 'LDSHARED' in os.environ: 202 ldshared = os.environ['LDSHARED'] 203 if 'CPP' in os.environ: 204 cpp = os.environ['CPP'] 205 else: 206 cpp = cc + " -E" # not always 207 if 'LDFLAGS' in os.environ: 208 ldshared = ldshared + ' ' + os.environ['LDFLAGS'] 209 if 'CFLAGS' in os.environ: 210 cflags = opt + ' ' + os.environ['CFLAGS'] 211 ldshared = ldshared + ' ' + os.environ['CFLAGS'] 212 if 'CPPFLAGS' in os.environ: 213 cpp = cpp + ' ' + os.environ['CPPFLAGS'] 214 cflags = cflags + ' ' + os.environ['CPPFLAGS'] 215 ldshared = ldshared + ' ' + os.environ['CPPFLAGS'] 216 if 'AR' in os.environ: 217 ar = os.environ['AR'] 218 if 'ARFLAGS' in os.environ: 219 archiver = ar + ' ' + os.environ['ARFLAGS'] 220 else: 221 archiver = ar + ' ' + ar_flags 222 223 cc_cmd = cc + ' ' + cflags 224 compiler.set_executables( 225 preprocessor=cpp, 226 compiler=cc_cmd, 227 compiler_so=cc_cmd + ' ' + ccshared, 228 compiler_cxx=cxx, 229 linker_so=ldshared, 230 linker_exe=cc, 231 archiver=archiver) 232 233 compiler.shared_lib_extension = shlib_suffix 234 235 236def get_config_h_filename(): 237 """Return full pathname of installed pyconfig.h file.""" 238 if python_build: 239 if os.name == "nt": 240 inc_dir = os.path.join(_sys_home or project_base, "PC") 241 else: 242 inc_dir = _sys_home or project_base 243 else: 244 inc_dir = get_python_inc(plat_specific=1) 245 246 return os.path.join(inc_dir, 'pyconfig.h') 247 248 249def get_makefile_filename(): 250 """Return full pathname of installed Makefile from the Python build.""" 251 if python_build: 252 return os.path.join(_sys_home or project_base, "Makefile") 253 lib_dir = get_python_lib(plat_specific=0, standard_lib=1) 254 config_file = 'config-{}{}'.format(get_python_version(), build_flags) 255 if hasattr(sys.implementation, '_multiarch'): 256 config_file += '-%s' % sys.implementation._multiarch 257 return os.path.join(lib_dir, config_file, 'Makefile') 258 259 260def parse_config_h(fp, g=None): 261 """Parse a config.h-style file. 262 263 A dictionary containing name/value pairs is returned. If an 264 optional dictionary is passed in as the second argument, it is 265 used instead of a new dictionary. 266 """ 267 if g is None: 268 g = {} 269 define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n") 270 undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n") 271 # 272 while True: 273 line = fp.readline() 274 if not line: 275 break 276 m = define_rx.match(line) 277 if m: 278 n, v = m.group(1, 2) 279 try: v = int(v) 280 except ValueError: pass 281 g[n] = v 282 else: 283 m = undef_rx.match(line) 284 if m: 285 g[m.group(1)] = 0 286 return g 287 288 289# Regexes needed for parsing Makefile (and similar syntaxes, 290# like old-style Setup files). 291_variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") 292_findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") 293_findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") 294 295def parse_makefile(fn, g=None): 296 """Parse a Makefile-style file. 297 298 A dictionary containing name/value pairs is returned. If an 299 optional dictionary is passed in as the second argument, it is 300 used instead of a new dictionary. 301 """ 302 from distutils.text_file import TextFile 303 fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1, errors="surrogateescape") 304 305 if g is None: 306 g = {} 307 done = {} 308 notdone = {} 309 310 while True: 311 line = fp.readline() 312 if line is None: # eof 313 break 314 m = _variable_rx.match(line) 315 if m: 316 n, v = m.group(1, 2) 317 v = v.strip() 318 # `$$' is a literal `$' in make 319 tmpv = v.replace('$$', '') 320 321 if "$" in tmpv: 322 notdone[n] = v 323 else: 324 try: 325 v = int(v) 326 except ValueError: 327 # insert literal `$' 328 done[n] = v.replace('$$', '$') 329 else: 330 done[n] = v 331 332 # Variables with a 'PY_' prefix in the makefile. These need to 333 # be made available without that prefix through sysconfig. 334 # Special care is needed to ensure that variable expansion works, even 335 # if the expansion uses the name without a prefix. 336 renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS') 337 338 # do variable interpolation here 339 while notdone: 340 for name in list(notdone): 341 value = notdone[name] 342 m = _findvar1_rx.search(value) or _findvar2_rx.search(value) 343 if m: 344 n = m.group(1) 345 found = True 346 if n in done: 347 item = str(done[n]) 348 elif n in notdone: 349 # get it on a subsequent round 350 found = False 351 elif n in os.environ: 352 # do it like make: fall back to environment 353 item = os.environ[n] 354 355 elif n in renamed_variables: 356 if name.startswith('PY_') and name[3:] in renamed_variables: 357 item = "" 358 359 elif 'PY_' + n in notdone: 360 found = False 361 362 else: 363 item = str(done['PY_' + n]) 364 else: 365 done[n] = item = "" 366 if found: 367 after = value[m.end():] 368 value = value[:m.start()] + item + after 369 if "$" in after: 370 notdone[name] = value 371 else: 372 try: value = int(value) 373 except ValueError: 374 done[name] = value.strip() 375 else: 376 done[name] = value 377 del notdone[name] 378 379 if name.startswith('PY_') \ 380 and name[3:] in renamed_variables: 381 382 name = name[3:] 383 if name not in done: 384 done[name] = value 385 else: 386 # bogus variable reference; just drop it since we can't deal 387 del notdone[name] 388 389 fp.close() 390 391 # strip spurious spaces 392 for k, v in done.items(): 393 if isinstance(v, str): 394 done[k] = v.strip() 395 396 # save the results in the global dictionary 397 g.update(done) 398 return g 399 400 401def expand_makefile_vars(s, vars): 402 """Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in 403 'string' according to 'vars' (a dictionary mapping variable names to 404 values). Variables not present in 'vars' are silently expanded to the 405 empty string. The variable values in 'vars' should not contain further 406 variable expansions; if 'vars' is the output of 'parse_makefile()', 407 you're fine. Returns a variable-expanded version of 's'. 408 """ 409 410 # This algorithm does multiple expansion, so if vars['foo'] contains 411 # "${bar}", it will expand ${foo} to ${bar}, and then expand 412 # ${bar}... and so forth. This is fine as long as 'vars' comes from 413 # 'parse_makefile()', which takes care of such expansions eagerly, 414 # according to make's variable expansion semantics. 415 416 while True: 417 m = _findvar1_rx.search(s) or _findvar2_rx.search(s) 418 if m: 419 (beg, end) = m.span() 420 s = s[0:beg] + vars.get(m.group(1)) + s[end:] 421 else: 422 break 423 return s 424 425 426_config_vars = None 427 428def _init_posix(): 429 """Initialize the module as appropriate for POSIX systems.""" 430 # _sysconfigdata is generated at build time, see the sysconfig module 431 name = os.environ.get('_PYTHON_SYSCONFIGDATA_NAME', 432 '_sysconfigdata_{abi}_{platform}_{multiarch}'.format( 433 abi=sys.abiflags, 434 platform=sys.platform, 435 multiarch=getattr(sys.implementation, '_multiarch', ''), 436 )) 437 _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0) 438 build_time_vars = _temp.build_time_vars 439 global _config_vars 440 _config_vars = {} 441 _config_vars.update(build_time_vars) 442 443 444def _init_nt(): 445 """Initialize the module as appropriate for NT""" 446 g = {} 447 # set basic install directories 448 g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1) 449 g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1) 450 451 # XXX hmmm.. a normal install puts include files here 452 g['INCLUDEPY'] = get_python_inc(plat_specific=0) 453 454 g['EXT_SUFFIX'] = _imp.extension_suffixes()[0] 455 g['EXE'] = ".exe" 456 g['VERSION'] = get_python_version().replace(".", "") 457 g['BINDIR'] = os.path.dirname(os.path.abspath(sys.executable)) 458 459 global _config_vars 460 _config_vars = g 461 462 463def get_config_vars(*args): 464 """With no arguments, return a dictionary of all configuration 465 variables relevant for the current platform. Generally this includes 466 everything needed to build extensions and install both pure modules and 467 extensions. On Unix, this means every variable defined in Python's 468 installed Makefile; on Windows it's a much smaller set. 469 470 With arguments, return a list of values that result from looking up 471 each argument in the configuration variable dictionary. 472 """ 473 global _config_vars 474 if _config_vars is None: 475 func = globals().get("_init_" + os.name) 476 if func: 477 func() 478 else: 479 _config_vars = {} 480 481 # Normalized versions of prefix and exec_prefix are handy to have; 482 # in fact, these are the standard versions used most places in the 483 # Distutils. 484 _config_vars['prefix'] = PREFIX 485 _config_vars['exec_prefix'] = EXEC_PREFIX 486 487 # For backward compatibility, see issue19555 488 SO = _config_vars.get('EXT_SUFFIX') 489 if SO is not None: 490 _config_vars['SO'] = SO 491 492 # Always convert srcdir to an absolute path 493 srcdir = _config_vars.get('srcdir', project_base) 494 if os.name == 'posix': 495 if python_build: 496 # If srcdir is a relative path (typically '.' or '..') 497 # then it should be interpreted relative to the directory 498 # containing Makefile. 499 base = os.path.dirname(get_makefile_filename()) 500 srcdir = os.path.join(base, srcdir) 501 else: 502 # srcdir is not meaningful since the installation is 503 # spread about the filesystem. We choose the 504 # directory containing the Makefile since we know it 505 # exists. 506 srcdir = os.path.dirname(get_makefile_filename()) 507 _config_vars['srcdir'] = os.path.abspath(os.path.normpath(srcdir)) 508 509 # Convert srcdir into an absolute path if it appears necessary. 510 # Normally it is relative to the build directory. However, during 511 # testing, for example, we might be running a non-installed python 512 # from a different directory. 513 if python_build and os.name == "posix": 514 base = project_base 515 if (not os.path.isabs(_config_vars['srcdir']) and 516 base != os.getcwd()): 517 # srcdir is relative and we are not in the same directory 518 # as the executable. Assume executable is in the build 519 # directory and make srcdir absolute. 520 srcdir = os.path.join(base, _config_vars['srcdir']) 521 _config_vars['srcdir'] = os.path.normpath(srcdir) 522 523 # OS X platforms require special customization to handle 524 # multi-architecture, multi-os-version installers 525 if sys.platform == 'darwin': 526 import _osx_support 527 _osx_support.customize_config_vars(_config_vars) 528 529 if args: 530 vals = [] 531 for name in args: 532 vals.append(_config_vars.get(name)) 533 return vals 534 else: 535 return _config_vars 536 537def get_config_var(name): 538 """Return the value of a single variable using the dictionary 539 returned by 'get_config_vars()'. Equivalent to 540 get_config_vars().get(name) 541 """ 542 if name == 'SO': 543 import warnings 544 warnings.warn('SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2) 545 return get_config_vars().get(name) 546