setup.py 76.4 KB
Newer Older
1 2
# Autodetecting setup.py script for building the Python extensions
#
3

4 5
__version__ = "$Revision$"

6
import sys, os, imp, re, optparse
7
from glob import glob
8
import sysconfig
9 10

from distutils import log
11
from distutils import text_file
Marc-André Lemburg's avatar
Marc-André Lemburg committed
12
from distutils.errors import *
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
13 14
from distutils.core import Extension, setup
from distutils.command.build_ext import build_ext
15
from distutils.command.install import install
16
from distutils.command.install_lib import install_lib
17
from distutils.spawn import find_executable
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
18

19 20 21
# Were we compiled --with-pydebug or with #define Py_DEBUG?
COMPILED_WITH_PYDEBUG = hasattr(sys, 'gettotalrefcount')

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
22 23 24
# This global variable is used to hold the list of modules to be disabled.
disabled_module_list = []

Michael W. Hudson's avatar
Michael W. Hudson committed
25 26 27 28
def add_dir_to_list(dirlist, dir):
    """Add the directory 'dir' to the list 'dirlist' (at the front) if
    1) 'dir' is not already in 'dirlist'
    2) 'dir' actually exists, and is a directory."""
29
    if dir is not None and os.path.isdir(dir) and dir not in dirlist:
Michael W. Hudson's avatar
Michael W. Hudson committed
30 31
        dirlist.insert(0, dir)

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
def macosx_sdk_root():
    """
    Return the directory of the current OSX SDK,
    or '/' if no SDK was specified.
    """
    cflags = sysconfig.get_config_var('CFLAGS')
    m = re.search(r'-isysroot\s+(\S+)', cflags)
    if m is None:
        sysroot = '/'
    else:
        sysroot = m.group(1)
    return sysroot

def is_macosx_sdk_path(path):
    """
    Returns True if 'path' can be located in an OSX SDK
    """
49
    return (path.startswith('/usr/') and not path.startswith('/usr/local')) or path.startswith('/System/')
50

51 52 53 54
def find_file(filename, std_dirs, paths):
    """Searches for the directory where a given file is located,
    and returns a possibly-empty list of additional directories, or None
    if the file couldn't be found at all.
55

56 57 58 59 60 61
    'filename' is the name of a file, such as readline.h or libcrypto.a.
    'std_dirs' is the list of standard system directories; if the
        file is found in one of them, no additional directives are needed.
    'paths' is a list of additional locations to check; if the file is
        found in one of them, the resulting list will contain the directory.
    """
62 63 64 65 66
    if sys.platform == 'darwin':
        # Honor the MacOSX SDK setting when one was specified.
        # An SDK is a directory with the same structure as a real
        # system, but with only header files and libraries.
        sysroot = macosx_sdk_root()
67 68 69 70

    # Check the standard locations
    for dir in std_dirs:
        f = os.path.join(dir, filename)
71 72 73 74

        if sys.platform == 'darwin' and is_macosx_sdk_path(dir):
            f = os.path.join(sysroot, dir[1:], filename)

75 76 77 78 79
        if os.path.exists(f): return []

    # Check the additional directories
    for dir in paths:
        f = os.path.join(dir, filename)
80 81 82 83

        if sys.platform == 'darwin' and is_macosx_sdk_path(dir):
            f = os.path.join(sysroot, dir[1:], filename)

84 85 86 87
        if os.path.exists(f):
            return [dir]

    # Not found anywhere
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
88 89
    return None

90
def find_library_file(compiler, libname, std_dirs, paths):
91 92 93
    result = compiler.find_library_file(std_dirs + paths, libname)
    if result is None:
        return None
94

95 96 97
    if sys.platform == 'darwin':
        sysroot = macosx_sdk_root()

98 99 100 101
    # Check whether the found file is in one of the standard directories
    dirname = os.path.dirname(result)
    for p in std_dirs:
        # Ensure path doesn't end with path separator
102
        p = p.rstrip(os.sep)
103 104 105 106 107

        if sys.platform == 'darwin' and is_macosx_sdk_path(p):
            if os.path.join(sysroot, p[1:]) == dirname:
                return [ ]

108 109
        if p == dirname:
            return [ ]
110

111 112 113 114
    # Otherwise, it must have been in one of the additional directories,
    # so we have to figure out which one.
    for p in paths:
        # Ensure path doesn't end with path separator
115
        p = p.rstrip(os.sep)
116 117 118 119 120

        if sys.platform == 'darwin' and is_macosx_sdk_path(p):
            if os.path.join(sysroot, p[1:]) == dirname:
                return [ p ]

121 122 123 124
        if p == dirname:
            return [p]
    else:
        assert False, "Internal error: Path not found in std_dirs or paths"
Tim Peters's avatar
Tim Peters committed
125

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
126 127 128 129 130
def module_enabled(extlist, modname):
    """Returns whether the module 'modname' is present in the list
    of extensions 'extlist'."""
    extlist = [ext for ext in extlist if ext.name == modname]
    return len(extlist)
131

Jack Jansen's avatar
Jack Jansen committed
132 133 134 135 136 137 138
def find_module_file(module, dirlist):
    """Find a module in a set of possible folders. If it is not found
    return the unadorned filename"""
    list = find_file(module, [], dirlist)
    if not list:
        return module
    if len(list) > 1:
139
        log.info("WARNING: multiple copies of %s found"%module)
Jack Jansen's avatar
Jack Jansen committed
140
    return os.path.join(list[0], module)
141

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
142
class PyBuildExt(build_ext):
143

144 145 146 147
    def __init__(self, dist):
        build_ext.__init__(self, dist)
        self.failed = []

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
148 149 150
    def build_extensions(self):

        # Detect which modules should be compiled
151
        missing = self.detect_modules()
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
152 153

        # Remove modules that are present on the disabled list
154 155 156 157 158 159 160 161
        extensions = [ext for ext in self.extensions
                      if ext.name not in disabled_module_list]
        # move ctypes to the end, it depends on other modules
        ext_map = dict((ext.name, i) for i, ext in enumerate(extensions))
        if "_ctypes" in ext_map:
            ctypes = extensions.pop(ext_map["_ctypes"])
            extensions.append(ctypes)
        self.extensions = extensions
162

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
163
        # Fix up the autodetected modules, prefixing all the source files
164 165
        # with Modules/.
        srcdir = sysconfig.get_config_var('srcdir')
Guido van Rossum's avatar
Guido van Rossum committed
166 167 168
        if not srcdir:
            # Maybe running on Windows but not using CYGWIN?
            raise ValueError("No source directory; cannot proceed.")
169
        srcdir = os.path.abspath(srcdir)
170
        moddirlist = [os.path.join(srcdir, 'Modules')]
171

Jack Jansen's avatar
Jack Jansen committed
172 173
        # Platform-dependent module source and include directories
        platform = self.get_platform()
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
174

175 176 177 178
        # Fix up the paths for scripts, too
        self.distribution.scripts = [os.path.join(srcdir, filename)
                                     for filename in self.distribution.scripts]

179
        # Python header files
180
        headers = [sysconfig.get_config_h_filename()]
181
        headers += glob(os.path.join(sysconfig.get_path('platinclude'), "*.h"))
182

183
        for ext in self.extensions[:]:
Jack Jansen's avatar
Jack Jansen committed
184
            ext.sources = [ find_module_file(filename, moddirlist)
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
185
                            for filename in ext.sources ]
186
            if ext.depends is not None:
187
                ext.depends = [find_module_file(filename, moddirlist)
188
                               for filename in ext.depends]
189 190 191 192 193
            else:
                ext.depends = []
            # re-compile extensions if a header file has been changed
            ext.depends.extend(headers)

194
            # If a module has already been built statically,
195
            # don't build it here
196
            if ext.name in sys.builtin_module_names:
197
                self.extensions.remove(ext)
198

199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
        # Parse Modules/Setup and Modules/Setup.local to figure out which
        # modules are turned on in the file.
        remove_modules = []
        for filename in ('Modules/Setup', 'Modules/Setup.local'):
            input = text_file.TextFile(filename, join_lines=1)
            while 1:
                line = input.readline()
                if not line: break
                line = line.split()
                remove_modules.append(line[0])
            input.close()

        for ext in self.extensions[:]:
            if ext.name in remove_modules:
                self.extensions.remove(ext)
214

215 216 217 218 219 220 221 222
        # When you run "make CC=altcc" or something similar, you really want
        # those environment variables passed into the setup.py phase.  Here's
        # a small set of useful ones.
        compiler = os.environ.get('CC')
        args = {}
        # unfortunately, distutils doesn't let us provide separate C and C++
        # compilers
        if compiler is not None:
223 224
            (ccshared,cflags) = sysconfig.get_config_vars('CCSHARED','CFLAGS')
            args['compiler_so'] = compiler + ' ' + ccshared + ' ' + cflags
225
        self.compiler.set_executables(**args)
226

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
227 228
        build_ext.build_extensions(self)

229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
        longest = max([len(e.name) for e in self.extensions])
        if self.failed:
            longest = max(longest, max([len(name) for name in self.failed]))

        def print_three_column(lst):
            lst.sort(key=str.lower)
            # guarantee zip() doesn't drop anything
            while len(lst) % 3:
                lst.append("")
            for e, f, g in zip(lst[::3], lst[1::3], lst[2::3]):
                print("%-*s   %-*s   %-*s" % (longest, e, longest, f,
                                              longest, g))

        if missing:
            print()
Benjamin Peterson's avatar
Benjamin Peterson committed
244 245
            print("Python build finished, but the necessary bits to build "
                   "these modules were not found:")
246
            print_three_column(missing)
247 248 249
            print("To find the necessary bits, look in setup.py in"
                  " detect_modules() for the module's name.")
            print()
250 251 252 253 254 255

        if self.failed:
            failed = self.failed[:]
            print()
            print("Failed to build these modules:")
            print_three_column(failed)
256
            print()
257

Marc-André Lemburg's avatar
Marc-André Lemburg committed
258 259
    def build_extension(self, ext):

