PageRenderTime 106ms CodeModel.GetById 36ms app.highlight 64ms RepoModel.GetById 1ms app.codeStats 0ms

/Lib/distutils/sysconfig.py

http://unladen-swallow.googlecode.com/
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)