/Lib/distutils/sysconfig.py
Python | 650 lines | 624 code | 8 blank | 18 comment | 19 complexity | 63d1d5f6fa1e9187aab0d7dccd766f2a MD5 | raw file
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: sysconfig.py 75023 2009-09-22 19:31:34Z ronald.oussoren $" 13 14import os 15import re 16import sys 17 18# These are needed in a couple of spots, so just compute them once. 19PREFIX = os.path.normpath(sys.prefix) 20EXEC_PREFIX = os.path.normpath(sys.exec_prefix) 21 22# Path to the base directory of the project. On Windows the binary may 23# live in project/PCBuild9. If we're dealing with an x64 Windows build, 24# it'll live in project/PCbuild/amd64. 25project_base = os.path.dirname(os.path.abspath(sys.executable)) 26if os.name == "nt" and "pcbuild" in project_base[-8:].lower(): 27 project_base = os.path.abspath(os.path.join(project_base, os.path.pardir)) 28# PC/VS7.1 29if os.name == "nt" and "\\pc\\v" in project_base[-10:].lower(): 30 project_base = os.path.abspath(os.path.join(project_base, os.path.pardir, 31 os.path.pardir)) 32# PC/AMD64 33if os.name == "nt" and "\\pcbuild\\amd64" in project_base[-14:].lower(): 34 project_base = os.path.abspath(os.path.join(project_base, os.path.pardir, 35 os.path.pardir)) 36 37# python_build: (Boolean) if true, we're either building Python or 38# building an extension with an un-installed Python, so we use 39# different (hard-wired) directories. 40# Setup.local is available for Makefile builds including VPATH builds, 41# Setup.dist is available on Windows 42def _python_build(): 43 for fn in ("Setup.dist", "Setup.local"): 44 if os.path.isfile(os.path.join(project_base, "Modules", fn)): 45 return True 46 return False 47python_build = _python_build() 48 49 50def get_python_version(): 51 """Return a string containing the major and minor Python version, 52 leaving off the patchlevel. Sample return values could be '1.5' 53 or '2.2'. 54 """ 55 return sys.version[:3] 56 57 58def get_python_inc(plat_specific=0, prefix=None): 59 """Return the directory containing installed Python header files. 60 61 If 'plat_specific' is false (the default), this is the path to the 62 non-platform-specific header files, i.e. Python.h and so on; 63 otherwise, this is the path to platform-specific header files 64 (namely pyconfig.h). 65 66 If 'prefix' is supplied, use it instead of sys.prefix or 67 sys.exec_prefix -- i.e., ignore 'plat_specific'. 68 """ 69 if prefix is None: 70 prefix = plat_specific and EXEC_PREFIX or PREFIX 71 if os.name == "posix": 72 if python_build: 73 # Assume the executable is in the build directory. The 74 # pyconfig.h file should be in the same directory. Since 75 # the build directory may not be the source directory, we 76 # must use "srcdir" from the makefile to find the "Include" 77 # directory. 78 base = os.path.dirname(os.path.abspath(sys.executable)) 79 if plat_specific: 80 return base 81 else: 82 incdir = os.path.join(get_config_var('srcdir'), 'Include') 83 return os.path.normpath(incdir) 84 return os.path.join(prefix, "include", "python" + get_python_version()) 85 elif os.name == "nt": 86 return os.path.join(prefix, "include") 87 elif os.name == "mac": 88 if plat_specific: 89 return os.path.join(prefix, "Mac", "Include") 90 else: 91 return os.path.join(prefix, "Include") 92 elif os.name == "os2": 93 return os.path.join(prefix, "Include") 94 else: 95 # Delay import to improve interpreter-startup time. 96 from distutils.errors import DistutilsPlatformError 97 raise DistutilsPlatformError( 98 "I don't know where Python installs its C header files " 99 "on platform '%s'" % os.name) 100 101 102def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): 103 """Return the directory containing the Python library (standard or 104 site additions). 105 106 If 'plat_specific' is true, return the directory containing 107 platform-specific modules, i.e. any module from a non-pure-Python 108 module distribution; otherwise, return the platform-shared library 109 directory. If 'standard_lib' is true, return the directory 110 containing standard Python library modules; otherwise, return the 111 directory for site-specific modules. 112 113 If 'prefix' is supplied, use it instead of sys.prefix or 114 sys.exec_prefix -- i.e., ignore 'plat_specific'. 115 """ 116 if prefix is None: 117 prefix = plat_specific and EXEC_PREFIX or PREFIX 118 119 if os.name == "posix": 120 libpython = os.path.join(prefix, 121 "lib", "python" + get_python_version()) 122 if standard_lib: 123 return libpython 124 else: 125 return os.path.join(libpython, "site-packages") 126 127 elif os.name == "nt": 128 if standard_lib: 129 return os.path.join(prefix, "Lib") 130 else: 131 if get_python_version() < "2.2": 132 return prefix 133 else: 134 return os.path.join(prefix, "Lib", "site-packages") 135 136 elif os.name == "mac": 137 if plat_specific: 138 if standard_lib: 139 return os.path.join(prefix, "Lib", "lib-dynload") 140 else: 141 return os.path.join(prefix, "Lib", "site-packages") 142 else: 143 if standard_lib: 144 return os.path.join(prefix, "Lib") 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 # Delay import to improve interpreter-startup time. 156 from distutils.errors import DistutilsPlatformError 157 raise DistutilsPlatformError( 158 "I don't know where Python installs its library " 159 "on platform '%s'" % os.name) 160 161 162def customize_compiler(compiler): 163 """Do any platform-specific customization of a CCompiler instance. 164 165 Mainly needed on Unix, so we can plug in the information that 166 varies across Unices and is stored in Python's Makefile. 167 """ 168 if compiler.compiler_type == "unix": 169 (cc, cxx, opt, cflags, ccshared, ldshared, so_ext, libs) = \ 170 get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS', 171 'CCSHARED', 'LDSHARED', 'SO', 'LIBS') 172 173 if 'CC' in os.environ: 174 cc = os.environ['CC'] 175 if 'CXX' in os.environ: 176 cxx = os.environ['CXX'] 177 if 'LDSHARED' in os.environ: 178 ldshared = os.environ['LDSHARED'] 179 if 'CPP' in os.environ: 180 cpp = os.environ['CPP'] 181 else: 182 cpp = cc + " -E" # not always 183 if 'LDFLAGS' in os.environ: 184 ldshared = ldshared + ' ' + os.environ['LDFLAGS'] 185 if 'CFLAGS' in os.environ: 186 cflags = opt + ' ' + os.environ['CFLAGS'] 187 ldshared = ldshared + ' ' + os.environ['CFLAGS'] 188 if 'CPPFLAGS' in os.environ: 189 cpp = cpp + ' ' + os.environ['CPPFLAGS'] 190 cflags = cflags + ' ' + os.environ['CPPFLAGS'] 191 ldshared = ldshared + ' ' + os.environ['CPPFLAGS'] 192 if 'LIBS' in os.environ: 193 libs = os.environ['LIBS'] 194 195 cc_cmd = cc + ' ' + cflags 196 compiler.set_executables( 197 preprocessor=cpp, 198 compiler=cc_cmd, 199 compiler_so=cc_cmd + ' ' + ccshared, 200 compiler_cxx=cxx, 201 linker_so=ldshared, 202 linker_exe=cc) 203 204 compiler.shared_lib_extension = so_ext 205 for chunk in libs.split(" "): 206 if not chunk: 207 continue 208 if chunk.startswith("-l"): 209 chunk = chunk[2:] 210 compiler.libraries.append(chunk) 211 212 213def get_config_h_filename(): 214 """Return full pathname of installed pyconfig.h file.""" 215 if python_build: 216 if os.name == "nt": 217 inc_dir = os.path.join(project_base, "PC") 218 else: 219 inc_dir = project_base 220 else: 221 inc_dir = get_python_inc(plat_specific=1) 222 if get_python_version() < '2.2': 223 config_h = 'config.h' 224 else: 225 # The name of the config.h file changed in 2.2 226 config_h = 'pyconfig.h' 227 return os.path.join(inc_dir, config_h) 228 229 230def get_makefile_filename(): 231 """Return full pathname of installed Makefile from the Python build.""" 232 if python_build: 233 return os.path.join(os.path.dirname(sys.executable), "Makefile") 234 lib_dir = get_python_lib(plat_specific=1, standard_lib=1) 235 return os.path.join(lib_dir, "config", "Makefile") 236 237 238def get_sysconfig_filename(): 239 """Return absolute pathname of the installed sysconfig file.""" 240 if python_build: 241 return os.path.join(os.path.dirname(sys.executable), "sysconfig") 242 lib_dir = get_python_lib(plat_specific=1, standard_lib=1) 243 return os.path.join(lib_dir, "config", "sysconfig") 244 245 246def parse_config_h(fp, g=None): 247 """Parse a config.h-style file. 248 249 A dictionary containing name/value pairs is returned. If an 250 optional dictionary is passed in as the second argument, it is 251 used instead of a new dictionary. 252 """ 253 if g is None: 254 g = {} 255 define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n") 256 undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n") 257 # 258 while 1: 259 line = fp.readline() 260 if not line: 261 break 262 m = define_rx.match(line) 263 if m: 264 n, v = m.group(1, 2) 265 try: v = int(v) 266 except ValueError: pass 267 g[n] = v 268 else: 269 m = undef_rx.match(line) 270 if m: 271 g[m.group(1)] = 0 272 return g 273 274 275# There's almost certainly something out there that expects parse_config_h() to 276# take a file-like object. Sigh. Create a simple wrapper for our own nefarious 277# purposes. 278def _parse_config_h_filename(filename, g=None): 279 with open(filename) as fp: 280 return parse_config_h(fp, g) 281 282# Regexes needed for parsing Makefile (and similar syntaxes, 283# like old-style Setup files). 284_variable_rx = re.compile("([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") 285_findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") 286_findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") 287 288def parse_makefile(fn, g=None): 289 """Parse a Makefile-style file. 290 291 A dictionary containing name/value pairs is returned. If an 292 optional dictionary is passed in as the second argument, it is 293 used instead of a new dictionary. 294 """ 295 from distutils.text_file import TextFile 296 fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1) 297 298 if g is None: 299 g = {} 300 done = {} 301 notdone = {} 302 303 while 1: 304 line = fp.readline() 305 if line is None: # eof 306 break 307 m = _variable_rx.match(line) 308 if m: 309 n, v = m.group(1, 2) 310 v = v.strip() 311 # `$$' is a literal `$' in make 312 tmpv = v.replace('$$', '') 313 314 if "$" in tmpv: 315 notdone[n] = v 316 else: 317 try: 318 v = int(v) 319 except ValueError: 320 # insert literal `$' 321 done[n] = v.replace('$$', '$') 322 else: 323 done[n] = v 324 325 # do variable interpolation here 326 while notdone: 327 for name in notdone.keys(): 328 value = notdone[name] 329 m = _findvar1_rx.search(value) or _findvar2_rx.search(value) 330 if m: 331 n = m.group(1) 332 found = True 333 if n in done: 334 item = str(done[n]) 335 elif n in notdone: 336 # get it on a subsequent round 337 found = False 338 elif n in os.environ: 339 # do it like make: fall back to environment 340 item = os.environ[n] 341 else: 342 done[n] = item = "" 343 if found: 344 after = value[m.end():] 345 value = value[:m.start()] + item + after 346 if "$" in after: 347 notdone[name] = value 348 else: 349 try: value = int(value) 350 except ValueError: 351 done[name] = value.strip() 352 else: 353 done[name] = value 354 del notdone[name] 355 else: 356 # bogus variable reference; just drop it since we can't deal 357 del notdone[name] 358 359 fp.close() 360 361 # save the results in the global dictionary 362 g.update(done) 363 return g 364 365 366def expand_makefile_vars(s, vars): 367 """Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in 368 'string' according to 'vars' (a dictionary mapping variable names to 369 values). Variables not present in 'vars' are silently expanded to the 370 empty string. The variable values in 'vars' should not contain further 371 variable expansions; if 'vars' is the output of 'parse_makefile()', 372 you're fine. Returns a variable-expanded version of 's'. 373 """ 374 375 # This algorithm does multiple expansion, so if vars['foo'] contains 376 # "${bar}", it will expand ${foo} to ${bar}, and then expand 377 # ${bar}... and so forth. This is fine as long as 'vars' comes from 378 # 'parse_makefile()', which takes care of such expansions eagerly, 379 # according to make's variable expansion semantics. 380 381 while 1: 382 m = _findvar1_rx.search(s) or _findvar2_rx.search(s) 383 if m: 384 (beg, end) = m.span() 385 s = s[0:beg] + vars.get(m.group(1)) + s[end:] 386 else: 387 break 388 return s 389 390 391def _parse_config_file(filename, parse_func, config_dict): 392 """Parse a config file into a common dict. 393 394 Args: 395 filename: name of the config file. 396 parse_func: function to use to parse the file. This will be given 397 `filename` and `config_dict` as arguments, and should update 398 `config_dict` in-place. 399 config_dict: dictionary to update in-place. 400 401 Raises: 402 DistutilsPlatformError: if the file could not be opened. 403 """ 404 try: 405 parse_func(filename, config_dict) 406 except IOError, msg: 407 my_msg = "invalid Python installation: unable to open %s" % filename 408 if hasattr(msg, "strerror"): 409 my_msg = my_msg + " (%s)" % msg.strerror 410 411 # Delay import to improve interpreter-startup time. 412 from distutils.errors import DistutilsPlatformError 413 raise DistutilsPlatformError(my_msg) 414 415 416_config_vars = None 417 418def _init_posix(): 419 """Initialize the module as appropriate for POSIX systems.""" 420 g = {} 421 # load the installed Makefile: 422 _parse_config_file(get_makefile_filename(), parse_makefile, g) 423 424 # load the installed pyconfig.h: 425 _parse_config_file(get_config_h_filename(), _parse_config_h_filename, g) 426 427 # Load the sysconfig config file; this contains variables that are 428 # calculated while building Python. 429 _parse_config_file(get_sysconfig_filename(), parse_makefile, g) 430 431 # On MacOSX we need to check the setting of the environment variable 432 # MACOSX_DEPLOYMENT_TARGET: configure bases some choices on it so 433 # it needs to be compatible. 434 # If it isn't set we set it to the configure-time value 435 if sys.platform == 'darwin' and 'MACOSX_DEPLOYMENT_TARGET' in g: 436 cfg_target = g['MACOSX_DEPLOYMENT_TARGET'] 437 cur_target = os.getenv('MACOSX_DEPLOYMENT_TARGET', '') 438 if cur_target == '': 439 cur_target = cfg_target 440 os.putenv('MACOSX_DEPLOYMENT_TARGET', cfg_target) 441 elif map(int, cfg_target.split('.')) > map(int, cur_target.split('.')): 442 my_msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: now "%s" but "%s" during configure' 443 % (cur_target, cfg_target)) 444 # Delay import to improve interpreter-startup time. 445 from distutils.errors import DistutilsPlatformError 446 raise DistutilsPlatformError(my_msg) 447 448 # On AIX, there are wrong paths to the linker scripts in the Makefile 449 # -- these paths are relative to the Python source, but when installed 450 # the scripts are in another directory. 451 if python_build: 452 g['LDSHARED'] = g['BLDSHARED'] 453 454 elif get_python_version() < '2.1': 455 # The following two branches are for 1.5.2 compatibility. 456 if sys.platform == 'aix4': # what about AIX 3.x ? 457 # Linker script is in the config directory, not in Modules as the 458 # Makefile says. 459 python_lib = get_python_lib(standard_lib=1) 460 ld_so_aix = os.path.join(python_lib, 'config', 'ld_so_aix') 461 python_exp = os.path.join(python_lib, 'config', 'python.exp') 462 463 g['LDSHARED'] = "%s %s -bI:%s" % (ld_so_aix, g['CC'], python_exp) 464 465 elif sys.platform == 'beos': 466 # Linker script is in the config directory. In the Makefile it is 467 # relative to the srcdir, which after installation no longer makes 468 # sense. 469 python_lib = get_python_lib(standard_lib=1) 470 linkerscript_path = g['LDSHARED'].split()[0] 471 linkerscript_name = os.path.basename(linkerscript_path) 472 linkerscript = os.path.join(python_lib, 'config', 473 linkerscript_name) 474 475 # XXX this isn't the right place to do this: adding the Python 476 # library to the link, if needed, should be in the "build_ext" 477 # command. (It's also needed for non-MS compilers on Windows, and 478 # it's taken care of for them by the 'build_ext.get_libraries()' 479 # method.) 480 g['LDSHARED'] = ("%s -L%s/lib -lpython%s" % 481 (linkerscript, PREFIX, get_python_version())) 482 483 global _config_vars 484 _config_vars = g 485 486 487def _init_nt(): 488 """Initialize the module as appropriate for NT""" 489 g = {} 490 # set basic install directories 491 g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1) 492 g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1) 493 494 # XXX hmmm.. a normal install puts include files here 495 g['INCLUDEPY'] = get_python_inc(plat_specific=0) 496 497 g['SO'] = '.pyd' 498 g['EXE'] = ".exe" 499 g['VERSION'] = get_python_version().replace(".", "") 500 g['BINDIR'] = os.path.dirname(os.path.abspath(sys.executable)) 501 502 global _config_vars 503 _config_vars = g 504 505 506def _init_mac(): 507 """Initialize the module as appropriate for Macintosh systems""" 508 g = {} 509 # set basic install directories 510 g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1) 511 g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1) 512 513 # XXX hmmm.. a normal install puts include files here 514 g['INCLUDEPY'] = get_python_inc(plat_specific=0) 515 516 import MacOS 517 if not hasattr(MacOS, 'runtimemodel'): 518 g['SO'] = '.ppc.slb' 519 else: 520 g['SO'] = '.%s.slb' % MacOS.runtimemodel 521 522 # XXX are these used anywhere? 523 g['install_lib'] = os.path.join(EXEC_PREFIX, "Lib") 524 g['install_platlib'] = os.path.join(EXEC_PREFIX, "Mac", "Lib") 525 526 # These are used by the extension module build 527 g['srcdir'] = ':' 528 global _config_vars 529 _config_vars = g 530 531 532def _init_os2(): 533 """Initialize the module as appropriate for OS/2""" 534 g = {} 535 # set basic install directories 536 g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1) 537 g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1) 538 539 # XXX hmmm.. a normal install puts include files here 540 g['INCLUDEPY'] = get_python_inc(plat_specific=0) 541 542 g['SO'] = '.pyd' 543 g['EXE'] = ".exe" 544 545 global _config_vars 546 _config_vars = g 547 548 549def get_config_vars(*args): 550 """With no arguments, return a dictionary of all configuration 551 variables relevant for the current platform. Generally this includes 552 everything needed to build extensions and install both pure modules and 553 extensions. On Unix, this means every variable defined in Python's 554 installed Makefile; on Windows and Mac OS it's a much smaller set. 555 556 With arguments, return a list of values that result from looking up 557 each argument in the configuration variable dictionary. 558 """ 559 global _config_vars 560 if _config_vars is None: 561 func = globals().get("_init_" + os.name) 562 if func: 563 func() 564 else: 565 _config_vars = {} 566 567 # Normalized versions of prefix and exec_prefix are handy to have; 568 # in fact, these are the standard versions used most places in the 569 # Distutils. 570 _config_vars['prefix'] = PREFIX 571 _config_vars['exec_prefix'] = EXEC_PREFIX 572 573 if 'srcdir' not in _config_vars: 574 _config_vars['srcdir'] = project_base 575 576 if sys.platform == 'darwin': 577 kernel_version = os.uname()[2] # Kernel version (8.4.3) 578 major_version = int(kernel_version.split('.')[0]) 579 580 if major_version < 8: 581 # On Mac OS X before 10.4, check if -arch and -isysroot 582 # are in CFLAGS or LDFLAGS and remove them if they are. 583 # This is needed when building extensions on a 10.3 system 584 # using a universal build of python. 585 for key in ('LDFLAGS', 'BASECFLAGS', 586 # a number of derived variables. These need to be 587 # patched up as well. 588 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): 589 flags = _config_vars[key] 590 flags = re.sub('-arch\s+\w+\s', ' ', flags) 591 flags = re.sub('-isysroot [^ \t]*', ' ', flags) 592 _config_vars[key] = flags 593 594 else: 595 596 # Allow the user to override the architecture flags using 597 # an environment variable. 598 # NOTE: This name was introduced by Apple in OSX 10.5 and 599 # is used by several scripting languages distributed with 600 # that OS release. 601 602 if 'ARCHFLAGS' in os.environ: 603 arch = os.environ['ARCHFLAGS'] 604 for key in ('LDFLAGS', 'BASECFLAGS', 605 # a number of derived variables. These need to be 606 # patched up as well. 607 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): 608 609 flags = _config_vars[key] 610 flags = re.sub('-arch\s+\w+\s', ' ', flags) 611 flags = flags + ' ' + arch 612 _config_vars[key] = flags 613 614 # If we're on OSX 10.5 or later and the user tries to 615 # compiles an extension using an SDK that is not present 616 # on the current machine it is better to not use an SDK 617 # than to fail. 618 # 619 # The major usecase for this is users using a Python.org 620 # binary installer on OSX 10.6: that installer uses 621 # the 10.4u SDK, but that SDK is not installed by default 622 # when you install Xcode. 623 # 624 m = re.search('-isysroot\s+(\S+)', _config_vars['CFLAGS']) 625 if m is not None: 626 sdk = m.group(1) 627 if not os.path.exists(sdk): 628 for key in ('LDFLAGS', 'BASECFLAGS', 629 # a number of derived variables. These need to be 630 # patched up as well. 631 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): 632 633 flags = _config_vars[key] 634 flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags) 635 _config_vars[key] = flags 636 637 if args: 638 vals = [] 639 for name in args: 640 vals.append(_config_vars.get(name)) 641 return vals 642 else: 643 return _config_vars 644 645def get_config_var(name): 646 """Return the value of a single variable using the dictionary 647 returned by 'get_config_vars()'. Equivalent to 648 get_config_vars().get(name) 649 """ 650 return get_config_vars().get(name)