sysconfig.py 17.7 KB
Newer Older
1 2 3 4 5 6
"""Provide access to Python's configuration information.  The specific
configuration variables available depend heavily on the platform and
configuration.  The values may be retrieved using
get_config_var(name), and the list of variables is available via
get_config_vars().keys().  Additional convenience functions are also
available.
Greg Ward's avatar
Greg Ward committed
7 8 9 10 11

Written by:   Fred L. Drake, Jr.
Email:        <fdrake@acm.org>
"""

12
__revision__ = "$Id$"
Greg Ward's avatar
Greg Ward committed
13

14 15
import os
import re
16
import string
17
import sys
Greg Ward's avatar
Greg Ward committed
18

19
from errors import DistutilsPlatformError
Greg Ward's avatar
Greg Ward committed
20

21
# These are needed in a couple of spots, so just compute them once.
22 23
PREFIX = os.path.normpath(sys.prefix)
EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
24

25 26 27 28 29 30
# python_build: (Boolean) if true, we're either building Python or
# building an extension with an un-installed Python, so we use
# different (hard-wired) directories.

argv0_path = os.path.dirname(os.path.abspath(sys.executable))
landmark = os.path.join(argv0_path, "Modules", "Setup")
31 32 33

python_build = os.path.isfile(landmark)

34
del argv0_path, landmark
35

Fred Drake's avatar
Fred Drake committed
36

37
def get_python_version():
38 39 40 41 42 43 44
    """Return a string containing the major and minor Python version,
    leaving off the patchlevel.  Sample return values could be '1.5'
    or '2.2'.
    """
    return sys.version[:3]


45
def get_python_inc(plat_specific=0, prefix=None):
46
    """Return the directory containing installed Python header files.
47 48 49 50

    If 'plat_specific' is false (the default), this is the path to the
    non-platform-specific header files, i.e. Python.h and so on;
    otherwise, this is the path to platform-specific header files
51
    (namely pyconfig.h).
52

53 54
    If 'prefix' is supplied, use it instead of sys.prefix or
    sys.exec_prefix -- i.e., ignore 'plat_specific'.
Fred Drake's avatar
Fred Drake committed
55
    """
56
    if prefix is None:
57
        prefix = plat_specific and EXEC_PREFIX or PREFIX
58
    if os.name == "posix":
59
        if python_build:
60 61 62 63 64 65 66 67
            base = os.path.dirname(os.path.abspath(sys.executable))
            if plat_specific:
                inc_dir = base
            else:
                inc_dir = os.path.join(base, "Include")
                if not os.path.exists(inc_dir):
                    inc_dir = os.path.join(os.path.dirname(base), "Include")
            return inc_dir
68
        return os.path.join(prefix, "include", "python" + get_python_version())
69
    elif os.name == "nt":
Fred Drake's avatar
Fred Drake committed
70
        return os.path.join(prefix, "include")
71
    elif os.name == "mac":
72
        if plat_specific:
73
            return os.path.join(prefix, "Mac", "Include")
74
        else:
75
            return os.path.join(prefix, "Include")
76 77
    elif os.name == "os2":
        return os.path.join(prefix, "Include")
78
    else:
79 80 81
        raise DistutilsPlatformError(
            "I don't know where Python installs its C header files "
            "on platform '%s'" % os.name)
82 83


84
def get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
85
    """Return the directory containing the Python library (standard or
86 87 88 89 90 91 92 93
    site additions).

    If 'plat_specific' is true, return the directory containing
    platform-specific modules, i.e. any module from a non-pure-Python
    module distribution; otherwise, return the platform-shared library
    directory.  If 'standard_lib' is true, return the directory
    containing standard Python library modules; otherwise, return the
    directory for site-specific modules.
94

95 96
    If 'prefix' is supplied, use it instead of sys.prefix or
    sys.exec_prefix -- i.e., ignore 'plat_specific'.
97
    """
98
    if prefix is None:
99
        prefix = plat_specific and EXEC_PREFIX or PREFIX
Fred Drake's avatar
Fred Drake committed
100

101
    if os.name == "posix":
102
        libpython = os.path.join(prefix,
103
                                 "lib", "python" + get_python_version())