260 261 262 263
        if ext.name == '_ctypes':
            if not self.configure_ctypes(ext):
                return

Marc-André Lemburg's avatar
Marc-André Lemburg committed
264 265
        try:
            build_ext.build_extension(self, ext)
266
        except (CCompilerError, DistutilsError) as why:
Marc-André Lemburg's avatar
Marc-André Lemburg committed
267 268
            self.announce('WARNING: building of extension "%s" failed: %s' %
                          (ext.name, sys.exc_info()[1]))
269
            self.failed.append(ext.name)
270
            return
271 272 273
        # Workaround for Mac OS X: The Carbon-based modules cannot be
        # reliably imported into a command-line Python
        if 'Carbon' in ext.extra_link_args:
274 275 276 277
            self.announce(
                'WARNING: skipping import check for Carbon-based "%s"' %
                ext.name)
            return
278 279

        if self.get_platform() == 'darwin' and (
Benjamin Peterson's avatar
Benjamin Peterson committed
280
                sys.maxsize > 2**32 and '-arch' in ext.extra_link_args):
281 282 283 284 285 286 287 288 289 290
            # Don't bother doing an import check when an extension was
            # build with an explicit '-arch' flag on OSX. That's currently
            # only used to build 32-bit only extensions in a 4-way
            # universal build and loading 32-bit code into a 64-bit
            # process will fail.
            self.announce(
                'WARNING: skipping import check for "%s"' %
                ext.name)
            return

291 292 293 294 295 296
        # Workaround for Cygwin: Cygwin currently has fork issues when many
        # modules have been imported
        if self.get_platform() == 'cygwin':
            self.announce('WARNING: skipping import check for Cygwin-based "%s"'
                % ext.name)
            return
Michael W. Hudson's avatar
Fix for  
Michael W. Hudson committed
297 298 299
        ext_filename = os.path.join(
            self.build_lib,
            self.get_ext_filename(self.get_ext_fullname(ext.name)))
300 301 302 303 304 305

        # If the build directory didn't exist when setup.py was
        # started, sys.path_importer_cache has a negative result
        # cached.  Clear that cache before trying to import.
        sys.path_importer_cache.clear()

306
        try:
Michael W. Hudson's avatar
Fix for  
Michael W. Hudson committed
307
            imp.load_dynamic(ext.name, ext_filename)
308
        except ImportError as why:
309
            self.failed.append(ext.name)
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
            self.announce('*** WARNING: renaming "%s" since importing it'
                          ' failed: %s' % (ext.name, why), level=3)
            assert not self.inplace
            basename, tail = os.path.splitext(ext_filename)
            newname = basename + "_failed" + tail
            if os.path.exists(newname):
                os.remove(newname)
            os.rename(ext_filename, newname)

            # XXX -- This relies on a Vile HACK in
            # distutils.command.build_ext.build_extension().  The
            # _built_objects attribute is stored there strictly for
            # use here.
            # If there is a failure, _built_objects may not be there,
            # so catch the AttributeError and move on.
            try:
                for filename in self._built_objects:
                    os.remove(filename)
            except AttributeError:
                self.announce('unable to remove files (ignored)')
330 331
        except:
            exc_type, why, tb = sys.exc_info()
332 333 334
            self.announce('*** WARNING: importing extension "%s" '
                          'failed with %s: %s' % (ext.name, exc_type, why),
                          level=3)
335
            self.failed.append(ext.name)
336

337
    def get_platform(self):
338
        # Get value of sys.platform
339
        for platform in ['cygwin', 'darwin', 'osf1']:
340 341 342
            if sys.platform.startswith(platform):
                return platform
        return sys.platform
343

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
344
    def detect_modules(self):
345
        # Ensure that /usr/local is always used
346 347
        add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib')
        add_dir_to_list(self.compiler.include_dirs, '/usr/local/include')
Michael W. Hudson's avatar
Michael W. Hudson committed
348

349
        # Add paths specified in the environment variables LDFLAGS and
350
        # CPPFLAGS for header and library files.
351 352 353
        # We must get the values from the Makefile and not the environment
        # directly since an inconsistently reproducible issue comes up where
        # the environment variable is not set even though the value were passed
354
        # into configure and stored in the Makefile (issue found on OS X 10.3).
355
        for env_var, arg_name, dir_list in (
356 357 358
                ('LDFLAGS', '-R', self.compiler.runtime_library_dirs),
                ('LDFLAGS', '-L', self.compiler.library_dirs),
                ('CPPFLAGS', '-I', self.compiler.include_dirs)):
359
            env_val = sysconfig.get_config_var(env_var)
360
            if env_val:
361
                # To prevent optparse from raising an exception about any
Skip Montanaro's avatar
Skip Montanaro committed
362
                # options in env_val that it doesn't know about we strip out
363 364 365 366 367 368 369
                # all double dashes and any dashes followed by a character
                # that is not for the option we are dealing with.
                #
                # Please note that order of the regex is important!  We must
                # strip out double-dashes first so that we don't end up with
                # substituting "--Long" to "-Long" and thus lead to "ong" being
                # used for a library directory.
370 371
                env_val = re.sub(r'(^|\s+)-(-|(?!%s))' % arg_name[1],
                                 ' ', env_val)
372
                parser = optparse.OptionParser()
373 374 375 376
                # Make sure that allowing args interspersed with options is
                # allowed
                parser.allow_interspersed_args = True
                parser.error = lambda msg: None
377 378
                parser.add_option(arg_name, dest="dirs", action="append")
                options = parser.parse_args(env_val.split())[0]
379
                if options.dirs:
Christian Heimes's avatar
Christian Heimes committed
380
                    for directory in reversed(options.dirs):
381
                        add_dir_to_list(dir_list, directory)
382

Michael W. Hudson's avatar
Fix for  
Michael W. Hudson committed
383
        if os.path.normpath(sys.prefix) != '/usr':
384
            add_dir_to_list(self.compiler.library_dirs,
Michael W. Hudson's avatar
Fix for  
Michael W. Hudson committed
385
                            sysconfig.get_config_var("LIBDIR"))
386
            add_dir_to_list(self.compiler.include_dirs,
Michael W. Hudson's avatar
Fix for  
Michael W. Hudson committed
387
                            sysconfig.get_config_var("INCLUDEDIR"))
388 389 390 391

        # lib_dirs and inc_dirs are used to search for files;
        # if a file is found in one of those directories, it can
        # be assumed that no additional -I,-L directives are needed.
392
        lib_dirs = self.compiler.library_dirs + [
393 394 395
            '/lib64', '/usr/lib64',
            '/lib', '/usr/lib',
            ]
396
        inc_dirs = self.compiler.include_dirs + ['/usr/include']
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
397
        exts = []
398
        missing = []
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
399

400 401 402
        config_h = sysconfig.get_config_h_filename()
        config_h_vars = sysconfig.parse_config_h(open(config_h))

403
        platform = self.get_platform()
404
        srcdir = sysconfig.get_config_var('srcdir')
405

406 407
        # OSF/1 and Unixware have some stuff in /usr/ccs/lib (like -ldb)
        if platform in ['osf1', 'unixware7', 'openunix8']:
408 409
            lib_dirs += ['/usr/ccs/lib']

410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
        if platform == 'darwin':
            # This should work on any unixy platform ;-)
            # If the user has bothered specifying additional -I and -L flags
            # in OPT and LDFLAGS we might as well use them here.
            #   NOTE: using shlex.split would technically be more correct, but
            # also gives a bootstrap problem. Let's hope nobody uses directories
            # with whitespace in the name to store libraries.
            cflags, ldflags = sysconfig.get_config_vars(
                    'CFLAGS', 'LDFLAGS')
            for item in cflags.split():
                if item.startswith('-I'):
                    inc_dirs.append(item[2:])

            for item in ldflags.split():
                if item.startswith('-L'):
                    lib_dirs.append(item[2:])

427 428
        # Check for MacOS X, which doesn't need libm.a at all
        math_libs = ['m']
429
        if platform == 'darwin':
430
            math_libs = []
431

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
432 433 434 435 436 437
        # XXX Omitted modules: gl, pure, dl, SGI-specific modules

        #
        # The following modules are all pretty straightforward, and compile
        # on pretty much any POSIXish platform.
        #
438

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
439
        # Some modules that are normally always on:
440
        exts.append( Extension('_weakref', ['_weakref.c']) )
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
441 442 443 444

        # array objects
        exts.append( Extension('array', ['arraymodule.c']) )
        # complex math library functions
445 446
        exts.append( Extension('cmath', ['cmathmodule.c', '_math.c'],
                               depends=['_math.h'],
447
                               libraries=math_libs) )
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
448
        # math library functions, e.g. sin()
449
        exts.append( Extension('math',  ['mathmodule.c', '_math.c'],
450
                               depends=['_math.h'],
451
                               libraries=math_libs) )
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
452
        # time operations and variables
453
        exts.append( Extension('time', ['timemodule.c', '_time.c'],
454
                               libraries=math_libs) )
455
        exts.append( Extension('_datetime', ['_datetimemodule.c', '_time.c'],
456
                               libraries=math_libs) )
457 458
        # fast iterator tools implemented in C
        exts.append( Extension("itertools", ["itertoolsmodule.c"]) )
Christian Heimes's avatar
Christian Heimes committed
459 460
        # random number generator implemented in C
        exts.append( Extension("_random", ["_randommodule.c"]) )
461
        # high-performance collections
462
        exts.append( Extension("_collections", ["_collectionsmodule.c"]) )
463 464
        # bisect
        exts.append( Extension("_bisect", ["_bisectmodule.c"]) )
465
        # heapq
466
        exts.append( Extension("_heapq", ["_heapqmodule.c"]) )
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
467 468
        # operator.add() and similar goodies
        exts.append( Extension('operator', ['operator.c']) )
469 470
        # C-optimized pickle replacement
        exts.append( Extension("_pickle", ["_pickle.c"]) )
471 472
        # atexit
        exts.append( Extension("atexit", ["atexitmodule.c"]) )
473 474
        # _json speedups
        exts.append( Extension("_json", ["_json.c"]) )
