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