104 105 106
        if standard_lib:
            return libpython
        else:
107
            return os.path.join(libpython, "site-packages")
108 109 110

    elif os.name == "nt":
        if standard_lib:
Fred Drake's avatar
Fred Drake committed
111
            return os.path.join(prefix, "Lib")
112
        else:
113
            if get_python_version() < "2.2":
114 115 116
                return prefix
            else:
                return os.path.join(PREFIX, "Lib", "site-packages")
117 118

    elif os.name == "mac":
Greg Ward's avatar
Greg Ward committed
119
        if plat_specific:
120
            if standard_lib:
121
                return os.path.join(prefix, "Lib", "lib-dynload")
122
            else:
123
                return os.path.join(prefix, "Lib", "site-packages")
124 125
        else:
            if standard_lib:
Fred Drake's avatar
Fred Drake committed
126
                return os.path.join(prefix, "Lib")
127
            else:
128
                return os.path.join(prefix, "Lib", "site-packages")
129 130 131 132 133 134 135

    elif os.name == "os2":
        if standard_lib:
            return os.path.join(PREFIX, "Lib")
        else:
            return os.path.join(PREFIX, "Lib", "site-packages")

136
    else:
137 138 139
        raise DistutilsPlatformError(
            "I don't know where Python installs its library "
            "on platform '%s'" % os.name)
140 141


142
def customize_compiler(compiler):
Fred Drake's avatar
Fred Drake committed
143 144 145 146
    """Do any platform-specific customization of a CCompiler instance.

    Mainly needed on Unix, so we can plug in the information that
    varies across Unices and is stored in Python's Makefile.
147 148
    """
    if compiler.compiler_type == "unix":
149 150 151
        (cc, cxx, opt, extra_cflags, basecflags, ccshared, ldshared, so_ext) = \
            get_config_vars('CC', 'CXX', 'OPT', 'EXTRA_CFLAGS', 'BASECFLAGS',
                            'CCSHARED', 'LDSHARED', 'SO')
152

153 154
        if os.environ.has_key('CC'):
            cc = os.environ['CC']
155 156
        if os.environ.has_key('CXX'):
            cxx = os.environ['CXX']
157 158
        if os.environ.has_key('LDSHARED'):
            ldshared = os.environ['LDSHARED']
159 160 161 162 163 164
        if os.environ.has_key('CPP'):
            cpp = os.environ['CPP']
        else:
            cpp = cc + " -E"           # not always
        if os.environ.has_key('LDFLAGS'):
            ldshared = ldshared + ' ' + os.environ['LDFLAGS']
165
        if basecflags:
166
            opt = basecflags + ' ' + opt
167 168 169 170 171 172 173 174
        if os.environ.has_key('CFLAGS'):
            opt = opt + ' ' + os.environ['CFLAGS']
            ldshared = ldshared + ' ' + os.environ['CFLAGS']
        if os.environ.has_key('CPPFLAGS'):
            cpp = cpp + ' ' + os.environ['CPPFLAGS']
            opt = opt + ' ' + os.environ['CPPFLAGS']
            ldshared = ldshared + ' ' + os.environ['CPPFLAGS']

175
        cc_cmd = ' '.join(str(x) for x in (cc, opt, extra_cflags) if x)
176
        compiler.set_executables(
177
            preprocessor=cpp,
178
            compiler=cc_cmd,
179
            compiler_so=cc_cmd + ' ' + ccshared,
180
            compiler_cxx=cxx,
181 182
            linker_so=ldshared,
            linker_exe=cc)
183

184
        compiler.shared_lib_extension = so_ext
185 186


187
def get_config_h_filename():
188
    """Return full pathname of installed pyconfig.h file."""
Fred Drake's avatar
Fred Drake committed
189 190 191 192
    if python_build:
        inc_dir = os.curdir
    else:
        inc_dir = get_python_inc(plat_specific=1)
193
    if get_python_version() < '2.2':
194 195 196 197 198
        config_h = 'config.h'
    else:
        # The name of the config.h file changed in 2.2
        config_h = 'pyconfig.h'
    return os.path.join(inc_dir, config_h)