Marc-André Lemburg's avatar
Marc-André Lemburg committed
475
        # Python C API test module
476 477
        exts.append( Extension('_testcapi', ['_testcapimodule.c'],
                               depends=['testcapi_long.h']) )
Fred Drake's avatar
Fred Drake committed
478
        # profiler (_lsprof is for cProfile.py)
Armin Rigo's avatar
Armin Rigo committed
479
        exts.append( Extension('_lsprof', ['_lsprof.c', 'rotatingtree.c']) )
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
480
        # static Unicode character database
481
        exts.append( Extension('unicodedata', ['unicodedata.c']) )
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
482 483 484 485 486 487 488

        # Modules with some UNIX dependencies -- on by default:
        # (If you have a really backward UNIX, select and socket may not be
        # supported...)

        # fcntl(2) and ioctl(2)
        exts.append( Extension('fcntl', ['fcntlmodule.c']) )
489 490 491 492 493 494 495 496
        # pwd(3)
        exts.append( Extension('pwd', ['pwdmodule.c']) )
        # grp(3)
        exts.append( Extension('grp', ['grpmodule.c']) )
        # spwd, shadow passwords
        if (config_h_vars.get('HAVE_GETSPNAM', False) or
                config_h_vars.get('HAVE_GETSPENT', False)):
            exts.append( Extension('spwd', ['spwdmodule.c']) )
497
        else:
498
            missing.append('spwd')
499

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
500 501 502 503 504 505 506
        # select(2); not on ancient System V
        exts.append( Extension('select', ['selectmodule.c']) )

        # Fred Drake's interface to the Python parser
        exts.append( Extension('parser', ['parsermodule.c']) )

        # Memory-mapped files (also works on Win32).
507
        exts.append( Extension('mmap', ['mmapmodule.c']) )
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
508

509
        # Lance Ellinghaus's syslog module
510 511
        # syslog daemon interface
        exts.append( Extension('syslog', ['syslogmodule.c']) )
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
512 513

        #
514 515
        # Here ends the simple stuff.  From here on, modules need certain
        # libraries, are platform-specific, or present other surprises.
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
516 517 518 519 520 521
        #

        # Multimedia modules
        # These don't work for 64-bit platforms!!!
        # These represent audio samples or images as strings:

522
        # Operations on audio samples
Tim Peters's avatar
Tim Peters committed
523
        # According to #993173, this one should actually work fine on
524 525 526
        # 64-bit platforms.
        exts.append( Extension('audioop', ['audioop.c']) )

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
527
        # readline
528
        do_readline = self.compiler.find_library_file(lib_dirs, 'readline')
529 530 531 532 533 534 535 536
        readline_termcap_library = ""
        curses_library = ""
        # Determine if readline is already linked against curses or tinfo.
        if do_readline and find_executable('ldd'):
            # Cannot use os.popen here in py3k.
            tmpfile = os.path.join(self.build_temp, 'readline_termcap_lib')
            if not os.path.exists(self.build_temp):
                os.makedirs(self.build_temp)
537 538 539 540 541 542 543 544 545 546 547 548 549
            ret = os.system("ldd %s > %s" % (do_readline, tmpfile))
            if ret >> 8 == 0:
                fp = open(tmpfile)
                for ln in fp:
                    if 'curses' in ln:
                        readline_termcap_library = re.sub(
                            r'.*lib(n?cursesw?)\.so.*', r'\1', ln
                        ).rstrip()
                        break
                    if 'tinfo' in ln: # termcap interface split out from ncurses
                        readline_termcap_library = 'tinfo'
                        break
                fp.close()
550 551 552 553 554
            os.unlink(tmpfile)
        # Issue 7384: If readline is already linked against curses,
        # use the same library for the readline and curses modules.
        if 'curses' in readline_termcap_library:
            curses_library = readline_termcap_library
555
        elif self.compiler.find_library_file(lib_dirs, 'ncursesw'):
556
            curses_library = 'ncursesw'
557
        elif self.compiler.find_library_file(lib_dirs, 'ncurses'):
558
            curses_library = 'ncurses'
559
        elif self.compiler.find_library_file(lib_dirs, 'curses'):
560 561
            curses_library = 'curses'

562 563
        if platform == 'darwin':
            os_release = int(os.uname()[2].split('.')[0])
564 565 566
            dep_target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
            if dep_target and dep_target.split('.') < ['10', '5']:
                os_release = 8
567 568 569 570 571 572
            if os_release < 9:
                # MacOSX 10.4 has a broken readline. Don't try to build
                # the readline module unless the user has installed a fixed
                # readline package
                if find_file('readline/rlconf.h', inc_dirs, []) is None:
                    do_readline = False
573
        if do_readline:
574
            if platform == 'darwin' and os_release < 9:
575 576
                # In every directory on the search path search for a dynamic
                # library and then a static library, instead of first looking
Fred Drake's avatar
Fred Drake committed
577
                # for dynamic libraries on the entire path.
578
                # This way a staticly linked custom readline gets picked up
579
                # before the (possibly broken) dynamic library in /usr/lib.
580 581 582 583
                readline_extra_link_args = ('-Wl,-search_paths_first',)
            else:
                readline_extra_link_args = ()

584
            readline_libs = ['readline']
585 586 587 588
            if readline_termcap_library:
                pass # Issue 7384: Already linked against curses or tinfo.
            elif curses_library:
                readline_libs.append(curses_library)
589
            elif self.compiler.find_library_file(lib_dirs +
590 591
                                                     ['/usr/lib/termcap'],
                                                     'termcap'):
592
                readline_libs.append('termcap')
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
593
            exts.append( Extension('readline', ['readline.c'],
Marc-André Lemburg's avatar
Marc-André Lemburg committed
594
                                   library_dirs=['/usr/lib/termcap'],
595
                                   extra_link_args=readline_extra_link_args,
596
                                   libraries=readline_libs) )
597 598 599
        else:
            missing.append('readline')

600
        # crypt module.
Tim Peters's avatar
Tim Peters committed
601

602
        if self.compiler.find_library_file(lib_dirs, 'crypt'):
603
            libs = ['crypt']
604
        else:
605 606
            libs = []
        exts.append( Extension('crypt', ['cryptmodule.c'], libraries=libs) )
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
607

Skip Montanaro's avatar
Skip Montanaro committed
608 609 610
        # CSV files
        exts.append( Extension('_csv', ['_csv.c']) )

611 612 613
        # POSIX subprocess module helper.
        exts.append( Extension('_posixsubprocess', ['_posixsubprocess.c']) )

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
614
        # socket(2)
615
        exts.append( Extension('_socket', ['socketmodule.c'],
616
                               depends = ['socketmodule.h']) )
617
        # Detect SSL support for the socket module (via _ssl)
618 619
        search_for_ssl_incs_in = [
                              '/usr/local/ssl/include',
620 621
                              '/usr/contrib/ssl/include/'
                             ]
622 623
        ssl_incs = find_file('openssl/ssl.h', inc_dirs,
                             search_for_ssl_incs_in
624
                             )
625 626 627 628 629
        if ssl_incs is not None:
            krb5_h = find_file('krb5.h', inc_dirs,
                               ['/usr/kerberos/include'])
            if krb5_h:
                ssl_incs += krb5_h
630
        ssl_libs = find_library_file(self.compiler, 'ssl',lib_dirs,
631 632 633
                                     ['/usr/local/ssl/lib',
                                      '/usr/contrib/ssl/lib/'
                                     ] )
634

635 636
        if (ssl_incs is not None and
            ssl_libs is not None):
637
            exts.append( Extension('_ssl', ['_ssl.c'],
638
                                   include_dirs = ssl_incs,
639
                                   library_dirs = ssl_libs,
640
                                   libraries = ['ssl', 'crypto'],
641
                                   depends = ['socketmodule.h']), )
642 643
        else:
            missing.append('_ssl')
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
644

645 646 647 648 649
        # find out which version of OpenSSL we have
        openssl_ver = 0
        openssl_ver_re = re.compile(
            '^\s*#\s*define\s+OPENSSL_VERSION_NUMBER\s+(0x[0-9a-fA-F]+)' )

650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
        # look for the openssl version header on the compiler search path.
        opensslv_h = find_file('openssl/opensslv.h', [],
                inc_dirs + search_for_ssl_incs_in)
        if opensslv_h:
            name = os.path.join(opensslv_h[0], 'openssl/opensslv.h')
            if sys.platform == 'darwin' and is_macosx_sdk_path(name):
                name = os.path.join(macosx_sdk_root(), name[1:])
            try:
                incfile = open(name, 'r')
                for line in incfile:
                    m = openssl_ver_re.match(line)
                    if m:
                        openssl_ver = eval(m.group(1))
            except IOError as msg:
                print("IOError while reading opensshv.h:", msg)
                pass
666

667
        #print('openssl_ver = 0x%08x' % openssl_ver)
668 669 670 671
        min_openssl_ver = 0x00907000
        have_any_openssl = ssl_incs is not None and ssl_libs is not None
        have_usable_openssl = (have_any_openssl and
                               openssl_ver >= min_openssl_ver)
672

673 674
        if have_any_openssl:
            if have_usable_openssl:
675 676 677
                # The _hashlib module wraps optimized implementations
                # of hash functions from the OpenSSL library.
                exts.append( Extension('_hashlib', ['_hashopenssl.c'],
Gregory P. Smith's avatar
Gregory P. Smith committed
678
                                       depends = ['hashlib.h'],
679 680 681 682 683 684 685
                                       include_dirs = ssl_incs,
                                       library_dirs = ssl_libs,
                                       libraries = ['ssl', 'crypto']) )
            else:
                print("warning: openssl 0x%08x is too old for _hashlib" %
                      openssl_ver)
                missing.append('_hashlib')
Gregory P. Smith's avatar
Gregory P. Smith committed
686

687 688
        min_sha2_openssl_ver = 0x00908000
        if COMPILED_WITH_PYDEBUG or openssl_ver < min_sha2_openssl_ver:
689
            # OpenSSL doesn't do these until 0.9.8 so we'll bring our own hash
Gregory P. Smith's avatar
Gregory P. Smith committed
690 691 692 693
            exts.append( Extension('_sha256', ['sha256module.c'],
                                   depends=['hashlib.h']) )
            exts.append( Extension('_sha512', ['sha512module.c'],
                                   depends=['hashlib.h']) )
Gregory P. Smith's avatar
Gregory P. Smith committed
694

695
        if COMPILED_WITH_PYDEBUG or not have_usable_openssl:
696
            # no openssl at all, use our own md5 and sha1
Gregory P. Smith's avatar
Gregory P. Smith committed
697 698 699 700
            exts.append( Extension('_md5', ['md5module.c'],
                                   depends=['hashlib.h']) )
            exts.append( Extension('_sha1', ['sha1module.c'],
                                   depends=['hashlib.h']) )
701

702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
        # Modules that provide persistent dictionary-like semantics.  You will
        # probably want to arrange for at least one of them to be available on
        # your machine, though none are defined by default because of library
        # dependencies.  The Python module dbm/__init__.py provides an
        # implementation independent wrapper for these; dbm/dumb.py provides
        # similar functionality (but slower of course) implemented in Python.

        # Sleepycat^WOracle Berkeley DB interface.
        #  http://www.oracle.com/database/berkeley-db/db/index.html
        #
        # This requires the Sleepycat^WOracle DB code. The supported versions
        # are set below.  Visit the URL above to download
        # a release.  Most open source OSes come with one or more
        # versions of BerkeleyDB already installed.

717
        max_db_ver = (4, 8)
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
        min_db_ver = (3, 3)
        db_setup_debug = False   # verbose debug prints from this script?

        def allow_db_ver(db_ver):
            """Returns a boolean if the given BerkeleyDB version is acceptable.

            Args:
              db_ver: A tuple of the version to verify.
            """
            if not (min_db_ver <= db_ver <= max_db_ver):
                return False
            return True

        def gen_db_minor_ver_nums(major):
            if major == 4:
                for x in range(max_db_ver[1]+1):
                    if allow_db_ver((4, x)):
                        yield x
            elif major == 3:
                for x in (3,):
                    if allow_db_ver((3, x)):
                        yield x
            else:
                raise ValueError("unknown major BerkeleyDB version", major)

        # construct a list of paths to look for the header file in on
        # top of the normal inc_dirs.
        db_inc_paths = [
            '/usr/include/db4',
            '/usr/local/include/db4',
            '/opt/sfw/include/db4',
            '/usr/include/db3',
            '/usr/local/include/db3',
            '/opt/sfw/include/db3',
            # Fink defaults (http://fink.sourceforge.net/)
            '/sw/include/db4',
            '/sw/include/db3',
        ]
        # 4.x minor number specific paths
        for x in gen_db_minor_ver_nums(4):
            db_inc_paths.append('/usr/include/db4%d' % x)
            db_inc_paths.append('/usr/include/db4.%d' % x)
            db_inc_paths.append('/usr/local/BerkeleyDB.4.%d/include' % x)
            db_inc_paths.append('/usr/local/include/db4%d' % x)
            db_inc_paths.append('/pkg/db-4.%d/include' % x)
            db_inc_paths.append('/opt/db-4.%d/include' % x)
            # MacPorts default (http://www.macports.org/)
            db_inc_paths.append('/opt/local/include/db4%d' % x)
        # 3.x minor number specific paths
        for x in gen_db_minor_ver_nums(3):
            db_inc_paths.append('/usr/include/db3%d' % x)
            db_inc_paths.append('/usr/local/BerkeleyDB.3.%d/include' % x)
            db_inc_paths.append('/usr/local/include/db3%d' % x)
            db_inc_paths.append('/pkg/db-3.%d/include' % x)
            db_inc_paths.append('/opt/db-3.%d/include' % x)

        # Add some common subdirectories for Sleepycat DB to the list,
        # based on the standard include directories. This way DB3/4 gets
        # picked up when it is installed in a non-standard prefix and
        # the user has added that prefix into inc_dirs.
        std_variants = []
        for dn in inc_dirs:
            std_variants.append(os.path.join(dn, 'db3'))
            std_variants.append(os.path.join(dn, 'db4'))
            for x in gen_db_minor_ver_nums(4):
                std_variants.append(os.path.join(dn, "db4%d"%x))
                std_variants.append(os.path.join(dn, "db4.%d"%x))
            for x in gen_db_minor_ver_nums(3):
                std_variants.append(os.path.join(dn, "db3%d"%x))
                std_variants.append(os.path.join(dn, "db3.%d"%x))

        db_inc_paths = std_variants + db_inc_paths
        db_inc_paths = [p for p in db_inc_paths if os.path.exists(p)]

        db_ver_inc_map = {}

794 795 796
        if sys.platform == 'darwin':
            sysroot = macosx_sdk_root()

797 798 799 800 801 802
        class db_found(Exception): pass
        try:
            # See whether there is a Sleepycat header in the standard
            # search path.
            for d in inc_dirs + db_inc_paths:
                f = os.path.join(d, "db.h")
803 804 805
                if sys.platform == 'darwin' and is_macosx_sdk_path(d):
                    f = os.path.join(sysroot, d[1:], "db.h")

806 807
                if db_setup_debug: print("db: looking for db.h in", f)
                if os.path.exists(f):
808 809
                    f = open(f, "rb").read()
                    m = re.search(br"#define\WDB_VERSION_MAJOR\W(\d+)", f)
810 811
                    if m:
                        db_major = int(m.group(1))
812
                        m = re.search(br"#define\WDB_VERSION_MINOR\W(\d+)", f)
813 814 815 816 817
                        db_minor = int(m.group(1))
                        db_ver = (db_major, db_minor)

                        # Avoid 4.6 prior to 4.6.21 due to a BerkeleyDB bug
                        if db_ver == (4, 6):
818
                            m = re.search(br"#define\WDB_VERSION_PATCH\W(\d+)", f)
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
                            db_patch = int(m.group(1))
                            if db_patch < 21:
                                print("db.h:", db_ver, "patch", db_patch,
                                      "being ignored (4.6.x must be >= 4.6.21)")
                                continue

                        if ( (db_ver not in db_ver_inc_map) and
                            allow_db_ver(db_ver) ):
                            # save the include directory with the db.h version
                            # (first occurrence only)
                            db_ver_inc_map[db_ver] = d
                            if db_setup_debug:
                                print("db.h: found", db_ver, "in", d)
                        else:
                            # we already found a header for this library version
                            if db_setup_debug: print("db.h: ignoring", d)
                    else:
                        # ignore this header, it didn't contain a version number
                        if db_setup_debug:
                            print("db.h: no version number version in", d)

            db_found_vers = list(db_ver_inc_map.keys())
            db_found_vers.sort()

            while db_found_vers:
                db_ver = db_found_vers.pop()
                db_incdir = db_ver_inc_map[db_ver]

                # check lib directories parallel to the location of the header
                db_dirs_to_check = [
                    db_incdir.replace("include", 'lib64'),
                    db_incdir.replace("include", 'lib'),
                ]
852 853 854 855 856 857 858 859 860 861 862 863 864 865

                if sys.platform != 'darwin':
                    db_dirs_to_check = list(filter(os.path.isdir, db_dirs_to_check))

                else:
                    # Same as other branch, but takes OSX SDK into account
                    tmp = []
                    for dn in db_dirs_to_check:
                        if is_macosx_sdk_path(dn):
                            if os.path.isdir(os.path.join(sysroot, dn[1:])):
                                tmp.append(dn)
                        else:
                            if os.path.isdir(dn):
                                tmp.append(dn)
866
                    db_dirs_to_check = tmp
867 868

                    db_dirs_to_check = tmp
869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896

                # Look for a version specific db-X.Y before an ambiguoius dbX
                # XXX should we -ever- look for a dbX name?  Do any
                # systems really not name their library by version and
                # symlink to more general names?
                for dblib in (('db-%d.%d' % db_ver),
                              ('db%d%d' % db_ver),
                              ('db%d' % db_ver[0])):
                    dblib_file = self.compiler.find_library_file(
                                    db_dirs_to_check + lib_dirs, dblib )
                    if dblib_file:
                        dblib_dir = [ os.path.abspath(os.path.dirname(dblib_file)) ]
                        raise db_found
                    else:
                        if db_setup_debug: print("db lib: ", dblib, "not found")

        except db_found:
            if db_setup_debug:
                print("bsddb using BerkeleyDB lib:", db_ver, dblib)
                print("bsddb lib dir:", dblib_dir, " inc dir:", db_incdir)
            db_incs = [db_incdir]
            dblibs = [dblib]
        else:
            if db_setup_debug: print("db: no appropriate library found")
            db_incs = None
            dblibs = []
            dblib_dir = None

897
        # The sqlite interface
898
        sqlite_setup_debug = False   # verbose debug prints from this script?
899 900 901 902 903 904 905 906 907 908 909 910 911 912

        # We hunt for #define SQLITE_VERSION "n.n.n"
        # We need to find >= sqlite version 3.0.8
        sqlite_incdir = sqlite_libdir = None
        sqlite_inc_paths = [ '/usr/include',
                             '/usr/include/sqlite',
                             '/usr/include/sqlite3',
                             '/usr/local/include',
                             '/usr/local/include/sqlite',
                             '/usr/local/include/sqlite3',
                           ]
        MIN_SQLITE_VERSION_NUMBER = (3, 0, 8)
        MIN_SQLITE_VERSION = ".".join([str(x)
                                    for x in MIN_SQLITE_VERSION_NUMBER])
913 914 915 916

        # Scan the default include directories before the SQLite specific
        # ones. This allows one to override the copy of sqlite on OSX,
        # where /usr/include contains an old version of sqlite.
917 918 919
        if sys.platform == 'darwin':
            sysroot = macosx_sdk_root()

920
        for d in inc_dirs + sqlite_inc_paths:
921
            f = os.path.join(d, "sqlite3.h")
