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