199

Greg Ward's avatar
Greg Ward committed
200

201
def get_makefile_filename():
Fred Drake's avatar
Fred Drake committed
202
    """Return full pathname of installed Makefile from the Python build."""
203
    if python_build:
204
        return os.path.join(os.path.dirname(sys.executable), "Makefile")
205 206
    lib_dir = get_python_lib(plat_specific=1, standard_lib=1)
    return os.path.join(lib_dir, "config", "Makefile")
207

Greg Ward's avatar
Greg Ward committed
208

209
def parse_config_h(fp, g=None):
210 211 212 213 214
    """Parse a config.h-style file.

    A dictionary containing name/value pairs is returned.  If an
    optional dictionary is passed in as the second argument, it is
    used instead of a new dictionary.
Fred Drake's avatar
Fred Drake committed
215
    """
216 217
    if g is None:
        g = {}
Greg Ward's avatar
Greg Ward committed
218 219
    define_rx = re.compile("#define ([A-Z][A-Z0-9_]+) (.*)\n")
    undef_rx = re.compile("/[*] #undef ([A-Z][A-Z0-9_]+) [*]/\n")
220
    #
Greg Ward's avatar
Greg Ward committed
221 222 223 224 225 226 227
    while 1:
        line = fp.readline()
        if not line:
            break
        m = define_rx.match(line)
        if m:
            n, v = m.group(1, 2)
228
            try: v = int(v)
229 230
            except ValueError: pass
            g[n] = v
Greg Ward's avatar
Greg Ward committed
231 232 233 234
        else:
            m = undef_rx.match(line)
            if m:
                g[m.group(1)] = 0
235
    return g
Greg Ward's avatar
Greg Ward committed
236

237 238 239 240 241 242 243

# Regexes needed for parsing Makefile (and similar syntaxes,
# like old-style Setup files).
_variable_rx = re.compile("([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)")
_findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")
_findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")

244
def parse_makefile(fn, g=None):
245 246 247 248 249
    """Parse a Makefile-style file.

    A dictionary containing name/value pairs is returned.  If an
    optional dictionary is passed in as the second argument, it is
    used instead of a new dictionary.
Fred Drake's avatar
Fred Drake committed
250
    """
251
    from distutils.text_file import TextFile
252
    fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1)
253

254 255
    if g is None:
        g = {}
Greg Ward's avatar
Greg Ward committed
256 257
    done = {}
    notdone = {}
258

Greg Ward's avatar
Greg Ward committed
259 260
    while 1:
        line = fp.readline()
261
        if line is None:                # eof
Greg Ward's avatar
Greg Ward committed
262
            break
263
        m = _variable_rx.match(line)
Greg Ward's avatar
Greg Ward committed
264 265
        if m:
            n, v = m.group(1, 2)
266
            v = string.strip(v)
Greg Ward's avatar
Greg Ward committed
267 268 269
            if "$" in v:
                notdone[n] = v
            else:
270
                try: v = int(v)
271
                except ValueError: pass
Greg Ward's avatar
Greg Ward committed
272 273 274 275 276 277
                done[n] = v

    # do variable interpolation here
    while notdone:
        for name in notdone.keys():
            value = notdone[name]
278
            m = _findvar1_rx.search(value) or _findvar2_rx.search(value)
Greg Ward's avatar
Greg Ward committed
279 280 281 282
            if m:
                n = m.group(1)
                if done.has_key(n):
                    after = value[m.end():]
283
                    value = value[:m.start()] + str(done[n]) + after
Greg Ward's avatar
Greg Ward committed
284 285 286
                    if "$" in after:
                        notdone[name] = value
                    else:
287
                        try: value = int(value)
288
                        except ValueError:
289
                            done[name] = string.strip(value)
290 291
                        else:
                            done[name] = value
Greg Ward's avatar
Greg Ward committed
292 293 294 295 296 297 298 299 300 301 302
                        del notdone[name]
                elif notdone.has_key(n):
                    # get it on a subsequent round
                    pass
                else:
                    done[n] = ""
                    after = value[m.end():]
                    value = value[:m.start()] + after
                    if "$" in after:
                        notdone[name] = value
                    else:
303
                        try: value = int(value)
304
                        except ValueError:
305
                            done[name] = string.strip(value)
306 307
                        else:
                            done[name] = value
Greg Ward's avatar
Greg Ward committed
308 309
                        del notdone[name]
            else:
310
                # bogus variable reference; just drop it since we can't deal
Greg Ward's avatar
Greg Ward committed
311 312
                del notdone[name]

313 314
    fp.close()

Greg Ward's avatar
Greg Ward committed
315 316
    # save the results in the global dictionary
    g.update(done)
317
    return g
Greg Ward's avatar
Greg Ward committed
318 319


320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
def expand_makefile_vars(s, vars):
    """Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in
    'string' according to 'vars' (a dictionary mapping variable names to
    values).  Variables not present in 'vars' are silently expanded to the
    empty string.  The variable values in 'vars' should not contain further
    variable expansions; if 'vars' is the output of 'parse_makefile()',
    you're fine.  Returns a variable-expanded version of 's'.
    """

    # This algorithm does multiple expansion, so if vars['foo'] contains
    # "${bar}", it will expand ${foo} to ${bar}, and then expand
    # ${bar}... and so forth.  This is fine as long as 'vars' comes from
    # 'parse_makefile()', which takes care of such expansions eagerly,
    # according to make's variable expansion semantics.

    while 1:
        m = _findvar1_rx.search(s) or _findvar2_rx.search(s)
        if m:
            (beg, end) = m.span()
            s = s[0:beg] + vars.get(m.group(1)) + s[end:]
        else:
            break
    return s


345 346
_config_vars = None

347
def _init_posix():
Fred Drake's avatar
Fred Drake committed
348
    """Initialize the module as appropriate for POSIX systems."""
349
    g = {}
Greg Ward's avatar
Greg Ward committed
350
    # load the installed Makefile:
351 352
    try:
        filename = get_makefile_filename()
353
        parse_makefile(filename, g)
354 355 356 357 358
    except IOError, msg:
        my_msg = "invalid Python installation: unable to open %s" % filename
        if hasattr(msg, "strerror"):
            my_msg = my_msg + " (%s)" % msg.strerror

359
        raise DistutilsPlatformError(my_msg)
Fred Drake's avatar
Fred Drake committed
360

361 362 363
    # On MacOSX we need to check the setting of the environment variable
    # MACOSX_DEPLOYMENT_TARGET: configure bases some choices on it so
    # it needs to be compatible.
364
    # If it isn't set we set it to the configure-time value
365 366 367
    if sys.platform == 'darwin' and g.has_key('CONFIGURE_MACOSX_DEPLOYMENT_TARGET'):
        cfg_target = g['CONFIGURE_MACOSX_DEPLOYMENT_TARGET']
        cur_target = os.getenv('MACOSX_DEPLOYMENT_TARGET', '')
368 369 370
        if cur_target == '':
            cur_target = cfg_target
            os.putenv('MACOSX_DEPLOYMENT_TARGET', cfg_target)
371 372 373 374
        if cfg_target != cur_target:
            my_msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: now "%s" but "%s" during configure'
                % (cur_target, cfg_target))
            raise DistutilsPlatformError(my_msg)
375

376 377 378
    # On AIX, there are wrong paths to the linker scripts in the Makefile
    # -- these paths are relative to the Python source, but when installed
    # the scripts are in another directory.
379
    if python_build:
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
380
        g['LDSHARED'] = g['BLDSHARED']
Fred Drake's avatar
Fred Drake committed
381

382
    elif get_python_version() < '2.1':
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
        # The following two branches are for 1.5.2 compatibility.
        if sys.platform == 'aix4':          # what about AIX 3.x ?
            # Linker script is in the config directory, not in Modules as the
            # Makefile says.
            python_lib = get_python_lib(standard_lib=1)
            ld_so_aix = os.path.join(python_lib, 'config', 'ld_so_aix')
            python_exp = os.path.join(python_lib, 'config', 'python.exp')

            g['LDSHARED'] = "%s %s -bI:%s" % (ld_so_aix, g['CC'], python_exp)

        elif sys.platform == 'beos':
            # Linker script is in the config directory.  In the Makefile it is
            # relative to the srcdir, which after installation no longer makes
            # sense.
            python_lib = get_python_lib(standard_lib=1)