922 923 924 925

            if sys.platform == 'darwin' and is_macosx_sdk_path(d):
                f = os.path.join(sysroot, d[1:], "sqlite3.h")

926
            if os.path.exists(f):
927
                if sqlite_setup_debug: print("sqlite: found %s"%f)
928 929 930 931 932 933 934 935 936
                incf = open(f).read()
                m = re.search(
                    r'\s*.*#\s*.*define\s.*SQLITE_VERSION\W*"(.*)"', incf)
                if m:
                    sqlite_version = m.group(1)
                    sqlite_version_tuple = tuple([int(x)
                                        for x in sqlite_version.split(".")])
                    if sqlite_version_tuple >= MIN_SQLITE_VERSION_NUMBER:
                        # we win!
937
                        if sqlite_setup_debug:
938
                            print("%s/sqlite3.h: version %s"%(d, sqlite_version))
939 940 941 942
                        sqlite_incdir = d
                        break
                    else:
                        if sqlite_setup_debug:
943 944
                            print("%s: version %d is too old, need >= %s"%(d,
                                        sqlite_version, MIN_SQLITE_VERSION))
945
                elif sqlite_setup_debug:
946
                    print("sqlite: %s had no SQLITE_VERSION"%(f,))
947 948 949 950 951 952 953 954

        if sqlite_incdir:
            sqlite_dirs_to_check = [
                os.path.join(sqlite_incdir, '..', 'lib64'),
                os.path.join(sqlite_incdir, '..', 'lib'),
                os.path.join(sqlite_incdir, '..', '..', 'lib64'),
                os.path.join(sqlite_incdir, '..', '..', 'lib'),
            ]
955
            sqlite_libfile = self.compiler.find_library_file(
956
                                sqlite_dirs_to_check + lib_dirs, 'sqlite3')
Benjamin Peterson's avatar
Benjamin Peterson committed
957 958
            if sqlite_libfile:
                sqlite_libdir = [os.path.abspath(os.path.dirname(sqlite_libfile))]
959 960

        if sqlite_incdir and sqlite_libdir:
961
            sqlite_srcs = ['_sqlite/cache.c',
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976
                '_sqlite/connection.c',
                '_sqlite/cursor.c',
                '_sqlite/microprotocols.c',
                '_sqlite/module.c',
                '_sqlite/prepare_protocol.c',
                '_sqlite/row.c',
                '_sqlite/statement.c',
                '_sqlite/util.c', ]

            sqlite_defines = []
            if sys.platform != "win32":
                sqlite_defines.append(('MODULE_NAME', '"sqlite3"'))
            else:
                sqlite_defines.append(('MODULE_NAME', '\\"sqlite3\\"'))

977 978
            # Comment this out if you want the sqlite3 module to be able to load extensions.
            sqlite_defines.append(("SQLITE_OMIT_LOAD_EXTENSION", "1"))
979 980 981 982 983 984 985 986 987 988

            if sys.platform == 'darwin':
                # In every directory on the search path search for a dynamic
                # library and then a static library, instead of first looking
                # for dynamic libraries on the entiry path.
                # This way a staticly linked custom sqlite gets picked up
                # before the dynamic library in /usr/lib.
                sqlite_extra_link_args = ('-Wl,-search_paths_first',)
            else:
                sqlite_extra_link_args = ()
989 990 991 992 993 994 995

            exts.append(Extension('_sqlite3', sqlite_srcs,
                                  define_macros=sqlite_defines,
                                  include_dirs=["Modules/_sqlite",
                                                sqlite_incdir],
                                  library_dirs=sqlite_libdir,
                                  runtime_library_dirs=sqlite_libdir,
996
                                  extra_link_args=sqlite_extra_link_args,
997
                                  libraries=["sqlite3",]))
998 999
        else:
            missing.append('_sqlite3')
1000

1001
        dbm_order = ['gdbm']
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1002
        # The standard Unix dbm module:
1003
        if platform not in ['cygwin']:
1004 1005
            config_args = [arg.strip("'")
                           for arg in sysconfig.get_config_var("CONFIG_ARGS").split()]
1006
            dbm_args = [arg for arg in config_args
1007 1008
                        if arg.startswith('--with-dbmliborder=')]
            if dbm_args:
1009
                dbm_order = [arg.split('=')[-1] for arg in dbm_args][-1].split(":")
1010
            else:
1011
                dbm_order = "ndbm:gdbm:bdb".split(":")
1012 1013 1014 1015 1016
            dbmext = None
            for cand in dbm_order:
                if cand == "ndbm":
                    if find_file("ndbm.h", inc_dirs, []) is not None:
                        # Some systems have -lndbm, others don't
1017
                        if self.compiler.find_library_file(lib_dirs,
1018
                                                               'ndbm'):
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
                            ndbm_libs = ['ndbm']
                        else:
                            ndbm_libs = []
                        print("building dbm using ndbm")
                        dbmext = Extension('_dbm', ['_dbmmodule.c'],
                                           define_macros=[
                                               ('HAVE_NDBM_H',None),
                                               ],
                                           libraries=ndbm_libs)
                        break

                elif cand == "gdbm":
1031
                    if self.compiler.find_library_file(lib_dirs, 'gdbm'):
1032
                        gdbm_libs = ['gdbm']
1033
                        if self.compiler.find_library_file(lib_dirs,
1034
                                                               'gdbm_compat'):
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
                            gdbm_libs.append('gdbm_compat')
                        if find_file("gdbm/ndbm.h", inc_dirs, []) is not None:
                            print("building dbm using gdbm")
                            dbmext = Extension(
                                '_dbm', ['_dbmmodule.c'],
                                define_macros=[
                                    ('HAVE_GDBM_NDBM_H', None),
                                    ],
                                libraries = gdbm_libs)
                            break
                        if find_file("gdbm-ndbm.h", inc_dirs, []) is not None:
                            print("building dbm using gdbm")
                            dbmext = Extension(
                                '_dbm', ['_dbmmodule.c'],
                                define_macros=[
                                    ('HAVE_GDBM_DASH_NDBM_H', None),
                                    ],
                                libraries = gdbm_libs)
                            break
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
                elif cand == "bdb":
                    if db_incs is not None:
                        print("building dbm using bdb")
                        dbmext = Extension('_dbm', ['_dbmmodule.c'],
                                           library_dirs=dblib_dir,
                                           runtime_library_dirs=dblib_dir,
                                           include_dirs=db_incs,
                                           define_macros=[
                                               ('HAVE_BERKDB_H', None),
                                               ('DB_DBM_HSEARCH', None),
                                               ],
                                           libraries=dblibs)
1066 1067 1068
                        break
            if dbmext is not None:
                exts.append(dbmext)
1069
            else:
1070
                missing.append('_dbm')
1071

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1072
        # Anthony Baxter's gdbm module.  GNU dbm(3) will require -lgdbm:
1073
        if ('gdbm' in dbm_order and
1074
            self.compiler.find_library_file(lib_dirs, 'gdbm')):
1075
            exts.append( Extension('_gdbm', ['_gdbmmodule.c'],
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1076
                                   libraries = ['gdbm'] ) )
1077
        else:
1078
            missing.append('_gdbm')
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1079 1080

        # Unix-only modules
1081
        if platform != 'win32':
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1082 1083 1084
            # Steen Lumholt's termios module
            exts.append( Extension('termios', ['termios.c']) )
            # Jeremy Hylton's rlimit interface
1085
            exts.append( Extension('resource', ['resource.c']) )
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1086

1087
            # Sun yellow pages. Some systems have the functions in libc.
1088 1089
            if (platform not in ['cygwin', 'qnx6'] and
                find_file('rpcsvc/yp_prot.h', inc_dirs, []) is not None):
1090
                if (self.compiler.find_library_file(lib_dirs, 'nsl')):
1091 1092 1093 1094 1095
                    libs = ['nsl']
                else:
                    libs = []
                exts.append( Extension('nis', ['nismodule.c'],
                                       libraries = libs) )
1096 1097 1098 1099
            else:
                missing.append('nis')
        else:
            missing.extend(['nis', 'resource', 'termios'])
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1100

1101
        # Curses support, requiring the System V version of curses, often
1102
        # provided by the ncurses library.
1103
        panel_library = 'panel'
1104 1105 1106 1107 1108 1109
        if curses_library.startswith('ncurses'):
            if curses_library == 'ncursesw':
                # Bug 1464056: If _curses.so links with ncursesw,
                # _curses_panel.so must link with panelw.
                panel_library = 'panelw'
            curses_libs = [curses_library]
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1110 1111
            exts.append( Extension('_curses', ['_cursesmodule.c'],
                                   libraries = curses_libs) )
1112
        elif curses_library == 'curses' and platform != 'darwin':
1113 1114
                # OSX has an old Berkeley curses, not good enough for
                # the _curses module.
1115
            if (self.compiler.find_library_file(lib_dirs, 'terminfo')):
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1116
                curses_libs = ['curses', 'terminfo']
1117
            elif (self.compiler.find_library_file(lib_dirs, 'termcap')):
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1118
                curses_libs = ['curses', 'termcap']
1119 1120
            else:
                curses_libs = ['curses']
1121

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1122 1123
            exts.append( Extension('_curses', ['_cursesmodule.c'],
                                   libraries = curses_libs) )
1124 1125
        else:
            missing.append('_curses')
1126

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1127
        # If the curses module is enabled, check for the panel module
1128
        if (module_enabled(exts, '_curses') and
1129
            self.compiler.find_library_file(lib_dirs, panel_library)):
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1130
            exts.append( Extension('_curses_panel', ['_curses_panel.c'],
1131
                                   libraries = [panel_library] + curses_libs) )
1132 1133
        else:
            missing.append('_curses_panel')
1134

1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146
        # Andrew Kuchling's zlib module.  Note that some versions of zlib
        # 1.1.3 have security problems.  See CERT Advisory CA-2002-07:
        # http://www.cert.org/advisories/CA-2002-07.html
        #
        # zlib 1.1.4 is fixed, but at least one vendor (RedHat) has decided to
        # patch its zlib 1.1.3 package instead of upgrading to 1.1.4.  For
        # now, we still accept 1.1.3, because we think it's difficult to
        # exploit this in Python, and we'd rather make it RedHat's problem
        # than our problem <wink>.
        #
        # You can upgrade zlib to version 1.1.4 yourself by going to
        # http://www.gzip.org/zlib/
