setup.py 76.2 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 9

from distutils import log
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
10
from distutils import sysconfig
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

# 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
22 23 24 25
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."""
26
    if dir is not None and os.path.isdir(dir) and dir not in dirlist:
Michael W. Hudson's avatar
Michael W. Hudson committed
27 28
        dirlist.insert(0, dir)

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
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
    """
46
    return (path.startswith('/usr/') and not path.startswith('/usr/local')) or path.startswith('/System/')
47

48 49 50 51
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.
52

53 54 55 56 57 58
    '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.
    """
59 60 61 62 63
    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()
64 65 66 67

    # Check the standard locations
    for dir in std_dirs:
        f = os.path.join(dir, filename)
68 69 70 71

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

72 73 74 75 76
        if os.path.exists(f): return []

    # Check the additional directories
    for dir in paths:
        f = os.path.join(dir, filename)
77 78 79 80

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

81 82 83 84
        if os.path.exists(f):
            return [dir]

    # Not found anywhere
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
85 86
    return None

87
def find_library_file(compiler, libname, std_dirs, paths):
88 89 90
    result = compiler.find_library_file(std_dirs + paths, libname)
    if result is None:
        return None
91

92 93 94
    if sys.platform == 'darwin':
        sysroot = macosx_sdk_root()

95 96 97 98
    # 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
99
        p = p.rstrip(os.sep)
100 101 102 103 104

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

105 106
        if p == dirname:
            return [ ]
107

108 109 110 111
    # 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
112
        p = p.rstrip(os.sep)
113 114 115 116 117

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

118 119 120 121
        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
122

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
123 124 125 126 127
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)
128

Jack Jansen's avatar
Jack Jansen committed
129 130 131 132 133 134 135
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:
136
        log.info("WARNING: multiple copies of %s found"%module)
Jack Jansen's avatar
Jack Jansen committed
137
    return os.path.join(list[0], module)
138

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
139
class PyBuildExt(build_ext):
140

141 142 143 144
    def __init__(self, dist):
        build_ext.__init__(self, dist)
        self.failed = []

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
145 146 147
    def build_extensions(self):

        # Detect which modules should be compiled
148
        missing = self.detect_modules()
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
149 150

        # Remove modules that are present on the disabled list
151 152 153 154 155 156 157 158
        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
159

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

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

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

176
        # Python header files
177 178
        headers = [sysconfig.get_config_h_filename()]
        headers += glob(os.path.join(sysconfig.get_python_inc(), "*.h"))
179

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

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

196
        if platform != 'mac':
197 198
            # Parse Modules/Setup and Modules/Setup.local to figure out which
            # modules are turned on in the file.
199
            remove_modules = []
200 201 202 203 204 205 206 207
            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()
Tim Peters's avatar
Tim Peters committed
208

209 210 211
            for ext in self.extensions[:]:
                if ext.name in remove_modules:
                    self.extensions.remove(ext)
212

213 214 215 216 217 218 219 220
        # 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:
221 222
            (ccshared,cflags) = sysconfig.get_config_vars('CCSHARED','CFLAGS')
            args['compiler_so'] = compiler + ' ' + ccshared + ' ' + cflags
223 224
        self.compiler.set_executables(**args)

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
225 226
        build_ext.build_extensions(self)

227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
        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
242 243
            print("Python build finished, but the necessary bits to build "
                   "these modules were not found:")
244
            print_three_column(missing)
245 246 247
            print("To find the necessary bits, look in setup.py in"
                  " detect_modules() for the module's name.")
            print()
248 249 250 251 252 253

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

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

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

Marc-André Lemburg's avatar
Marc-André Lemburg committed
262 263
        try:
            build_ext.build_extension(self, ext)
264
        except (CCompilerError, DistutilsError) as why:
Marc-André Lemburg's avatar
Marc-André Lemburg committed
265 266
            self.announce('WARNING: building of extension "%s" failed: %s' %
                          (ext.name, sys.exc_info()[1]))
267
            self.failed.append(ext.name)
268
            return
269 270 271
        # 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:
272 273 274 275
            self.announce(
                'WARNING: skipping import check for Carbon-based "%s"' %
                ext.name)
            return
276 277

        if self.get_platform() == 'darwin' and (
Benjamin Peterson's avatar
Benjamin Peterson committed
278
                sys.maxsize > 2**32 and '-arch' in ext.extra_link_args):
279 280 281 282 283 284 285 286 287 288
            # 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

289 290 291 292 293 294
        # 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
295 296 297
        ext_filename = os.path.join(
            self.build_lib,
            self.get_ext_filename(self.get_ext_fullname(ext.name)))
298 299 300 301 302 303

        # 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()

304
        try:
Michael W. Hudson's avatar
Fix for  
Michael W. Hudson committed
305
            imp.load_dynamic(ext.name, ext_filename)
306
        except ImportError as why:
307
            self.failed.append(ext.name)
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
            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)')
328 329
        except:
            exc_type, why, tb = sys.exc_info()
330 331 332
            self.announce('*** WARNING: importing extension "%s" '
                          'failed with %s: %s' % (ext.name, exc_type, why),
                          level=3)
333
            self.failed.append(ext.name)
334

335
    def get_platform(self):
336
        # Get value of sys.platform
Skip Montanaro's avatar
Skip Montanaro committed
337
        for platform in ['cygwin', 'darwin', 'atheos', 'osf1']:
338 339 340
            if sys.platform.startswith(platform):
                return platform
        return sys.platform
341

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

347
        # Add paths specified in the environment variables LDFLAGS and
348
        # CPPFLAGS for header and library files.
349 350 351
        # 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
352
        # into configure and stored in the Makefile (issue found on OS X 10.3).
353
        for env_var, arg_name, dir_list in (
Skip Montanaro's avatar
Skip Montanaro committed
354
                ('LDFLAGS', '-R', self.compiler.runtime_library_dirs),
355 356
                ('LDFLAGS', '-L', self.compiler.library_dirs),
                ('CPPFLAGS', '-I', self.compiler.include_dirs)):
357
            env_val = sysconfig.get_config_var(env_var)
358
            if env_val:
359
                # To prevent optparse from raising an exception about any
Skip Montanaro's avatar
Skip Montanaro committed
360
                # options in env_val that it doesn't know about we strip out
361 362 363 364 365 366 367
                # 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.
368 369
                env_val = re.sub(r'(^|\s+)-(-|(?!%s))' % arg_name[1],
                                 ' ', env_val)
370
                parser = optparse.OptionParser()
371 372 373 374
                # Make sure that allowing args interspersed with options is
                # allowed
                parser.allow_interspersed_args = True
                parser.error = lambda msg: None
375 376
                parser.add_option(arg_name, dest="dirs", action="append")
                options = parser.parse_args(env_val.split())[0]
377
                if options.dirs:
Christian Heimes's avatar
Christian Heimes committed
378
                    for directory in reversed(options.dirs):
379
                        add_dir_to_list(dir_list, directory)
380

381 382 383 384 385 386
        if os.path.normpath(sys.prefix) != '/usr' \
                and not sysconfig.get_config_var('PYTHONFRAMEWORK'):
            # OSX note: Don't add LIBDIR and INCLUDEDIR to building a framework
            # (PYTHONFRAMEWORK is set) to avoid # linking problems when
            # building a framework with different architectures than
            # the one that is currently installed (issue #7473)
Michael W. Hudson's avatar
Fix for  
Michael W. Hudson committed
387 388 389 390
            add_dir_to_list(self.compiler.library_dirs,
                            sysconfig.get_config_var("LIBDIR"))
            add_dir_to_list(self.compiler.include_dirs,
                            sysconfig.get_config_var("INCLUDEDIR"))
391 392 393 394

        # 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.
395 396 397 398
        lib_dirs = self.compiler.library_dirs + [
            '/lib64', '/usr/lib64',
            '/lib', '/usr/lib',
            ]
399
        inc_dirs = self.compiler.include_dirs + ['/usr/include']
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
400
        exts = []
401
        missing = []
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
402

403 404 405
        config_h = sysconfig.get_config_h_filename()
        config_h_vars = sysconfig.parse_config_h(open(config_h))

406
        platform = self.get_platform()
407
        srcdir = sysconfig.get_config_var('srcdir')
408

Martin v. Löwis's avatar
Martin v. Löwis committed
409 410 411 412 413 414 415
        # Check for AtheOS which has libraries in non-standard locations
        if platform == 'atheos':
            lib_dirs += ['/system/libs', '/atheos/autolnk/lib']
            lib_dirs += os.getenv('LIBRARY_PATH', '').split(os.pathsep)
            inc_dirs += ['/system/include', '/atheos/autolnk/include']
            inc_dirs += os.getenv('C_INCLUDE_PATH', '').split(os.pathsep)

416 417
        # OSF/1 and Unixware have some stuff in /usr/ccs/lib (like -ldb)
        if platform in ['osf1', 'unixware7', 'openunix8']:
418 419
            lib_dirs += ['/usr/ccs/lib']

420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
        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:])

437 438
        # Check for MacOS X, which doesn't need libm.a at all
        math_libs = ['m']
Skip Montanaro's avatar
Skip Montanaro committed
439
        if platform in ['darwin', 'mac']:
440
            math_libs = []
441

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
442 443 444 445 446 447
        # XXX Omitted modules: gl, pure, dl, SGI-specific modules

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

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
449
        # Some modules that are normally always on:
450
        exts.append( Extension('_weakref', ['_weakref.c']) )
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
451 452 453 454

        # array objects
        exts.append( Extension('array', ['arraymodule.c']) )
        # complex math library functions
455 456
        exts.append( Extension('cmath', ['cmathmodule.c'],
                               libraries=math_libs) )
457

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

        # 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)
497 498 499 500 501
        libs = []
        if (config_h_vars.get('FLOCK_NEEDS_LIBBSD', False)):
            # May be necessary on AIX for flock function
            libs = ['bsd']
        exts.append( Extension('fcntl', ['fcntlmodule.c'], libraries=libs) )
502
        if platform not in ['mac']:
503
            # pwd(3)
Tim Peters's avatar
Tim Peters committed
504 505 506
            exts.append( Extension('pwd', ['pwdmodule.c']) )
            # grp(3)
            exts.append( Extension('grp', ['grpmodule.c']) )
507
            # spwd, shadow passwords
508 509
            if (config_h_vars.get('HAVE_GETSPNAM', False) or
                    config_h_vars.get('HAVE_GETSPENT', False)):
510
                exts.append( Extension('spwd', ['spwdmodule.c']) )
511 512 513 514 515
            else:
                missing.append('spwd')
        else:
            missing.extend(['pwd', 'grp', 'spwd'])

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
516 517 518 519 520 521 522
        # 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).
523
        if platform not in ['atheos', 'mac']:
Martin v. Löwis's avatar
Martin v. Löwis committed
524
            exts.append( Extension('mmap', ['mmapmodule.c']) )
525 526
        else:
            missing.append('mmap')
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
527

528
        # Lance Ellinghaus's syslog module
529
        if platform not in ['mac']:
Tim Peters's avatar
Tim Peters committed
530 531
            # syslog daemon interface
            exts.append( Extension('syslog', ['syslogmodule.c']) )
532 533
        else:
            missing.append('syslog')
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
534 535

        #
536 537
        # 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
538 539 540 541 542 543
        #

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

544
        # Operations on audio samples
Tim Peters's avatar
Tim Peters committed
545
        # According to #993173, this one should actually work fine on
546 547 548
        # 64-bit platforms.
        exts.append( Extension('audioop', ['audioop.c']) )

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
549
        # readline
550
        do_readline = self.compiler.find_library_file(lib_dirs, 'readline')
551 552 553 554 555 556 557 558
        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)
559 560 561 562 563 564 565 566 567 568 569 570 571
            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()
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
            os.unlink(tmpfile)
        # Issue 7384: If readline is already linked against curses,
        # use the same library for the readline and curses modules.
        # Disabled since applications relying on ncursesw might break.
        #
        # if 'curses' in readline_termcap_library:
        #    curses_library = readline_termcap_library
        # elif self.compiler.find_library_file(lib_dirs, 'ncursesw'):
        # (...)
        if self.compiler.find_library_file(lib_dirs, 'ncursesw'):
            curses_library = 'ncursesw'
        elif self.compiler.find_library_file(lib_dirs, 'ncurses'):
            curses_library = 'ncurses'
        elif self.compiler.find_library_file(lib_dirs, 'curses'):
            curses_library = 'curses'

588
        if platform == 'darwin': # and os.uname()[2] < '9.':
589 590 591
            # MacOSX 10.4 has a broken readline. Don't try to build
            # the readline module unless the user has installed a fixed
            # readline package
592 593
            # FIXME: The readline emulation on 10.5 is better, but the
            # readline module doesn't compile out of the box.
594
            if find_file('readline/rlconf.h', inc_dirs, []) is None:
595 596
                do_readline = False
        if do_readline:
597 598 599
            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
Fred Drake's avatar
Fred Drake committed
600
                # for dynamic libraries on the entire path.
601
                # This way a staticly linked custom readline gets picked up
602
                # before the (possibly broken) dynamic library in /usr/lib.
603 604 605 606
                readline_extra_link_args = ('-Wl,-search_paths_first',)
            else:
                readline_extra_link_args = ()

607
            readline_libs = ['readline']
608 609 610 611
            if readline_termcap_library:
                pass # Issue 7384: Already linked against curses or tinfo.
            elif curses_library:
                readline_libs.append(curses_library)
612
            elif self.compiler.find_library_file(lib_dirs +
613 614 615
                                               ['/usr/lib/termcap'],
                                               'termcap'):
                readline_libs.append('termcap')
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
616
            exts.append( Extension('readline', ['readline.c'],
Marc-André Lemburg's avatar
Marc-André Lemburg committed
617
                                   library_dirs=['/usr/lib/termcap'],
618
                                   extra_link_args=readline_extra_link_args,
619
                                   libraries=readline_libs) )
620 621 622
        else:
            missing.append('readline')

623
        if platform not in ['mac']:
624
            # crypt module.
Tim Peters's avatar
Tim Peters committed
625 626 627 628 629 630

            if self.compiler.find_library_file(lib_dirs, 'crypt'):
                libs = ['crypt']
            else:
                libs = []
            exts.append( Extension('crypt', ['cryptmodule.c'], libraries=libs) )
631 632
        else:
            missing.append('crypt')
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
633

Skip Montanaro's avatar
Skip Montanaro committed
634 635 636
        # CSV files
        exts.append( Extension('_csv', ['_csv.c']) )

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
637
        # socket(2)
638
        exts.append( Extension('_socket', ['socketmodule.c'],
639
                               depends = ['socketmodule.h']) )
640
        # Detect SSL support for the socket module (via _ssl)
641 642
        search_for_ssl_incs_in = [
                              '/usr/local/ssl/include',
643 644
                              '/usr/contrib/ssl/include/'
                             ]
645 646
        ssl_incs = find_file('openssl/ssl.h', inc_dirs,
                             search_for_ssl_incs_in
647
                             )
648 649 650 651 652
        if ssl_incs is not None:
            krb5_h = find_file('krb5.h', inc_dirs,
                               ['/usr/kerberos/include'])
            if krb5_h:
                ssl_incs += krb5_h
653
        ssl_libs = find_library_file(self.compiler, 'ssl',lib_dirs,
654 655 656
                                     ['/usr/local/ssl/lib',
                                      '/usr/contrib/ssl/lib/'
                                     ] )
657

658 659
        if (ssl_incs is not None and
            ssl_libs is not None):
660
            exts.append( Extension('_ssl', ['_ssl.c'],
661
                                   include_dirs = ssl_incs,
662
                                   library_dirs = ssl_libs,
663
                                   libraries = ['ssl', 'crypto'],
664
                                   depends = ['socketmodule.h']), )
665 666
        else:
            missing.append('_ssl')
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
667

668 669 670 671 672
        # 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]+)' )

673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
        # 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
689

690 691 692 693 694 695 696 697 698 699 700 701 702 703
        #print('openssl_ver = 0x%08x' % openssl_ver)

        if ssl_incs is not None and ssl_libs is not None:
            if openssl_ver >= 0x00907000:
                # The _hashlib module wraps optimized implementations
                # of hash functions from the OpenSSL library.
                exts.append( Extension('_hashlib', ['_hashopenssl.c'],
                                       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
704
        else:
705
            missing.append('_hashlib')
Gregory P. Smith's avatar
Gregory P. Smith committed
706

707
        if openssl_ver < 0x00908000:
708 709 710
            # OpenSSL doesn't do these until 0.9.8 so we'll bring our own hash
            exts.append( Extension('_sha256', ['sha256module.c']) )
            exts.append( Extension('_sha512', ['sha512module.c']) )
Gregory P. Smith's avatar
Gregory P. Smith committed
711

712
        if openssl_ver < 0x00907000:
713 714 715 716
            # no openssl at all, use our own md5 and sha1
            exts.append( Extension('_md5', ['md5module.c']) )
            exts.append( Extension('_sha1', ['sha1module.c']) )

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
717 718 719
        # 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
720 721
        # dependencies.  The Python module dbm/__init__.py provides an
        # implementation independent wrapper for these; dbm/dumb.py provides
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
722 723
        # similar functionality (but slower of course) implemented in Python.

724 725 726 727 728 729 730 731
        # 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.

732
        max_db_ver = (5, 1)
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
        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.
Benjamin Peterson's avatar
Benjamin Peterson committed
760 761 762 763 764 765 766 767 768 769 770
        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',
        ]
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
        # 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 = {}

809 810 811
        if sys.platform == 'darwin':
            sysroot = macosx_sdk_root()

812 813 814 815 816 817
        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")
818 819 820
                if sys.platform == 'darwin' and is_macosx_sdk_path(d):
                    f = os.path.join(sysroot, d[1:], "db.h")

821 822
                if db_setup_debug: print("db: looking for db.h in", f)
                if os.path.exists(f):
823 824
                    f = open(f, "rb").read()
                    m = re.search(br"#define\WDB_VERSION_MAJOR\W(\d+)", f)
825 826
                    if m:
                        db_major = int(m.group(1))
827
                        m = re.search(br"#define\WDB_VERSION_MINOR\W(\d+)", f)
828 829 830 831 832
                        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):
833
                            m = re.search(br"#define\WDB_VERSION_PATCH\W(\d+)", f)
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
                            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'),
                ]
867 868 869 870 871 872 873 874 875 876 877 878 879 880

                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)
881
                    db_dirs_to_check = tmp
882 883

                    db_dirs_to_check = tmp
884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910

                # 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
Benjamin Peterson's avatar
Benjamin Peterson committed
911

912
        # The sqlite interface
913
        sqlite_setup_debug = False   # verbose debug prints from this script?
914 915 916 917 918 919 920 921 922 923 924 925 926 927

        # 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])
928 929 930 931

        # 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.
932 933 934
        if sys.platform == 'darwin':
            sysroot = macosx_sdk_root()

935
        for d in inc_dirs + sqlite_inc_paths:
936
            f = os.path.join(d, "sqlite3.h")
937 938 939 940

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

941
            if os.path.exists(f):
942
                if sqlite_setup_debug: print("sqlite: found %s"%f)
943 944 945 946 947 948 949 950 951
                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!
952
                        if sqlite_setup_debug:
953
                            print("%s/sqlite3.h: version %s"%(d, sqlite_version))
954 955 956 957
                        sqlite_incdir = d
                        break
                    else:
                        if sqlite_setup_debug:
958 959
                            print("%s: version %d is too old, need >= %s"%(d,
                                        sqlite_version, MIN_SQLITE_VERSION))
960
                elif sqlite_setup_debug:
961
                    print("sqlite: %s had no SQLITE_VERSION"%(f,))
962 963 964 965 966 967 968 969 970 971

        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'),
            ]
            sqlite_libfile = self.compiler.find_library_file(
                                sqlite_dirs_to_check + lib_dirs, 'sqlite3')
Benjamin Peterson's avatar
Benjamin Peterson committed
972 973
            if sqlite_libfile:
                sqlite_libdir = [os.path.abspath(os.path.dirname(sqlite_libfile))]
974 975

        if sqlite_incdir and sqlite_libdir:
976
            sqlite_srcs = ['_sqlite/cache.c',
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991
                '_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\\"'))

992 993 994 995 996 997 998 999 1000 1001

            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 = ()
1002 1003 1004 1005 1006 1007 1008

            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,
1009
                                  extra_link_args=sqlite_extra_link_args,
1010
                                  libraries=["sqlite3",]))
1011 1012
        else:
            missing.append('_sqlite3')
1013

1014
        dbm_order = ['gdbm']
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1015
        # The standard Unix dbm module:
1016
        if platform not in ['cygwin']:
1017 1018
            config_args = [arg.strip("'")
                           for arg in sysconfig.get_config_var("CONFIG_ARGS").split()]
1019
            dbm_args = [arg for arg in config_args
1020 1021
                        if arg.startswith('--with-dbmliborder=')]
            if dbm_args:
1022
                dbm_order = [arg.split('=')[-1] for arg in dbm_args][-1].split(":")
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
            else:
                dbm_order = "ndbm:gdbm:bdb".split(":")
            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
                        if self.compiler.find_library_file(lib_dirs, 'ndbm'):
                            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":
                    if self.compiler.find_library_file(lib_dirs, 'gdbm'):
                        gdbm_libs = ['gdbm']
                        if self.compiler.find_library_file(lib_dirs, 'gdbm_compat'):
                            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
                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)
                        break
            if dbmext is not None:
                exts.append(dbmext)
1080
            else:
1081
                missing.append('_dbm')
1082

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1083
        # Anthony Baxter's gdbm module.  GNU dbm(3) will require -lgdbm:
1084 1085
        if ('gdbm' in dbm_order and
            self.compiler.find_library_file(lib_dirs, 'gdbm')):
1086
            exts.append( Extension('_gdbm', ['_gdbmmodule.c'],
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1087
                                   libraries = ['gdbm'] ) )
1088
        else:
1089
            missing.append('_gdbm')
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1090 1091

        # Unix-only modules
1092
        if platform not in ['mac', 'win32']:
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1093 1094 1095
            # Steen Lumholt's termios module
            exts.append( Extension('termios', ['termios.c']) )
            # Jeremy Hylton's rlimit interface
Tim Peters's avatar
Tim Peters committed
1096
            if platform not in ['atheos']:
Martin v. Löwis's avatar
Martin v. Löwis committed
1097
                exts.append( Extension('resource', ['resource.c']) )
1098 1099
            else:
                missing.append('resource')
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1100

1101
            # Sun yellow pages. Some systems have the functions in libc.
1102 1103
            if (platform not in ['cygwin', 'qnx6'] and
                find_file('rpcsvc/yp_prot.h', inc_dirs, []) is not None):
Benjamin Peterson's avatar
Benjamin Peterson committed
1104
                if (self.compiler.find_library_file(lib_dirs, 'nsl')):
1105 1106 1107 1108 1109
                    libs = ['nsl']
                else:
                    libs = []
                exts.append( Extension('nis', ['nismodule.c'],
                                       libraries = libs) )
1110 1111 1112 1113
            else:
                missing.append('nis')
        else:
            missing.extend(['nis', 'resource', 'termios'])
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1114

1115
        # Curses support, requiring the System V version of curses, often
1116
        # provided by the ncurses library.
1117
        panel_library = 'panel'
1118 1119 1120 1121 1122 1123
        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
1124 1125
            exts.append( Extension('_curses', ['_cursesmodule.c'],
                                   libraries = curses_libs) )
1126
        elif curses_library == 'curses' and platform != 'darwin':
1127 1128
                # OSX has an old Berkeley curses, not good enough for
                # the _curses module.
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1129 1130
            if (self.compiler.find_library_file(lib_dirs, 'terminfo')):
                curses_libs = ['curses', 'terminfo']
1131
            elif (self.compiler.find_library_file(lib_dirs, 'termcap')):
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1132
                curses_libs = ['curses', 'termcap']
1133 1134
            else:
                curses_libs = ['curses']
1135

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1136 1137
            exts.append( Extension('_curses', ['_cursesmodule.c'],
                                   libraries = curses_libs) )
1138 1139
        else:
            missing.append('_curses')
1140

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1141
        # If the curses module is enabled, check for the panel module
1142
        if (module_enabled(exts, '_curses') and
1143
            self.compiler.find_library_file(lib_dirs, panel_library)):
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1144
            exts.append( Extension('_curses_panel', ['_curses_panel.c'],
1145
                                   libraries = [panel_library] + curses_libs) )
1146 1147
        else:
            missing.append('_curses_panel')
1148

1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160
        # 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/
1161
        zlib_inc = find_file('zlib.h', [], inc_dirs)
1162
        have_zlib = False
1163 1164 1165
        if zlib_inc is not None:
            zlib_h = zlib_inc[0] + '/zlib.h'
            version = '"0.0.0"'
1166
            version_req = '"1.1.3"'
1167 1168 1169 1170 1171
            fp = open(zlib_h)
            while 1:
                line = fp.readline()
                if not line:
                    break
1172
                if line.startswith('#define ZLIB_VERSION'):
1173 1174 1175 1176
                    version = line.split()[2]
                    break
            if version >= version_req:
                if (self.compiler.find_library_file(lib_dirs, 'z')):
1177 1178 1179 1180
                    if sys.platform == "darwin":
                        zlib_extra_link_args = ('-Wl,-search_paths_first',)
                    else:
                        zlib_extra_link_args = ()
1181
                    exts.append( Extension('zlib', ['zlibmodule.c'],
1182 1183
                                           libraries = ['z'],
                                           extra_link_args = zlib_extra_link_args))
1184
                    have_zlib = True
1185 1186 1187 1188 1189 1190
                else:
                    missing.append('zlib')
            else:
                missing.append('zlib')
        else:
            missing.append('zlib')
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1191

1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206
        # 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) )

1207 1208
        # Gustavo Niemeyer's bz2 module.
        if (self.compiler.find_library_file(lib_dirs, 'bz2')):
1209 1210 1211 1212
            if sys.platform == "darwin":
                bz2_extra_link_args = ('-Wl,-search_paths_first',)
            else:
                bz2_extra_link_args = ()
1213
            exts.append( Extension('bz2', ['bz2module.c'],
1214 1215
                                   libraries = ['bz2'],
                                   extra_link_args = bz2_extra_link_args) )
1216 1217
        else:
            missing.append('bz2')
1218

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1219 1220
        # Interface to the Expat XML parser
        #
1221 1222 1223
        # 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
1224 1225
        # Prescod after a prototype by Jack Jansen.  The Expat source
        # is included in Modules/expat/.  Usage of a system
1226 1227 1228 1229
        # shared libexpat.so/expat.dll is not advised.
        #
        # More information on Expat can be found at www.libexpat.org.
        #
1230
        expatinc = os.path.join(os.getcwd(), srcdir, 'Modules', 'expat')
1231
        define_macros = [
1232 1233 1234
            ('HAVE_EXPAT_CONFIG_H', '1'),
        ]

1235 1236 1237 1238 1239 1240 1241 1242 1243
        exts.append(Extension('pyexpat',
                              define_macros = define_macros,
                              include_dirs = [expatinc],
                              sources = ['pyexpat.c',
                                         'expat/xmlparse.c',
                                         'expat/xmlrole.c',
                                         'expat/xmltok.c',
                                         ],
                              ))
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1244

1245 1246 1247
        # Fredrik Lundh's cElementTree module.  Note that this also
        # uses expat (via the CAPI hook in pyexpat).

1248
        if os.path.isfile(os.path.join(srcdir, 'Modules', '_elementtree.c')):
1249 1250 1251 1252 1253 1254
            define_macros.append(('USE_PYEXPAT_CAPI', None))
            exts.append(Extension('_elementtree',
                                  define_macros = define_macros,
                                  include_dirs = [expatinc],
                                  sources = ['_elementtree.c'],
                                  ))
1255 1256
        else:
            missing.append('_elementtree')
1257

1258
        # Hye-Shik Chang's CJKCodecs modules.
1259 1260 1261 1262 1263
        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]))
1264

1265
        # Thomas Heller's _ctypes module
1266
        self.detect_ctypes(inc_dirs, lib_dirs)
1267

1268 1269 1270 1271 1272 1273
        # Richard Oudkerk's multiprocessing module
        if platform == 'win32':             # Windows
            macros = dict()
            libraries = ['ws2_32']

        elif platform == 'darwin':          # Mac OSX
1274
            macros = dict()
1275 1276 1277
            libraries = []

        elif platform == 'cygwin':          # Cygwin
1278
            macros = dict()
1279
            libraries = []
Benjamin Peterson's avatar
Benjamin Peterson committed
1280

1281
        elif platform in ('freebsd4', 'freebsd5', 'freebsd6', 'freebsd7', 'freebsd8'):
Benjamin Peterson's avatar
Benjamin Peterson committed
1282 1283
            # FreeBSD's P1003.1b semaphore support is very experimental
            # and has many known problems. (as of June 2008)
1284
            macros = dict()
Benjamin Peterson's avatar
Benjamin Peterson committed
1285 1286
            libraries = []

1287
        elif platform.startswith('openbsd'):
1288
            macros = dict()
1289 1290
            libraries = []

1291
        elif platform.startswith('netbsd'):
1292
            macros = dict()
1293 1294
            libraries = []

1295
        else:                                   # Linux and other unices
1296
            macros = dict()
1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310
            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'
                                   ]
1311 1312
            if (sysconfig.get_config_var('HAVE_SEM_OPEN') and not
                sysconfig.get_config_var('POSIX_SEMAPHORES_NOT_ENABLED')):
1313 1314
                multiprocessing_srcs.append('_multiprocessing/semaphore.c')

Jesse Noller's avatar
Jesse Noller committed
1315 1316 1317 1318 1319 1320
        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')
1321
        # End multiprocessing
1322

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1323
        # Platform-specific libraries
Hye-Shik Chang's avatar
Hye-Shik Chang committed
1324
        if platform in ('linux2', 'freebsd4', 'freebsd5', 'freebsd6',
1325
                        'freebsd7', 'freebsd8'):
1326
            exts.append( Extension('ossaudiodev', ['ossaudiodev.c']) )
1327 1328
        else:
            missing.append('ossaudiodev')
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1329

1330 1331 1332 1333 1334
        if sys.platform == 'darwin':
            exts.append(
                       Extension('_gestalt', ['_gestalt.c'],
                       extra_link_args=['-framework', 'Carbon'])
                       )
1335 1336 1337 1338 1339 1340
            exts.append(
                       Extension('_scproxy', ['_scproxy.c'],
                       extra_link_args=[
                           '-framework', 'SystemConfiguration',
                           '-framework', 'CoreFoundation',
                        ]))
1341

1342 1343 1344 1345
        self.extensions.extend(exts)

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

1347 1348 1349 1350 1351
        if '_tkinter' not in [e.name for e in self.extensions]:
            missing.append('_tkinter')

        return missing

1352 1353 1354 1355 1356
    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
1357
            '/Library/Frameworks',
1358
            '/System/Library/Frameworks/',
1359 1360 1361
            join(os.getenv('HOME'), '/Library/Frameworks')
        ]

1362 1363
        sysroot = macosx_sdk_root()

1364
        # Find the directory that contains the Tcl.framework and Tk.framework
1365 1366 1367
        # bundles.
        # XXX distutils should support -F!
        for F in framework_dirs:
Tim Peters's avatar
Tim Peters committed
1368
            # both Tcl.framework and Tk.framework should be present
1369 1370


1371
            for fw in 'Tcl', 'Tk':
1372 1373 1374 1375 1376 1377
                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
1378 1379 1380 1381 1382 1383 1384 1385
            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
1386

1387 1388
        # 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
1389
        # the -F option to gcc, which specifies a framework lookup path.
1390 1391
        #
        include_dirs = [
Tim Peters's avatar
Tim Peters committed
1392
            join(F, fw + '.framework', H)
1393 1394
            for fw in ('Tcl', 'Tk')
            for H in ('Headers', 'Versions/Current/PrivateHeaders')
1395 1396
        ]

Tim Peters's avatar
Tim Peters committed
1397
        # For 8.4a2, the X11 headers are not included. Rather than include a
1398 1399 1400 1401 1402
        # 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']

1403 1404 1405 1406 1407
        # 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)

1408 1409 1410 1411 1412 1413
        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.
1414 1415 1416 1417
        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))
1418
        fp = open(tmpfile)
1419

1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430
        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)
1431

1432 1433 1434 1435
        ext = Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
                        define_macros=[('WITH_APPINIT', 1)],
                        include_dirs = include_dirs,
                        libraries = [],
1436
                        extra_compile_args = frameworks[2:],
1437 1438 1439 1440 1441
                        extra_link_args = frameworks,
                        )
        self.extensions.append(ext)
        return 1

Tim Peters's avatar
Tim Peters committed
1442

1443
    def detect_tkinter(self, inc_dirs, lib_dirs):
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1444
        # The _tkinter module.
1445

1446 1447 1448 1449
        # 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()
1450 1451
        if (platform == 'darwin' and
            self.detect_tkinter_darwin(inc_dirs, lib_dirs)):
Tim Peters's avatar
Tim Peters committed
1452
            return
1453

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

1466
        # Now check for the header files
1467
        if tklib and tcllib:
1468
            # Check for the include files on Debian and {Free,Open}BSD, where
1469
            # they're put in /usr/include/{tcl,tk}X.Y
1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
            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)
1483

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

1489 1490 1491 1492 1493 1494
        # 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)
1495

1496
        # Check for various platform-specific directories
1497
        if platform == 'sunos5':
1498 1499 1500 1501
            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')
1502
            added_lib_dirs.append('/usr/X11R6/lib64')
1503 1504 1505 1506 1507
            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:
1508
            # Assume default location for X11
1509 1510 1511
            include_dirs.append('/usr/X11/include')
            added_lib_dirs.append('/usr/X11/lib')

1512 1513 1514 1515 1516 1517
        # 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

1518
        # Check for BLT extension
Fred Drake's avatar
Fred Drake committed
1519 1520
        if self.compiler.find_library_file(lib_dirs + added_lib_dirs,
                                           'BLT8.0'):
1521 1522
            defs.append( ('WITH_BLT', 1) )
            libs.append('BLT8.0')
1523 1524 1525 1526
        elif self.compiler.find_library_file(lib_dirs + added_lib_dirs,
                                           'BLT'):
            defs.append( ('WITH_BLT', 1) )
            libs.append('BLT')
1527 1528

        # Add the Tcl/Tk libraries
1529 1530
        libs.append('tk'+ version)
        libs.append('tcl'+ version)
1531

1532
        if platform in ['aix3', 'aix4']:
1533 1534
            libs.append('ld')

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

        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)
1546

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

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

1559 1560 1561
    def configure_ctypes_darwin(self, ext):
        # Darwin (OS X) uses preconfigured files, in
        # the Modules/_ctypes/libffi_osx directory.
1562
        srcdir = sysconfig.get_config_var('srcdir')
1563 1564 1565 1566
        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',
1567
                             'x86/darwin64.S',
1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585
                             '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.
        self.compiler.src_extensions.append('.S')

        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

1586 1587
    def configure_ctypes(self, ext):
        if not self.use_system_libffi:
1588 1589 1590
            if sys.platform == 'darwin':
                return self.configure_ctypes_darwin(ext)

1591
            srcdir = sysconfig.get_config_var('srcdir')
1592 1593 1594 1595 1596
            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')

1597 1598 1599
            from distutils.dep_util import newer_group

            config_sources = [os.path.join(ffi_srcdir, fname)
1600 1601
                              for fname in os.listdir(ffi_srcdir)
                              if os.path.isfile(os.path.join(ffi_srcdir, fname))]
1602 1603
            if self.force or newer_group(config_sources,
                                         ffi_configfile):
1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614
                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):
1615
                    print("Failed to configure _ctypes module")
1616 1617 1618
                    return False

            fficonfig = {}
1619 1620 1621 1622 1623 1624
            fp = open(ffi_configfile)
            try:
                script = fp.read()
            finally:
                fp.close()
            exec(script, globals(), fficonfig)
1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642
            ffi_srcdir = os.path.join(fficonfig['ffi_srcdir'], 'src')

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

            include_dirs = [os.path.join(ffi_builddir, 'include'),
                            ffi_builddir, ffi_srcdir]
            extra_compile_args = fficonfig['ffi_cflags'].split()

            ext.sources.extend(fficonfig['ffi_sources'])
            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 = []
1643
        extra_link_args = []
1644 1645 1646 1647
        sources = ['_ctypes/_ctypes.c',
                   '_ctypes/callbacks.c',
                   '_ctypes/callproc.c',
                   '_ctypes/stgdict.c',
1648 1649
                   '_ctypes/cfield.c',
                   '_ctypes/malloc_closure.c']
1650 1651 1652 1653
        depends = ['_ctypes/ctypes.h']

        if sys.platform == 'darwin':
            sources.append('_ctypes/darwin/dlfcn_simple.c')
1654
            extra_compile_args.append('-DMACOSX')
1655 1656 1657 1658
            include_dirs.append('_ctypes/darwin')
# XXX Is this still needed?
##            extra_link_args.extend(['-read_only_relocs', 'warning'])

1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669
        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')

1670
        elif sys.platform.startswith('hp-ux'):
1671 1672
            extra_link_args.append('-fPIC')

1673 1674 1675
        ext = Extension('_ctypes',
                        include_dirs=include_dirs,
                        extra_compile_args=extra_compile_args,
1676
                        extra_link_args=extra_link_args,
1677
                        libraries=[],
1678 1679 1680 1681 1682 1683
                        sources=sources,
                        depends=depends)
        ext_test = Extension('_ctypes_test',
                             sources=['_ctypes/_ctypes_test.c'])
        self.extensions.extend([ext, ext_test])

1684 1685 1686
        if not '--with-system-ffi' in sysconfig.get_config_var("CONFIG_ARGS"):
            return

1687 1688 1689 1690 1691
        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')

1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715
        ffi_inc = find_file('ffi.h', [], inc_dirs)
        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'):
                if (self.compiler.find_library_file(lib_dirs, lib_name)):
                    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


1716 1717 1718 1719 1720 1721 1722
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
1723

1724 1725 1726 1727 1728 1729 1730 1731 1732 1733
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)
1734 1735
        self.set_file_modes(outfiles, 0o644, 0o755)
        self.set_dir_modes(self.install_dir, 0o755)
1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750
        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
1751 1752 1753 1754 1755
        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)
1756 1757 1758 1759

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

Guido van Rossum's avatar
Guido van Rossum committed
1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787
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
1788
def main():
1789 1790 1791
    # turn off warnings when deprecated modules are imported
    import warnings
    warnings.filterwarnings("ignore",category=DeprecationWarning)
Guido van Rossum's avatar
Guido van Rossum committed
1792 1793 1794 1795 1796 1797 1798 1799 1800
    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",
1801
          classifiers = [x for x in CLASSIFIERS.split("\n") if x],
Guido van Rossum's avatar
Guido van Rossum committed
1802 1803 1804
          platforms = ["Many"],

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

1811 1812
          scripts = ["Tools/scripts/pydoc3", "Tools/scripts/idle3",
                     "Tools/scripts/2to3"]
Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1813
        )
1814

Andrew M. Kuchling's avatar
Andrew M. Kuchling committed
1815 1816 1817
# --install-platlib
if __name__ == '__main__':
    main()