398 399
            linkerscript_path = string.split(g['LDSHARED'])[0]
            linkerscript_name = os.path.basename(linkerscript_path)
400 401
            linkerscript = os.path.join(python_lib, 'config',
                                        linkerscript_name)
Fred Drake's avatar
Fred Drake committed
402

403 404 405 406 407 408
            # XXX this isn't the right place to do this: adding the Python
            # library to the link, if needed, should be in the "build_ext"
            # command.  (It's also needed for non-MS compilers on Windows, and
            # it's taken care of for them by the 'build_ext.get_libraries()'
            # method.)
            g['LDSHARED'] = ("%s -L%s/lib -lpython%s" %
409
                             (linkerscript, PREFIX, get_python_version()))
Fred Drake's avatar
Fred Drake committed
410

411 412
    global _config_vars
    _config_vars = g
413

414

415 416
def _init_nt():
    """Initialize the module as appropriate for NT"""
417
    g = {}
418
    # set basic install directories
419 420
    g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1)
    g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1)
421

422
    # XXX hmmm.. a normal install puts include files here
423
    g['INCLUDEPY'] = get_python_inc(plat_specific=0)
424

425
    g['SO'] = '.pyd'
426
    g['EXE'] = ".exe"
427 428 429

    global _config_vars
    _config_vars = g
430

431

432 433
def _init_mac():
    """Initialize the module as appropriate for Macintosh systems"""
434
    g = {}
435
    # set basic install directories
436 437
    g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1)
    g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1)
438 439

    # XXX hmmm.. a normal install puts include files here
440
    g['INCLUDEPY'] = get_python_inc(plat_specific=0)
441

442 443
    import MacOS
    if not hasattr(MacOS, 'runtimemodel'):
444
        g['SO'] = '.ppc.slb'
445 446
    else:
        g['SO'] = '.%s.slb' % MacOS.runtimemodel
447 448

    # XXX are these used anywhere?
449 450
    g['install_lib'] = os.path.join(EXEC_PREFIX, "Lib")
    g['install_platlib'] = os.path.join(EXEC_PREFIX, "Mac", "Lib")
451

452 453
    # These are used by the extension module build
    g['srcdir'] = ':'
454 455
    global _config_vars
    _config_vars = g
456

457

458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
def _init_os2():
    """Initialize the module as appropriate for OS/2"""
    g = {}
    # set basic install directories
    g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1)
    g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1)

    # XXX hmmm.. a normal install puts include files here
    g['INCLUDEPY'] = get_python_inc(plat_specific=0)

    g['SO'] = '.pyd'
    g['EXE'] = ".exe"

    global _config_vars
    _config_vars = g


475 476 477 478 479 480
def get_config_vars(*args):
    """With no arguments, return a dictionary of all configuration
    variables relevant for the current platform.  Generally this includes
    everything needed to build extensions and install both pure modules and
    extensions.  On Unix, this means every variable defined in Python's
    installed Makefile; on Windows and Mac OS it's a much smaller set.
481

482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
    With arguments, return a list of values that result from looking up
    each argument in the configuration variable dictionary.
    """
    global _config_vars
    if _config_vars is None:
        func = globals().get("_init_" + os.name)
        if func:
            func()
        else:
            _config_vars = {}

        # Normalized versions of prefix and exec_prefix are handy to have;
        # in fact, these are the standard versions used most places in the
        # Distutils.
        _config_vars['prefix'] = PREFIX
        _config_vars['exec_prefix'] = EXEC_PREFIX

    if args:
        vals = []
        for name in args:
            vals.append(_config_vars.get(name))
        return vals
    else:
        return _config_vars

def get_config_var(name):
    """Return the value of a single variable using the dictionary
    returned by 'get_config_vars()'.  Equivalent to
Fred Drake's avatar
Fred Drake committed
510
    get_config_vars().get(name)
511 512
    """
    return get_config_vars().get(name)