1147
        zlib_inc = find_file('zlib.h', [], inc_dirs)
1148
        have_zlib = False
1149 1150 1151
        if zlib_inc is not None:
            zlib_h = zlib_inc[0] + '/zlib.h'
            version = '"0.0.0"'
1152
            version_req = '"1.1.3"'
1153 1154 1155 1156 1157
            fp = open(zlib_h)
            while 1:
                line = fp.readline()
                if not line:
                    break
1158
                if line.startswith('#define ZLIB_VERSION'):
1159 1160 1161
                    version = line.split()[2]
                    break
            if version >= version_req:
1162
                if (self.compiler.find_library_file(lib_dirs, 'z')):
1163 1164 1165 1166
                    if sys.platform == "darwin":
                        zlib_extra_link_args = ('-Wl,-search_paths_first',)
                    else:
                        zlib_extra_link_args = ()
1167
                    exts.append( Extension('zlib', ['zlibmodule.c'],
1168 1169
                                           libraries = ['z'],
                                           extra_link_args = zlib_extra_link_args))
1170
                    have_zlib = True
1171 1172 1173 1174 1175 1176
                else:
                    missing.append('zlib')
            else:
                missing.append('zlib')
        else:
            missing.append('zlib')
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1177

1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
        # Helper module for various ascii-encoders.  Uses zlib for an optimized
        # crc32 if we have it.  Otherwise binascii uses its own.
        if have_zlib:
            extra_compile_args = ['-DUSE_ZLIB_CRC32']
            libraries = ['z']
            extra_link_args = zlib_extra_link_args
        else:
            extra_compile_args = []
            libraries = []
            extra_link_args = []
        exts.append( Extension('binascii', ['binascii.c'],
                               extra_compile_args = extra_compile_args,
                               libraries = libraries,
                               extra_link_args = extra_link_args) )

1193
        # Gustavo Niemeyer's bz2 module.
1194
        if (self.compiler.find_library_file(lib_dirs, 'bz2')):
1195 1196 1197 1198
            if sys.platform == "darwin":
                bz2_extra_link_args = ('-Wl,-search_paths_first',)
            else:
                bz2_extra_link_args = ()
1199
            exts.append( Extension('bz2', ['bz2module.c'],
1200 1201
                                   libraries = ['bz2'],
                                   extra_link_args = bz2_extra_link_args) )
1202 1203
        else:
            missing.append('bz2')
1204

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1205 1206
        # Interface to the Expat XML parser
        #
1207 1208 1209 1210 1211 1212
        # Expat was written by James Clark and is now maintained by a group of
        # developers on SourceForge; see www.libexpat.org for more information.
        # The pyexpat module was written by Paul Prescod after a prototype by
        # Jack Jansen.  The Expat source is included in Modules/expat/.  Usage
        # of a system shared libexpat.so is possible with --with-system-expat
        # cofigure option.
1213 1214 1215
        #
        # More information on Expat can be found at www.libexpat.org.
        #
1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229
        if '--with-system-expat' in sysconfig.get_config_var("CONFIG_ARGS"):
            expat_inc = []
            define_macros = []
            expat_lib = ['expat']
            expat_sources = []
        else:
            expat_inc = [os.path.join(os.getcwd(), srcdir, 'Modules', 'expat')]
            define_macros = [
                ('HAVE_EXPAT_CONFIG_H', '1'),
            ]
            expat_lib = []
            expat_sources = ['expat/xmlparse.c',
                             'expat/xmlrole.c',
                             'expat/xmltok.c']
1230

1231 1232
        exts.append(Extension('pyexpat',
                              define_macros = define_macros,
1233 1234 1235
                              include_dirs = expat_inc,
                              libraries = expat_lib,
                              sources = ['pyexpat.c'] + expat_sources
1236
                              ))
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1237

1238 1239 1240
        # Fredrik Lundh's cElementTree module.  Note that this also
        # uses expat (via the CAPI hook in pyexpat).

1241
        if os.path.isfile(os.path.join(srcdir, 'Modules', '_elementtree.c')):
1242 1243 1244
            define_macros.append(('USE_PYEXPAT_CAPI', None))
            exts.append(Extension('_elementtree',
                                  define_macros = define_macros,
1245 1246
                                  include_dirs = expat_inc,
                                  libraries = expat_lib,
1247 1248
                                  sources = ['_elementtree.c'],
                                  ))
1249 1250
        else:
            missing.append('_elementtree')
1251

1252
        # Hye-Shik Chang's CJKCodecs modules.
1253 1254 1255 1256 1257
        exts.append(Extension('_multibytecodec',
                              ['cjkcodecs/multibytecodec.c']))
        for loc in ('kr', 'jp', 'cn', 'tw', 'hk', 'iso2022'):
            exts.append(Extension('_codecs_%s' % loc,
                                  ['cjkcodecs/_codecs_%s.c' % loc]))
1258

1259
        # Thomas Heller's _ctypes module
1260
        self.detect_ctypes(inc_dirs, lib_dirs)
1261

1262 1263 1264 1265 1266 1267
        # Richard Oudkerk's multiprocessing module
        if platform == 'win32':             # Windows
            macros = dict()
            libraries = ['ws2_32']

        elif platform == 'darwin':          # Mac OSX
1268
            macros = dict()
1269 1270 1271
            libraries = []

        elif platform == 'cygwin':          # Cygwin
1272
            macros = dict()
1273
            libraries = []
Benjamin Peterson's avatar
Benjamin Peterson committed
1274

1275
        elif platform in ('freebsd4', 'freebsd5', 'freebsd6', 'freebsd7', 'freebsd8'):
Benjamin Peterson's avatar
Benjamin Peterson committed
1276 1277
            # FreeBSD's P1003.1b semaphore support is very experimental
            # and has many known problems. (as of June 2008)
1278
            macros = dict()
Benjamin Peterson's avatar
Benjamin Peterson committed
1279 1280
            libraries = []

1281
        elif platform.startswith('openbsd'):
1282
            macros = dict()
1283 1284
            libraries = []

1285
        elif platform.startswith('netbsd'):
1286
            macros = dict()
1287 1288
            libraries = []

1289
        else:                                   # Linux and other unices
1290
            macros = dict()
1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304
            libraries = ['rt']

        if platform == 'win32':
            multiprocessing_srcs = [ '_multiprocessing/multiprocessing.c',
                                     '_multiprocessing/semaphore.c',
                                     '_multiprocessing/pipe_connection.c',
                                     '_multiprocessing/socket_connection.c',
                                     '_multiprocessing/win32_functions.c'
                                   ]

        else:
            multiprocessing_srcs = [ '_multiprocessing/multiprocessing.c',
                                     '_multiprocessing/socket_connection.c'
                                   ]
1305 1306
            if (sysconfig.get_config_var('HAVE_SEM_OPEN') and not
                sysconfig.get_config_var('POSIX_SEMAPHORES_NOT_ENABLED')):
1307 1308
                multiprocessing_srcs.append('_multiprocessing/semaphore.c')

Jesse Noller's avatar
Jesse Noller committed
1309 1310 1311 1312 1313 1314
        if sysconfig.get_config_var('WITH_THREAD'):
            exts.append ( Extension('_multiprocessing', multiprocessing_srcs,
                                    define_macros=list(macros.items()),
                                    include_dirs=["Modules/_multiprocessing"]))
        else:
            missing.append('_multiprocessing')
1315
        # End multiprocessing
1316

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1317
        # Platform-specific libraries
1318 1319 1320
        if (platform in ('linux2', 'freebsd4', 'freebsd5', 'freebsd6',
                        'freebsd7', 'freebsd8')
            or platform.startswith("gnukfreebsd")):
1321
            exts.append( Extension('ossaudiodev', ['ossaudiodev.c']) )
1322 1323
        else:
            missing.append('ossaudiodev')
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1324

1325 1326 1327 1328 1329
        if sys.platform == 'darwin':
            exts.append(
                       Extension('_gestalt', ['_gestalt.c'],
                       extra_link_args=['-framework', 'Carbon'])
                       )
1330 1331 1332 1333 1334 1335
            exts.append(
                       Extension('_scproxy', ['_scproxy.c'],
                       extra_link_args=[
                           '-framework', 'SystemConfiguration',
                           '-framework', 'CoreFoundation',
                        ]))
1336

1337 1338 1339 1340
        self.extensions.extend(exts)

        # Call the method for detecting whether _tkinter can be compiled
        self.detect_tkinter(inc_dirs, lib_dirs)
1341

1342 1343 1344 1345 1346
        if '_tkinter' not in [e.name for e in self.extensions]:
            missing.append('_tkinter')

        return missing

1347 1348 1349 1350 1351
    def detect_tkinter_darwin(self, inc_dirs, lib_dirs):
        # The _tkinter module, using frameworks. Since frameworks are quite
        # different the UNIX search logic is not sharable.
        from os.path import join, exists
        framework_dirs = [
Tim Peters's avatar
Tim Peters committed
1352
            '/Library/Frameworks',
1353
            '/System/Library/Frameworks/',
1354 1355 1356
            join(os.getenv('HOME'), '/Library/Frameworks')
        ]

1357 1358
        sysroot = macosx_sdk_root()

1359
        # Find the directory that contains the Tcl.framework and Tk.framework
1360 1361 1362
        # bundles.
        # XXX distutils should support -F!
        for F in framework_dirs:
Tim Peters's avatar
Tim Peters committed
1363
            # both Tcl.framework and Tk.framework should be present
1364 1365


1366
            for fw in 'Tcl', 'Tk':
1367 1368 1369 1370 1371 1372
                if is_macosx_sdk_path(F):
                    if not exists(join(sysroot, F[1:], fw + '.framework')):
                        break
                else:
                    if not exists(join(F, fw + '.framework')):
                        break
