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