1373 1374 1375 1376 1377 1378 1379 1380
            else:
                # ok, F is now directory with both frameworks. Continure
                # building
                break
        else:
            # Tk and Tcl frameworks not found. Normal "unix" tkinter search
            # will now resume.
            return 0
Tim Peters's avatar
Tim Peters committed
1381

1382 1383
        # For 8.4a2, we must add -I options that point inside the Tcl and Tk
        # frameworks. In later release we should hopefully be able to pass
Tim Peters's avatar
Tim Peters committed
1384
        # the -F option to gcc, which specifies a framework lookup path.
1385 1386
        #
        include_dirs = [
Tim Peters's avatar
Tim Peters committed
1387
            join(F, fw + '.framework', H)
1388 1389
            for fw in ('Tcl', 'Tk')
            for H in ('Headers', 'Versions/Current/PrivateHeaders')
1390 1391
        ]

Tim Peters's avatar
Tim Peters committed
1392
        # For 8.4a2, the X11 headers are not included. Rather than include a
1393 1394 1395 1396 1397
        # complicated search, this is a hard-coded path. It could bail out
        # if X11 libs are not found...
        include_dirs.append('/usr/X11R6/include')
        frameworks = ['-framework', 'Tcl', '-framework', 'Tk']

1398 1399 1400 1401 1402
        # All existing framework builds of Tcl/Tk don't support 64-bit
        # architectures.
        cflags = sysconfig.get_config_vars('CFLAGS')[0]
        archs = re.findall('-arch\s+(\w+)', cflags)

1403 1404 1405 1406 1407 1408
        tmpfile = os.path.join(self.build_temp, 'tk.arch')
        if not os.path.exists(self.build_temp):
            os.makedirs(self.build_temp)

        # Note: cannot use os.popen or subprocess here, that
        # requires extensions that are not available here.
1409 1410 1411 1412
        if is_macosx_sdk_path(F):
            os.system("file %s/Tk.framework/Tk | grep 'for architecture' > %s"%(os.path.join(sysroot, F[1:]), tmpfile))
        else:
            os.system("file %s/Tk.framework/Tk | grep 'for architecture' > %s"%(F, tmpfile))
1413
        fp = open(tmpfile)
1414

1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425
        detected_archs = []
        for ln in fp:
            a = ln.split()[-1]
            if a in archs:
                detected_archs.append(ln.split()[-1])
        fp.close()
        os.unlink(tmpfile)

        for a in detected_archs:
            frameworks.append('-arch')
            frameworks.append(a)
1426

1427 1428 1429 1430
        ext = Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
                        define_macros=[('WITH_APPINIT', 1)],
                        include_dirs = include_dirs,
                        libraries = [],
1431
                        extra_compile_args = frameworks[2:],
1432 1433 1434 1435 1436
                        extra_link_args = frameworks,
                        )
        self.extensions.append(ext)
        return 1

Tim Peters's avatar
Tim Peters committed
1437

1438
    def detect_tkinter(self, inc_dirs, lib_dirs):
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1439
        # The _tkinter module.
1440

1441 1442 1443 1444
        # Rather than complicate the code below, detecting and building
        # AquaTk is a separate method. Only one Tkinter will be built on
        # Darwin - either AquaTk, if it is found, or X11 based Tk.
        platform = self.get_platform()
1445 1446
        if (platform == 'darwin' and
            self.detect_tkinter_darwin(inc_dirs, lib_dirs)):
Tim Peters's avatar
Tim Peters committed
1447
            return
1448

1449
        # Assume we haven't found any of the libraries or include files
1450 1451
        # The versions with dots are used on Unix, and the versions without
        # dots on Windows, for detection by cygwin.
1452
        tcllib = tklib = tcl_includes = tk_includes = None
1453 1454
        for version in ['8.6', '86', '8.5', '85', '8.4', '84', '8.3', '83',
                        '8.2', '82', '8.1', '81', '8.0', '80']:
1455
            tklib = self.compiler.find_library_file(lib_dirs,
1456
                                                        'tk' + version)
1457
            tcllib = self.compiler.find_library_file(lib_dirs,
1458
                                                         'tcl' + version)
1459
            if tklib and tcllib:
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1460 1461
                # Exit the loop when we've found the Tcl/Tk libraries
                break
1462

1463
        # Now check for the header files
1464
        if tklib and tcllib:
1465
            # Check for the include files on Debian and {Free,Open}BSD, where
1466
            # they're put in /usr/include/{tcl,tk}X.Y
1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479
            dotversion = version
            if '.' not in dotversion and "bsd" in sys.platform.lower():
                # OpenBSD and FreeBSD use Tcl/Tk library names like libtcl83.a,
                # but the include subdirs are named like .../include/tcl8.3.
                dotversion = dotversion[:-1] + '.' + dotversion[-1]
            tcl_include_sub = []
            tk_include_sub = []
            for dir in inc_dirs:
                tcl_include_sub += [dir + os.sep + "tcl" + dotversion]
                tk_include_sub += [dir + os.sep + "tk" + dotversion]
            tk_include_sub += tcl_include_sub
            tcl_includes = find_file('tcl.h', inc_dirs, tcl_include_sub)
            tk_includes = find_file('tk.h', inc_dirs, tk_include_sub)
1480

1481
        if (tcllib is None or tklib is None or
1482
            tcl_includes is None or tk_includes is None):
1483
            self.announce("INFO: Can't locate Tcl/Tk libs and/or headers", 2)
1484
            return
1485

1486 1487 1488 1489 1490 1491
        # OK... everything seems to be present for Tcl/Tk.

        include_dirs = [] ; libs = [] ; defs = [] ; added_lib_dirs = []
        for dir in tcl_includes + tk_includes:
            if dir not in include_dirs:
                include_dirs.append(dir)
1492

1493
        # Check for various platform-specific directories
1494
        if platform == 'sunos5':
1495 1496 1497 1498
            include_dirs.append('/usr/openwin/include')
            added_lib_dirs.append('/usr/openwin/lib')
        elif os.path.exists('/usr/X11R6/include'):
            include_dirs.append('/usr/X11R6/include')
1499
            added_lib_dirs.append('/usr/X11R6/lib64')
1500 1501 1502 1503 1504
            added_lib_dirs.append('/usr/X11R6/lib')
        elif os.path.exists('/usr/X11R5/include'):
            include_dirs.append('/usr/X11R5/include')
            added_lib_dirs.append('/usr/X11R5/lib')
        else:
1505
            # Assume default location for X11
1506 1507 1508
            include_dirs.append('/usr/X11/include')
            added_lib_dirs.append('/usr/X11/lib')

1509 1510 1511 1512 1513 1514
        # If Cygwin, then verify that X is installed before proceeding
        if platform == 'cygwin':
            x11_inc = find_file('X11/Xlib.h', [], include_dirs)
            if x11_inc is None:
                return

1515
        # Check for BLT extension
1516
        if self.compiler.find_library_file(lib_dirs + added_lib_dirs,
1517
                                               'BLT8.0'):
1518 1519
            defs.append( ('WITH_BLT', 1) )
            libs.append('BLT8.0')
1520
        elif self.compiler.find_library_file(lib_dirs + added_lib_dirs,
1521
                                                'BLT'):
1522 1523
            defs.append( ('WITH_BLT', 1) )
            libs.append('BLT')
1524 1525

        # Add the Tcl/Tk libraries
1526 1527
        libs.append('tk'+ version)
        libs.append('tcl'+ version)
1528

1529
        if platform in ['aix3', 'aix4']:
1530 1531
            libs.append('ld')

1532 1533 1534
        # Finally, link with the X11 libraries (not appropriate on cygwin)
        if platform != "cygwin":
            libs.append('X11')
1535 1536 1537 1538 1539 1540 1541 1542

        ext = Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
                        define_macros=[('WITH_APPINIT', 1)] + defs,
                        include_dirs = include_dirs,
                        libraries = libs,
                        library_dirs = added_lib_dirs,
                        )
        self.extensions.append(ext)
1543

1544 1545 1546 1547
##         # Uncomment these lines if you want to play with xxmodule.c
##         ext = Extension('xx', ['xxmodule.c'])
##         self.extensions.append(ext)

1548
        # XXX handle these, but how to detect?
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1549
        # *** Uncomment and edit for PIL (TkImaging) extension only:
1550
        #       -DWITH_PIL -I../Extensions/Imaging/libImaging  tkImaging.c \
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1551
        # *** Uncomment and edit for TOGL extension only:
1552
        #       -DWITH_TOGL togl.c \
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1553
        # *** Uncomment these for TOGL extension only:
1554
        #       -lGL -lGLU -lXext -lXmu \
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1555

1556 1557 1558
    def configure_ctypes_darwin(self, ext):
        # Darwin (OS X) uses preconfigured files, in
        # the Modules/_ctypes/libffi_osx directory.
1559
        srcdir = sysconfig.get_config_var('srcdir')
1560 1561 1562 1563
        ffi_srcdir = os.path.abspath(os.path.join(srcdir, 'Modules',
                                                  '_ctypes', 'libffi_osx'))
        sources = [os.path.join(ffi_srcdir, p)
                   for p in ['ffi.c',
1564
                             'x86/darwin64.S',
1565 1566 1567 1568 1569 1570 1571 1572 1573 1574
                             'x86/x86-darwin.S',
                             'x86/x86-ffi_darwin.c',
                             'x86/x86-ffi64.c',
                             'powerpc/ppc-darwin.S',
                             'powerpc/ppc-darwin_closure.S',
                             'powerpc/ppc-ffi_darwin.c',
                             'powerpc/ppc64-darwin_closure.S',
                             ]]

        # Add .S (preprocessed assembly) to C compiler source extensions.
1575
        self.compiler.src_extensions.append('.S')
1576 1577 1578 1579 1580 1581 1582

        include_dirs = [os.path.join(ffi_srcdir, 'include'),
                        os.path.join(ffi_srcdir, 'powerpc')]
        ext.include_dirs.extend(include_dirs)
        ext.sources.extend(sources)
        return True

1583 1584
    def configure_ctypes(self, ext):
        if not self.use_system_libffi:
1585 1586 1587
            if sys.platform == 'darwin':
                return self.configure_ctypes_darwin(ext)

1588
            srcdir = sysconfig.get_config_var('srcdir')
1589 1590 1591 1592 1593
            ffi_builddir = os.path.join(self.build_temp, 'libffi')
            ffi_srcdir = os.path.abspath(os.path.join(srcdir, 'Modules',
                                         '_ctypes', 'libffi'))
            ffi_configfile = os.path.join(ffi_builddir, 'fficonfig.py')

1594 1595 1596
            from distutils.dep_util import newer_group

            config_sources = [os.path.join(ffi_srcdir, fname)
1597 1598
                              for fname in os.listdir(ffi_srcdir)
                              if os.path.isfile(os.path.join(ffi_srcdir, fname))]
1599 1600
            if self.force or newer_group(config_sources,
                                         ffi_configfile):
1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611
                from distutils.dir_util import mkpath
                mkpath(ffi_builddir)
                config_args = []

                # Pass empty CFLAGS because we'll just append the resulting
                # CFLAGS to Python's; -g or -O2 is to be avoided.
                cmd = "cd %s && env CFLAGS='' '%s/configure' %s" \
                      % (ffi_builddir, ffi_srcdir, " ".join(config_args))

                res = os.system(cmd)
                if res or not os.path.exists(ffi_configfile):
1612
                    print("Failed to configure _ctypes module")
1613 1614 1615
                    return False

            fficonfig = {}
1616 1617
            with open(ffi_configfile) as f:
                exec(f.read(), globals(), fficonfig)
1618 1619

            # Add .S (preprocessed assembly) to C compiler source extensions.
1620
            self.compiler.src_extensions.append('.S')
1621 1622

            include_dirs = [os.path.join(ffi_builddir, 'include'),
1623 1624
                            ffi_builddir,
                            os.path.join(ffi_srcdir, 'src')]
1625 1626
            extra_compile_args = fficonfig['ffi_cflags'].split()

1627 1628
            ext.sources.extend(os.path.join(ffi_srcdir, f) for f in
                               fficonfig['ffi_sources'])
1629 1630 1631 1632 1633 1634 1635 1636
            ext.include_dirs.extend(include_dirs)
            ext.extra_compile_args.extend(extra_compile_args)
        return True

    def detect_ctypes(self, inc_dirs, lib_dirs):
        self.use_system_libffi = False
        include_dirs = []
        extra_compile_args = []
1637
        extra_link_args = []
1638 1639 1640 1641 1642
        sources = ['_ctypes/_ctypes.c',
                   '_ctypes/callbacks.c',
                   '_ctypes/callproc.c',
                   '_ctypes/stgdict.c',
                   '_ctypes/cfield.c',
1643
                   '_ctypes/malloc_closure.c']
1644 1645 1646 1647
        depends = ['_ctypes/ctypes.h']

        if sys.platform == 'darwin':
            sources.append('_ctypes/darwin/dlfcn_simple.c')
1648
            extra_compile_args.append('-DMACOSX')
1649 1650 1651 1652
            include_dirs.append('_ctypes/darwin')
# XXX Is this still needed?
##            extra_link_args.extend(['-read_only_relocs', 'warning'])

1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663
        elif sys.platform == 'sunos5':
            # XXX This shouldn't be necessary; it appears that some
            # of the assembler code is non-PIC (i.e. it has relocations
            # when it shouldn't. The proper fix would be to rewrite
            # the assembler code to be PIC.
            # This only works with GCC; the Sun compiler likely refuses
            # this option. If you want to compile ctypes with the Sun
            # compiler, please research a proper solution, instead of
            # finding some -z option for the Sun compiler.
            extra_link_args.append('-mimpure-text')

1664
        elif sys.platform.startswith('hp-ux'):
1665 1666
            extra_link_args.append('-fPIC')

1667 1668 1669
        ext = Extension('_ctypes',
                        include_dirs=include_dirs,
                        extra_compile_args=extra_compile_args,
1670
                        extra_link_args=extra_link_args,
1671
                        libraries=[],
1672 1673 1674 1675 1676 1677
                        sources=sources,
                        depends=depends)
        ext_test = Extension('_ctypes_test',
                             sources=['_ctypes/_ctypes_test.c'])
        self.extensions.extend([ext, ext_test])

1678 1679 1680
        if not '--with-system-ffi' in sysconfig.get_config_var("CONFIG_ARGS"):
            return

1681 1682 1683 1684 1685
        if sys.platform == 'darwin':
            # OS X 10.5 comes with libffi.dylib; the include files are
            # in /usr/include/ffi
            inc_dirs.append('/usr/include/ffi')

1686
        ffi_inc = [sysconfig.get_config_var("LIBFFI_INCLUDEDIR")]
1687
        if not ffi_inc or ffi_inc[0] == '':
1688
            ffi_inc = find_file('ffi.h', [], inc_dirs)
1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701
        if ffi_inc is not None:
            ffi_h = ffi_inc[0] + '/ffi.h'
            fp = open(ffi_h)
            while 1:
                line = fp.readline()
                if not line:
                    ffi_inc = None
                    break
                if line.startswith('#define LIBFFI_H'):
                    break
        ffi_lib = None
        if ffi_inc is not None:
            for lib_name in ('ffi_convenience', 'ffi_pic', 'ffi'):
1702
                if (self.compiler.find_library_file(lib_dirs, lib_name)):
1703 1704 1705 1706 1707 1708 1709 1710 1711
                    ffi_lib = lib_name
                    break

        if ffi_inc and ffi_lib:
            ext.include_dirs.extend(ffi_inc)
            ext.libraries.append(ffi_lib)
            self.use_system_libffi = True


1712 1713 1714 1715 1716 1717 1718
class PyBuildInstall(install):
    # Suppress the warning about installation into the lib_dynload
    # directory, which is not in sys.path when running Python during
    # installation:
    def initialize_options (self):
        install.initialize_options(self)
        self.warn_dir=0
1719

1720 1721 1722 1723 1724 1725 1726 1727 1728 1729
class PyBuildInstallLib(install_lib):
    # Do exactly what install_lib does but make sure correct access modes get
    # set on installed directories and files. All installed files with get
    # mode 644 unless they are a shared library in which case they will get
    # mode 755. All installed directories will get mode 755.

    so_ext = sysconfig.get_config_var("SO")

    def install(self):
        outfiles = install_lib.install(self)
1730 1731
        self.set_file_modes(outfiles, 0o644, 0o755)
        self.set_dir_modes(self.install_dir, 0o755)
1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746
        return outfiles

    def set_file_modes(self, files, defaultMode, sharedLibMode):
        if not self.is_chmod_supported(): return
        if not files: return

        for filename in files:
            if os.path.islink(filename): continue
            mode = defaultMode
            if filename.endswith(self.so_ext): mode = sharedLibMode
            log.info("changing mode of %s to %o", filename, mode)
            if not self.dry_run: os.chmod(filename, mode)

    def set_dir_modes(self, dirname, mode):
        if not self.is_chmod_supported(): return
1747 1748 1749 1750 1751
        for dirpath, dirnames, fnames in os.walk(dirname):
            if os.path.islink(dirpath):
                continue
            log.info("changing mode of %s to %o", dirpath, mode)
            if not self.dry_run: os.chmod(dirpath, mode)
1752 1753 1754 1755

    def is_chmod_supported(self):
        return hasattr(os, 'chmod')

Guido van Rossum's avatar
Guido van Rossum committed
1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783
SUMMARY = """
Python is an interpreted, interactive, object-oriented programming
language. It is often compared to Tcl, Perl, Scheme or Java.

Python combines remarkable power with very clear syntax. It has
modules, classes, exceptions, very high level dynamic data types, and
dynamic typing. There are interfaces to many system calls and
libraries, as well as to various windowing systems (X11, Motif, Tk,
Mac, MFC). New built-in modules are easily written in C or C++. Python
is also usable as an extension language for applications that need a
programmable interface.

The Python implementation is portable: it runs on many brands of UNIX,
on Windows, DOS, OS/2, Mac, Amiga... If your favorite system isn't
listed here, it may still be supported, if there's a C compiler for
it. Ask around on comp.lang.python -- or just try compiling Python
yourself.
"""

CLASSIFIERS = """
Development Status :: 6 - Mature
License :: OSI Approved :: Python Software Foundation License
Natural Language :: English
Programming Language :: C
Programming Language :: Python
Topic :: Software Development
"""

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1784
def main():
1785 1786 1787
    # turn off warnings when deprecated modules are imported
    import warnings
    warnings.filterwarnings("ignore",category=DeprecationWarning)
Guido van Rossum's avatar
Guido van Rossum committed
1788 1789 1790 1791 1792 1793 1794 1795 1796
    setup(# PyPI Metadata (PEP 301)
          name = "Python",
          version = sys.version.split()[0],
          url = "http://www.python.org/%s" % sys.version[:3],
          maintainer = "Guido van Rossum and the Python community",
          maintainer_email = "python-dev@python.org",
          description = "A high-level object-oriented programming language",
          long_description = SUMMARY.strip(),
          license = "PSF license",
1797
          classifiers = [x for x in CLASSIFIERS.split("\n") if x],
Guido van Rossum's avatar
Guido van Rossum committed
1798 1799 1800
          platforms = ["Many"],

          # Build info
1801 1802
          cmdclass = {'build_ext':PyBuildExt, 'install':PyBuildInstall,
                      'install_lib':PyBuildInstallLib},
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1803 1804
          # The struct module is defined here, because build_ext won't be
          # called unless there's at least one extension module defined.
1805
          ext_modules=[Extension('_struct', ['_struct.c'])],
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1806

1807 1808
          scripts = ["Tools/scripts/pydoc3", "Tools/scripts/idle3",
                     "Tools/scripts/2to3"]
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1809
        )
1810

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1811 1812 1813
# --install-platlib
if __name__ == '__main__':
    main()