1# Autodetecting setup.py script for building the Python extensions
2#
3
4__version__ = "$Revision$"
5
6import sys, os, imp, re, optparse
7from glob import glob
8from platform import machine as platform_machine
9import sysconfig
10
11from distutils import log
12from distutils import text_file
13from distutils.errors import *
14from distutils.core import Extension, setup
15from distutils.command.build_ext import build_ext
16from distutils.command.install import install
17from distutils.command.install_lib import install_lib
18from distutils.spawn import find_executable
19
20cross_compiling = "_PYTHON_HOST_PLATFORM" in os.environ
21
22def get_platform():
23    # cross build
24    if "_PYTHON_HOST_PLATFORM" in os.environ:
25        return os.environ["_PYTHON_HOST_PLATFORM"]
26    # Get value of sys.platform
27    if sys.platform.startswith('osf1'):
28        return 'osf1'
29    return sys.platform
30host_platform = get_platform()
31
32# Were we compiled --with-pydebug or with #define Py_DEBUG?
33COMPILED_WITH_PYDEBUG = ('--with-pydebug' in sysconfig.get_config_var("CONFIG_ARGS"))
34
35# This global variable is used to hold the list of modules to be disabled.
36disabled_module_list = []
37
38def add_dir_to_list(dirlist, dir):
39    """Add the directory 'dir' to the list 'dirlist' (at the front) if
40    1) 'dir' is not already in 'dirlist'
41    2) 'dir' actually exists, and is a directory."""
42    if dir is not None and os.path.isdir(dir) and dir not in dirlist:
43        dirlist.insert(0, dir)
44
45def macosx_sdk_root():
46    """
47    Return the directory of the current OSX SDK,
48    or '/' if no SDK was specified.
49    """
50    cflags = sysconfig.get_config_var('CFLAGS')
51    m = re.search(r'-isysroot\s+(\S+)', cflags)
52    if m is None:
53        sysroot = '/'
54    else:
55        sysroot = m.group(1)
56    return sysroot
57
58def is_macosx_sdk_path(path):
59    """
60    Returns True if 'path' can be located in an OSX SDK
61    """
62    return ( (path.startswith('/usr/') and not path.startswith('/usr/local'))
63                or path.startswith('/System/')
64                or path.startswith('/Library/') )
65
66def find_file(filename, std_dirs, paths):
67    """Searches for the directory where a given file is located,
68    and returns a possibly-empty list of additional directories, or None
69    if the file couldn't be found at all.
70
71    'filename' is the name of a file, such as readline.h or libcrypto.a.
72    'std_dirs' is the list of standard system directories; if the
73        file is found in one of them, no additional directives are needed.
74    'paths' is a list of additional locations to check; if the file is
75        found in one of them, the resulting list will contain the directory.
76    """
77    if host_platform == 'darwin':
78        # Honor the MacOSX SDK setting when one was specified.
79        # An SDK is a directory with the same structure as a real
80        # system, but with only header files and libraries.
81        sysroot = macosx_sdk_root()
82
83    # Check the standard locations
84    for dir in std_dirs:
85        f = os.path.join(dir, filename)
86
87        if host_platform == 'darwin' and is_macosx_sdk_path(dir):
88            f = os.path.join(sysroot, dir[1:], filename)
89
90        if os.path.exists(f): return []
91
92    # Check the additional directories
93    for dir in paths:
94        f = os.path.join(dir, filename)
95
96        if host_platform == 'darwin' and is_macosx_sdk_path(dir):
97            f = os.path.join(sysroot, dir[1:], filename)
98
99        if os.path.exists(f):
100            return [dir]
101
102    # Not found anywhere
103    return None
104
105def find_library_file(compiler, libname, std_dirs, paths):
106    result = compiler.find_library_file(std_dirs + paths, libname)
107    if result is None:
108        return None
109
110    if host_platform == 'darwin':
111        sysroot = macosx_sdk_root()
112
113    # Check whether the found file is in one of the standard directories
114    dirname = os.path.dirname(result)
115    for p in std_dirs:
116        # Ensure path doesn't end with path separator
117        p = p.rstrip(os.sep)
118
119        if host_platform == 'darwin' and is_macosx_sdk_path(p):
120            # Note that, as of Xcode 7, Apple SDKs may contain textual stub
121            # libraries with .tbd extensions rather than the normal .dylib
122            # shared libraries installed in /.  The Apple compiler tool
123            # chain handles this transparently but it can cause problems
124            # for programs that are being built with an SDK and searching
125            # for specific libraries.  Distutils find_library_file() now
126            # knows to also search for and return .tbd files.  But callers
127            # of find_library_file need to keep in mind that the base filename
128            # of the returned SDK library file might have a different extension
129            # from that of the library file installed on the running system,
130            # for example:
131            #   /Applications/Xcode.app/Contents/Developer/Platforms/
132            #       MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/
133            #       usr/lib/libedit.tbd
134            # vs
135            #   /usr/lib/libedit.dylib
136            if os.path.join(sysroot, p[1:]) == dirname:
137                return [ ]
138
139        if p == dirname:
140            return [ ]
141
142    # Otherwise, it must have been in one of the additional directories,
143    # so we have to figure out which one.
144    for p in paths:
145        # Ensure path doesn't end with path separator
146        p = p.rstrip(os.sep)
147
148        if host_platform == 'darwin' and is_macosx_sdk_path(p):
149            if os.path.join(sysroot, p[1:]) == dirname:
150                return [ p ]
151
152        if p == dirname:
153            return [p]
154    else:
155        assert False, "Internal error: Path not found in std_dirs or paths"
156
157def module_enabled(extlist, modname):
158    """Returns whether the module 'modname' is present in the list
159    of extensions 'extlist'."""
160    extlist = [ext for ext in extlist if ext.name == modname]
161    return len(extlist)
162
163def find_module_file(module, dirlist):
164    """Find a module in a set of possible folders. If it is not found
165    return the unadorned filename"""
166    list = find_file(module, [], dirlist)
167    if not list:
168        return module
169    if len(list) > 1:
170        log.info("WARNING: multiple copies of %s found"%module)
171    return os.path.join(list[0], module)
172
173class PyBuildExt(build_ext):
174
175    def __init__(self, dist):
176        build_ext.__init__(self, dist)
177        self.failed = []
178
179    def build_extensions(self):
180
181        # Detect which modules should be compiled
182        missing = self.detect_modules()
183
184        # Remove modules that are present on the disabled list
185        extensions = [ext for ext in self.extensions
186                      if ext.name not in disabled_module_list]
187        # move ctypes to the end, it depends on other modules
188        ext_map = dict((ext.name, i) for i, ext in enumerate(extensions))
189        if "_ctypes" in ext_map:
190            ctypes = extensions.pop(ext_map["_ctypes"])
191            extensions.append(ctypes)
192        self.extensions = extensions
193
194        # Fix up the autodetected modules, prefixing all the source files
195        # with Modules/ and adding Python's include directory to the path.
196        (srcdir,) = sysconfig.get_config_vars('srcdir')
197        if not srcdir:
198            # Maybe running on Windows but not using CYGWIN?
199            raise ValueError("No source directory; cannot proceed.")
200        srcdir = os.path.abspath(srcdir)
201        moddirlist = [os.path.join(srcdir, 'Modules')]
202
203        # Platform-dependent module source and include directories
204        incdirlist = []
205
206        if host_platform == 'darwin' and ("--disable-toolbox-glue" not in
207            sysconfig.get_config_var("CONFIG_ARGS")):
208            # Mac OS X also includes some mac-specific modules
209            macmoddir = os.path.join(srcdir, 'Mac/Modules')
210            moddirlist.append(macmoddir)
211            incdirlist.append(os.path.join(srcdir, 'Mac/Include'))
212
213        # Fix up the paths for scripts, too
214        self.distribution.scripts = [os.path.join(srcdir, filename)
215                                     for filename in self.distribution.scripts]
216
217        # Python header files
218        headers = [sysconfig.get_config_h_filename()]
219        headers += glob(os.path.join(sysconfig.get_path('include'), "*.h"))
220        for ext in self.extensions[:]:
221            ext.sources = [ find_module_file(filename, moddirlist)
222                            for filename in ext.sources ]
223            if ext.depends is not None:
224                ext.depends = [find_module_file(filename, moddirlist)
225                               for filename in ext.depends]
226            else:
227                ext.depends = []
228            # re-compile extensions if a header file has been changed
229            ext.depends.extend(headers)
230
231            # platform specific include directories
232            ext.include_dirs.extend(incdirlist)
233
234            # If a module has already been built statically,
235            # don't build it here
236            if ext.name in sys.builtin_module_names:
237                self.extensions.remove(ext)
238
239        # Parse Modules/Setup and Modules/Setup.local to figure out which
240        # modules are turned on in the file.
241        remove_modules = []
242        for filename in ('Modules/Setup', 'Modules/Setup.local'):
243            input = text_file.TextFile(filename, join_lines=1)
244            while 1:
245                line = input.readline()
246                if not line: break
247                line = line.split()
248                remove_modules.append(line[0])
249            input.close()
250
251        for ext in self.extensions[:]:
252            if ext.name in remove_modules:
253                self.extensions.remove(ext)
254
255        # When you run "make CC=altcc" or something similar, you really want
256        # those environment variables passed into the setup.py phase.  Here's
257        # a small set of useful ones.
258        compiler = os.environ.get('CC')
259        args = {}
260        # unfortunately, distutils doesn't let us provide separate C and C++
261        # compilers
262        if compiler is not None:
263            (ccshared,cflags) = sysconfig.get_config_vars('CCSHARED','CFLAGS')
264            args['compiler_so'] = compiler + ' ' + ccshared + ' ' + cflags
265        self.compiler.set_executables(**args)
266
267        build_ext.build_extensions(self)
268
269        longest = 0
270        if self.extensions:
271            longest = max([len(e.name) for e in self.extensions])
272        if self.failed:
273            longest = max(longest, max([len(name) for name in self.failed]))
274
275        def print_three_column(lst):
276            lst.sort(key=str.lower)
277            # guarantee zip() doesn't drop anything
278            while len(lst) % 3:
279                lst.append("")
280            for e, f, g in zip(lst[::3], lst[1::3], lst[2::3]):
281                print "%-*s   %-*s   %-*s" % (longest, e, longest, f,
282                                              longest, g)
283
284        if missing:
285            print
286            print ("Python build finished, but the necessary bits to build "
287                   "these modules were not found:")
288            print_three_column(missing)
289            print ("To find the necessary bits, look in setup.py in"
290                   " detect_modules() for the module's name.")
291            print
292
293        if self.failed:
294            failed = self.failed[:]
295            print
296            print "Failed to build these modules:"
297            print_three_column(failed)
298            print
299
300    def build_extension(self, ext):
301
302        if ext.name == '_ctypes':
303            if not self.configure_ctypes(ext):
304                return
305
306        try:
307            build_ext.build_extension(self, ext)
308        except (CCompilerError, DistutilsError), why:
309            self.announce('WARNING: building of extension "%s" failed: %s' %
310                          (ext.name, sys.exc_info()[1]))
311            self.failed.append(ext.name)
312            return
313        # Workaround for Mac OS X: The Carbon-based modules cannot be
314        # reliably imported into a command-line Python
315        if 'Carbon' in ext.extra_link_args:
316            self.announce(
317                'WARNING: skipping import check for Carbon-based "%s"' %
318                ext.name)
319            return
320
321        if host_platform == 'darwin' and (
322                sys.maxint > 2**32 and '-arch' in ext.extra_link_args):
323            # Don't bother doing an import check when an extension was
324            # build with an explicit '-arch' flag on OSX. That's currently
325            # only used to build 32-bit only extensions in a 4-way
326            # universal build and loading 32-bit code into a 64-bit
327            # process will fail.
328            self.announce(
329                'WARNING: skipping import check for "%s"' %
330                ext.name)
331            return
332
333        # Workaround for Cygwin: Cygwin currently has fork issues when many
334        # modules have been imported
335        if host_platform == 'cygwin':
336            self.announce('WARNING: skipping import check for Cygwin-based "%s"'
337                % ext.name)
338            return
339        ext_filename = os.path.join(
340            self.build_lib,
341            self.get_ext_filename(self.get_ext_fullname(ext.name)))
342
343        # Don't try to load extensions for cross builds
344        if cross_compiling:
345            return
346
347        try:
348            imp.load_dynamic(ext.name, ext_filename)
349        except ImportError, why:
350            self.failed.append(ext.name)
351            self.announce('*** WARNING: renaming "%s" since importing it'
352                          ' failed: %s' % (ext.name, why), level=3)
353            assert not self.inplace
354            basename, tail = os.path.splitext(ext_filename)
355            newname = basename + "_failed" + tail
356            if os.path.exists(newname):
357                os.remove(newname)
358            os.rename(ext_filename, newname)
359
360            # XXX -- This relies on a Vile HACK in
361            # distutils.command.build_ext.build_extension().  The
362            # _built_objects attribute is stored there strictly for
363            # use here.
364            # If there is a failure, _built_objects may not be there,
365            # so catch the AttributeError and move on.
366            try:
367                for filename in self._built_objects:
368                    os.remove(filename)
369            except AttributeError:
370                self.announce('unable to remove files (ignored)')
371        except:
372            exc_type, why, tb = sys.exc_info()
373            self.announce('*** WARNING: importing extension "%s" '
374                          'failed with %s: %s' % (ext.name, exc_type, why),
375                          level=3)
376            self.failed.append(ext.name)
377
378    def add_multiarch_paths(self):
379        # Debian/Ubuntu multiarch support.
380        # https://wiki.ubuntu.com/MultiarchSpec
381        cc = sysconfig.get_config_var('CC')
382        tmpfile = os.path.join(self.build_temp, 'multiarch')
383        if not os.path.exists(self.build_temp):
384            os.makedirs(self.build_temp)
385        ret = os.system(
386            '%s -print-multiarch > %s 2> /dev/null' % (cc, tmpfile))
387        multiarch_path_component = ''
388        try:
389            if ret >> 8 == 0:
390                with open(tmpfile) as fp:
391                    multiarch_path_component = fp.readline().strip()
392        finally:
393            os.unlink(tmpfile)
394
395        if multiarch_path_component != '':
396            add_dir_to_list(self.compiler.library_dirs,
397                            '/usr/lib/' + multiarch_path_component)
398            add_dir_to_list(self.compiler.include_dirs,
399                            '/usr/include/' + multiarch_path_component)
400            return
401
402        if not find_executable('dpkg-architecture'):
403            return
404        opt = ''
405        if cross_compiling:
406            opt = '-t' + sysconfig.get_config_var('HOST_GNU_TYPE')
407        tmpfile = os.path.join(self.build_temp, 'multiarch')
408        if not os.path.exists(self.build_temp):
409            os.makedirs(self.build_temp)
410        ret = os.system(
411            'dpkg-architecture %s -qDEB_HOST_MULTIARCH > %s 2> /dev/null' %
412            (opt, tmpfile))
413        try:
414            if ret >> 8 == 0:
415                with open(tmpfile) as fp:
416                    multiarch_path_component = fp.readline().strip()
417                add_dir_to_list(self.compiler.library_dirs,
418                                '/usr/lib/' + multiarch_path_component)
419                add_dir_to_list(self.compiler.include_dirs,
420                                '/usr/include/' + multiarch_path_component)
421        finally:
422            os.unlink(tmpfile)
423
424    def add_gcc_paths(self):
425        gcc = sysconfig.get_config_var('CC')
426        tmpfile = os.path.join(self.build_temp, 'gccpaths')
427        if not os.path.exists(self.build_temp):
428            os.makedirs(self.build_temp)
429        ret = os.system('%s -E -v - </dev/null 2>%s 1>/dev/null' % (gcc, tmpfile))
430        is_gcc = False
431        in_incdirs = False
432        inc_dirs = []
433        lib_dirs = []
434        try:
435            if ret >> 8 == 0:
436                with open(tmpfile) as fp:
437                    for line in fp.readlines():
438                        if line.startswith("gcc version"):
439                            is_gcc = True
440                        elif line.startswith("#include <...>"):
441                            in_incdirs = True
442                        elif line.startswith("End of search list"):
443                            in_incdirs = False
444                        elif is_gcc and line.startswith("LIBRARY_PATH"):
445                            for d in line.strip().split("=")[1].split(":"):
446                                d = os.path.normpath(d)
447                                if '/gcc/' not in d:
448                                    add_dir_to_list(self.compiler.library_dirs,
449                                                    d)
450                        elif is_gcc and in_incdirs and '/gcc/' not in line:
451                            add_dir_to_list(self.compiler.include_dirs,
452                                            line.strip())
453        finally:
454            os.unlink(tmpfile)
455
456    def detect_modules(self):
457        # Ensure that /usr/local is always used
458        if not cross_compiling:
459            add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib')
460            add_dir_to_list(self.compiler.include_dirs, '/usr/local/include')
461        if cross_compiling:
462            self.add_gcc_paths()
463        self.add_multiarch_paths()
464
465        # Add paths specified in the environment variables LDFLAGS and
466        # CPPFLAGS for header and library files.
467        # We must get the values from the Makefile and not the environment
468        # directly since an inconsistently reproducible issue comes up where
469        # the environment variable is not set even though the value were passed
470        # into configure and stored in the Makefile (issue found on OS X 10.3).
471        for env_var, arg_name, dir_list in (
472                ('LDFLAGS', '-R', self.compiler.runtime_library_dirs),
473                ('LDFLAGS', '-L', self.compiler.library_dirs),
474                ('CPPFLAGS', '-I', self.compiler.include_dirs)):
475            env_val = sysconfig.get_config_var(env_var)
476            if env_val:
477                # To prevent optparse from raising an exception about any
478                # options in env_val that it doesn't know about we strip out
479                # all double dashes and any dashes followed by a character
480                # that is not for the option we are dealing with.
481                #
482                # Please note that order of the regex is important!  We must
483                # strip out double-dashes first so that we don't end up with
484                # substituting "--Long" to "-Long" and thus lead to "ong" being
485                # used for a library directory.
486                env_val = re.sub(r'(^|\s+)-(-|(?!%s))' % arg_name[1],
487                                 ' ', env_val)
488                parser = optparse.OptionParser()
489                # Make sure that allowing args interspersed with options is
490                # allowed
491                parser.allow_interspersed_args = True
492                parser.error = lambda msg: None
493                parser.add_option(arg_name, dest="dirs", action="append")
494                options = parser.parse_args(env_val.split())[0]
495                if options.dirs:
496                    for directory in reversed(options.dirs):
497                        add_dir_to_list(dir_list, directory)
498
499        if os.path.normpath(sys.prefix) != '/usr' \
500                and not sysconfig.get_config_var('PYTHONFRAMEWORK'):
501            # OSX note: Don't add LIBDIR and INCLUDEDIR to building a framework
502            # (PYTHONFRAMEWORK is set) to avoid # linking problems when
503            # building a framework with different architectures than
504            # the one that is currently installed (issue #7473)
505            add_dir_to_list(self.compiler.library_dirs,
506                            sysconfig.get_config_var("LIBDIR"))
507            add_dir_to_list(self.compiler.include_dirs,
508                            sysconfig.get_config_var("INCLUDEDIR"))
509
510        try:
511            have_unicode = unicode
512        except NameError:
513            have_unicode = 0
514
515        # lib_dirs and inc_dirs are used to search for files;
516        # if a file is found in one of those directories, it can
517        # be assumed that no additional -I,-L directives are needed.
518        inc_dirs = self.compiler.include_dirs[:]
519        lib_dirs = self.compiler.library_dirs[:]
520        if not cross_compiling:
521            for d in (
522                '/usr/include',
523                ):
524                add_dir_to_list(inc_dirs, d)
525            for d in (
526                '/lib64', '/usr/lib64',
527                '/lib', '/usr/lib',
528                ):
529                add_dir_to_list(lib_dirs, d)
530        exts = []
531        missing = []
532
533        config_h = sysconfig.get_config_h_filename()
534        config_h_vars = sysconfig.parse_config_h(open(config_h))
535
536        srcdir = sysconfig.get_config_var('srcdir')
537
538        # Check for AtheOS which has libraries in non-standard locations
539        if host_platform == 'atheos':
540            lib_dirs += ['/system/libs', '/atheos/autolnk/lib']
541            lib_dirs += os.getenv('LIBRARY_PATH', '').split(os.pathsep)
542            inc_dirs += ['/system/include', '/atheos/autolnk/include']
543            inc_dirs += os.getenv('C_INCLUDE_PATH', '').split(os.pathsep)
544
545        # OSF/1 and Unixware have some stuff in /usr/ccs/lib (like -ldb)
546        if host_platform in ['osf1', 'unixware7', 'openunix8']:
547            lib_dirs += ['/usr/ccs/lib']
548
549        # HP-UX11iv3 keeps files in lib/hpux folders.
550        if host_platform == 'hp-ux11':
551            lib_dirs += ['/usr/lib/hpux64', '/usr/lib/hpux32']
552
553        if host_platform == 'darwin':
554            # This should work on any unixy platform ;-)
555            # If the user has bothered specifying additional -I and -L flags
556            # in OPT and LDFLAGS we might as well use them here.
557            #   NOTE: using shlex.split would technically be more correct, but
558            # also gives a bootstrap problem. Let's hope nobody uses directories
559            # with whitespace in the name to store libraries.
560            cflags, ldflags = sysconfig.get_config_vars(
561                    'CFLAGS', 'LDFLAGS')
562            for item in cflags.split():
563                if item.startswith('-I'):
564                    inc_dirs.append(item[2:])
565
566            for item in ldflags.split():
567                if item.startswith('-L'):
568                    lib_dirs.append(item[2:])
569
570        # Check for MacOS X, which doesn't need libm.a at all
571        math_libs = ['m']
572        if host_platform in ['darwin', 'beos']:
573            math_libs = []
574
575        # XXX Omitted modules: gl, pure, dl, SGI-specific modules
576
577        #
578        # The following modules are all pretty straightforward, and compile
579        # on pretty much any POSIXish platform.
580        #
581
582        # Some modules that are normally always on:
583        #exts.append( Extension('_weakref', ['_weakref.c']) )
584
585        # array objects
586        exts.append( Extension('array', ['arraymodule.c']) )
587
588        shared_math = 'Modules/_math.o'
589        # complex math library functions
590        exts.append( Extension('cmath', ['cmathmodule.c'],
591                               extra_objects=[shared_math],
592                               depends=['_math.h', shared_math],
593                               libraries=math_libs) )
594        # math library functions, e.g. sin()
595        exts.append( Extension('math',  ['mathmodule.c'],
596                               extra_objects=[shared_math],
597                               depends=['_math.h', shared_math],
598                               libraries=math_libs) )
599        # fast string operations implemented in C
600        exts.append( Extension('strop', ['stropmodule.c']) )
601        # time operations and variables
602        exts.append( Extension('time', ['timemodule.c'],
603                               libraries=math_libs) )
604        exts.append( Extension('datetime', ['datetimemodule.c', 'timemodule.c'],
605                               libraries=math_libs) )
606        # fast iterator tools implemented in C
607        exts.append( Extension("itertools", ["itertoolsmodule.c"]) )
608        # code that will be builtins in the future, but conflict with the
609        #  current builtins
610        exts.append( Extension('future_builtins', ['future_builtins.c']) )
611        # random number generator implemented in C
612        exts.append( Extension("_random", ["_randommodule.c"]) )
613        # high-performance collections
614        exts.append( Extension("_collections", ["_collectionsmodule.c"]) )
615        # bisect
616        exts.append( Extension("_bisect", ["_bisectmodule.c"]) )
617        # heapq
618        exts.append( Extension("_heapq", ["_heapqmodule.c"]) )
619        # operator.add() and similar goodies
620        exts.append( Extension('operator', ['operator.c']) )
621        # Python 3.1 _io library
622        exts.append( Extension("_io",
623            ["_io/bufferedio.c", "_io/bytesio.c", "_io/fileio.c",
624             "_io/iobase.c", "_io/_iomodule.c", "_io/stringio.c", "_io/textio.c"],
625             depends=["_io/_iomodule.h"], include_dirs=["Modules/_io"]))
626        # _functools
627        exts.append( Extension("_functools", ["_functoolsmodule.c"]) )
628        # _json speedups
629        exts.append( Extension("_json", ["_json.c"]) )
630        # Python C API test module
631        exts.append( Extension('_testcapi', ['_testcapimodule.c'],
632                               depends=['testcapi_long.h']) )
633        # profilers (_lsprof is for cProfile.py)
634        exts.append( Extension('_hotshot', ['_hotshot.c']) )
635        exts.append( Extension('_lsprof', ['_lsprof.c', 'rotatingtree.c']) )
636        # static Unicode character database
637        if have_unicode:
638            exts.append( Extension('unicodedata', ['unicodedata.c']) )
639        else:
640            missing.append('unicodedata')
641        # access to ISO C locale support
642        data = open('pyconfig.h').read()
643        m = re.search(r"#s*define\s+WITH_LIBINTL\s+1\s*", data)
644        if m is not None:
645            locale_libs = ['intl']
646        else:
647            locale_libs = []
648        if host_platform == 'darwin':
649            locale_extra_link_args = ['-framework', 'CoreFoundation']
650        else:
651            locale_extra_link_args = []
652
653
654        exts.append( Extension('_locale', ['_localemodule.c'],
655                               libraries=locale_libs,
656                               extra_link_args=locale_extra_link_args) )
657
658        # Modules with some UNIX dependencies -- on by default:
659        # (If you have a really backward UNIX, select and socket may not be
660        # supported...)
661
662        # fcntl(2) and ioctl(2)
663        libs = []
664        if (config_h_vars.get('FLOCK_NEEDS_LIBBSD', False)):
665            # May be necessary on AIX for flock function
666            libs = ['bsd']
667        exts.append( Extension('fcntl', ['fcntlmodule.c'], libraries=libs) )
668        # pwd(3)
669        exts.append( Extension('pwd', ['pwdmodule.c']) )
670        # grp(3)
671        exts.append( Extension('grp', ['grpmodule.c']) )
672        # spwd, shadow passwords
673        if (config_h_vars.get('HAVE_GETSPNAM', False) or
674                config_h_vars.get('HAVE_GETSPENT', False)):
675            exts.append( Extension('spwd', ['spwdmodule.c']) )
676        else:
677            missing.append('spwd')
678
679        # select(2); not on ancient System V
680        exts.append( Extension('select', ['selectmodule.c']) )
681
682        # Fred Drake's interface to the Python parser
683        exts.append( Extension('parser', ['parsermodule.c']) )
684
685        # cStringIO and cPickle
686        exts.append( Extension('cStringIO', ['cStringIO.c']) )
687        exts.append( Extension('cPickle', ['cPickle.c']) )
688
689        # Memory-mapped files (also works on Win32).
690        if host_platform not in ['atheos']:
691            exts.append( Extension('mmap', ['mmapmodule.c']) )
692        else:
693            missing.append('mmap')
694
695        # Lance Ellinghaus's syslog module
696        # syslog daemon interface
697        exts.append( Extension('syslog', ['syslogmodule.c']) )
698
699        # George Neville-Neil's timing module:
700        # Deprecated in PEP 4 http://www.python.org/peps/pep-0004.html
701        # http://mail.python.org/pipermail/python-dev/2006-January/060023.html
702        #exts.append( Extension('timing', ['timingmodule.c']) )
703
704        #
705        # Here ends the simple stuff.  From here on, modules need certain
706        # libraries, are platform-specific, or present other surprises.
707        #
708
709        # Multimedia modules
710        # These don't work for 64-bit platforms!!!
711        # These represent audio samples or images as strings:
712
713        # Operations on audio samples
714        # According to #993173, this one should actually work fine on
715        # 64-bit platforms.
716        exts.append( Extension('audioop', ['audioop.c']) )
717
718        # Disabled on 64-bit platforms
719        if sys.maxsize != 9223372036854775807L:
720            # Operations on images
721            exts.append( Extension('imageop', ['imageop.c']) )
722        else:
723            missing.extend(['imageop'])
724
725        # readline
726        do_readline = self.compiler.find_library_file(lib_dirs, 'readline')
727        readline_termcap_library = ""
728        curses_library = ""
729        # Determine if readline is already linked against curses or tinfo.
730        if do_readline and find_executable('ldd'):
731            fp = os.popen("ldd %s" % do_readline)
732            ldd_output = fp.readlines()
733            ret = fp.close()
734            if ret is None or ret >> 8 == 0:
735                for ln in ldd_output:
736                    if 'curses' in ln:
737                        readline_termcap_library = re.sub(
738                            r'.*lib(n?cursesw?)\.so.*', r'\1', ln
739                        ).rstrip()
740                        break
741                    if 'tinfo' in ln: # termcap interface split out from ncurses
742                        readline_termcap_library = 'tinfo'
743                        break
744        # Issue 7384: If readline is already linked against curses,
745        # use the same library for the readline and curses modules.
746        if 'curses' in readline_termcap_library:
747            curses_library = readline_termcap_library
748        elif self.compiler.find_library_file(lib_dirs, 'ncursesw'):
749            curses_library = 'ncursesw'
750        elif self.compiler.find_library_file(lib_dirs, 'ncurses'):
751            curses_library = 'ncurses'
752        elif self.compiler.find_library_file(lib_dirs, 'curses'):
753            curses_library = 'curses'
754
755        if host_platform == 'darwin':
756            os_release = int(os.uname()[2].split('.')[0])
757            dep_target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
758            if (dep_target and
759                    (tuple(int(n) for n in dep_target.split('.')[0:2])
760                        < (10, 5) ) ):
761                os_release = 8
762            if os_release < 9:
763                # MacOSX 10.4 has a broken readline. Don't try to build
764                # the readline module unless the user has installed a fixed
765                # readline package
766                if find_file('readline/rlconf.h', inc_dirs, []) is None:
767                    do_readline = False
768        if do_readline:
769            if host_platform == 'darwin' and os_release < 9:
770                # In every directory on the search path search for a dynamic
771                # library and then a static library, instead of first looking
772                # for dynamic libraries on the entire path.
773                # This way a statically linked custom readline gets picked up
774                # before the (possibly broken) dynamic library in /usr/lib.
775                readline_extra_link_args = ('-Wl,-search_paths_first',)
776            else:
777                readline_extra_link_args = ()
778
779            readline_libs = ['readline']
780            if readline_termcap_library:
781                pass # Issue 7384: Already linked against curses or tinfo.
782            elif curses_library:
783                readline_libs.append(curses_library)
784            elif self.compiler.find_library_file(lib_dirs +
785                                                     ['/usr/lib/termcap'],
786                                                     'termcap'):
787                readline_libs.append('termcap')
788            exts.append( Extension('readline', ['readline.c'],
789                                   library_dirs=['/usr/lib/termcap'],
790                                   extra_link_args=readline_extra_link_args,
791                                   libraries=readline_libs) )
792        else:
793            missing.append('readline')
794
795        # crypt module.
796
797        if self.compiler.find_library_file(lib_dirs, 'crypt'):
798            libs = ['crypt']
799        else:
800            libs = []
801        exts.append( Extension('crypt', ['cryptmodule.c'], libraries=libs) )
802
803        # CSV files
804        exts.append( Extension('_csv', ['_csv.c']) )
805
806        # socket(2)
807        exts.append( Extension('_socket', ['socketmodule.c', 'timemodule.c'],
808                               depends=['socketmodule.h'],
809                               libraries=math_libs) )
810        # Detect SSL support for the socket module (via _ssl)
811        search_for_ssl_incs_in = [
812                              '/usr/local/ssl/include',
813                              '/usr/contrib/ssl/include/'
814                             ]
815        ssl_incs = find_file('openssl/ssl.h', inc_dirs,
816                             search_for_ssl_incs_in
817                             )
818        if ssl_incs is not None:
819            krb5_h = find_file('krb5.h', inc_dirs,
820                               ['/usr/kerberos/include'])
821            if krb5_h:
822                ssl_incs += krb5_h
823        ssl_libs = find_library_file(self.compiler, 'ssl',lib_dirs,
824                                     ['/usr/local/ssl/lib',
825                                      '/usr/contrib/ssl/lib/'
826                                     ] )
827
828        if (ssl_incs is not None and
829            ssl_libs is not None):
830            exts.append( Extension('_ssl', ['_ssl.c'],
831                                   include_dirs = ssl_incs,
832                                   library_dirs = ssl_libs,
833                                   libraries = ['ssl', 'crypto'],
834                                   depends = ['socketmodule.h']), )
835        else:
836            missing.append('_ssl')
837
838        # find out which version of OpenSSL we have
839        openssl_ver = 0
840        openssl_ver_re = re.compile(
841            '^\s*#\s*define\s+OPENSSL_VERSION_NUMBER\s+(0x[0-9a-fA-F]+)' )
842
843        # look for the openssl version header on the compiler search path.
844        opensslv_h = find_file('openssl/opensslv.h', [],
845                inc_dirs + search_for_ssl_incs_in)
846        if opensslv_h:
847            name = os.path.join(opensslv_h[0], 'openssl/opensslv.h')
848            if host_platform == 'darwin' and is_macosx_sdk_path(name):
849                name = os.path.join(macosx_sdk_root(), name[1:])
850            try:
851                incfile = open(name, 'r')
852                for line in incfile:
853                    m = openssl_ver_re.match(line)
854                    if m:
855                        openssl_ver = eval(m.group(1))
856            except IOError, msg:
857                print "IOError while reading opensshv.h:", msg
858                pass
859
860        min_openssl_ver = 0x00907000
861        have_any_openssl = ssl_incs is not None and ssl_libs is not None
862        have_usable_openssl = (have_any_openssl and
863                               openssl_ver >= min_openssl_ver)
864
865        if have_any_openssl:
866            if have_usable_openssl:
867                # The _hashlib module wraps optimized implementations
868                # of hash functions from the OpenSSL library.
869                exts.append( Extension('_hashlib', ['_hashopenssl.c'],
870                                       include_dirs = ssl_incs,
871                                       library_dirs = ssl_libs,
872                                       libraries = ['ssl', 'crypto']) )
873            else:
874                print ("warning: openssl 0x%08x is too old for _hashlib" %
875                       openssl_ver)
876                missing.append('_hashlib')
877        if COMPILED_WITH_PYDEBUG or not have_usable_openssl:
878            # The _sha module implements the SHA1 hash algorithm.
879            exts.append( Extension('_sha', ['shamodule.c']) )
880            # The _md5 module implements the RSA Data Security, Inc. MD5
881            # Message-Digest Algorithm, described in RFC 1321.  The
882            # necessary files md5.c and md5.h are included here.
883            exts.append( Extension('_md5',
884                            sources = ['md5module.c', 'md5.c'],
885                            depends = ['md5.h']) )
886
887        min_sha2_openssl_ver = 0x00908000
888        if COMPILED_WITH_PYDEBUG or openssl_ver < min_sha2_openssl_ver:
889            # OpenSSL doesn't do these until 0.9.8 so we'll bring our own hash
890            exts.append( Extension('_sha256', ['sha256module.c']) )
891            exts.append( Extension('_sha512', ['sha512module.c']) )
892
893        # Modules that provide persistent dictionary-like semantics.  You will
894        # probably want to arrange for at least one of them to be available on
895        # your machine, though none are defined by default because of library
896        # dependencies.  The Python module anydbm.py provides an
897        # implementation independent wrapper for these; dumbdbm.py provides
898        # similar functionality (but slower of course) implemented in Python.
899
900        # Sleepycat^WOracle Berkeley DB interface.
901        #  http://www.oracle.com/database/berkeley-db/db/index.html
902        #
903        # This requires the Sleepycat^WOracle DB code. The supported versions
904        # are set below.  Visit the URL above to download
905        # a release.  Most open source OSes come with one or more
906        # versions of BerkeleyDB already installed.
907
908        max_db_ver = (5, 3)
909        min_db_ver = (4, 3)
910        db_setup_debug = False   # verbose debug prints from this script?
911
912        def allow_db_ver(db_ver):
913            """Returns a boolean if the given BerkeleyDB version is acceptable.
914
915            Args:
916              db_ver: A tuple of the version to verify.
917            """
918            if not (min_db_ver <= db_ver <= max_db_ver):
919                return False
920            # Use this function to filter out known bad configurations.
921            if (4, 6) == db_ver[:2]:
922                # BerkeleyDB 4.6.x is not stable on many architectures.
923                arch = platform_machine()
924                if arch not in ('i386', 'i486', 'i586', 'i686',
925                                'x86_64', 'ia64'):
926                    return False
927            return True
928
929        def gen_db_minor_ver_nums(major):
930            if major == 5:
931                for x in range(max_db_ver[1]+1):
932                    if allow_db_ver((5, x)):
933                        yield x
934            elif major == 4:
935                for x in range(9):
936                    if allow_db_ver((4, x)):
937                        yield x
938            elif major == 3:
939                for x in (3,):
940                    if allow_db_ver((3, x)):
941                        yield x
942            else:
943                raise ValueError("unknown major BerkeleyDB version", major)
944
945        # construct a list of paths to look for the header file in on
946        # top of the normal inc_dirs.
947        db_inc_paths = [
948            '/usr/include/db4',
949            '/usr/local/include/db4',
950            '/opt/sfw/include/db4',
951            '/usr/include/db3',
952            '/usr/local/include/db3',
953            '/opt/sfw/include/db3',
954            # Fink defaults (http://fink.sourceforge.net/)
955            '/sw/include/db4',
956            '/sw/include/db3',
957        ]
958        # 4.x minor number specific paths
959        for x in gen_db_minor_ver_nums(4):
960            db_inc_paths.append('/usr/include/db4%d' % x)
961            db_inc_paths.append('/usr/include/db4.%d' % x)
962            db_inc_paths.append('/usr/local/BerkeleyDB.4.%d/include' % x)
963            db_inc_paths.append('/usr/local/include/db4%d' % x)
964            db_inc_paths.append('/pkg/db-4.%d/include' % x)
965            db_inc_paths.append('/opt/db-4.%d/include' % x)
966            # MacPorts default (http://www.macports.org/)
967            db_inc_paths.append('/opt/local/include/db4%d' % x)
968        # 3.x minor number specific paths
969        for x in gen_db_minor_ver_nums(3):
970            db_inc_paths.append('/usr/include/db3%d' % x)
971            db_inc_paths.append('/usr/local/BerkeleyDB.3.%d/include' % x)
972            db_inc_paths.append('/usr/local/include/db3%d' % x)
973            db_inc_paths.append('/pkg/db-3.%d/include' % x)
974            db_inc_paths.append('/opt/db-3.%d/include' % x)
975
976        if cross_compiling:
977            db_inc_paths = []
978
979        # Add some common subdirectories for Sleepycat DB to the list,
980        # based on the standard include directories. This way DB3/4 gets
981        # picked up when it is installed in a non-standard prefix and
982        # the user has added that prefix into inc_dirs.
983        std_variants = []
984        for dn in inc_dirs:
985            std_variants.append(os.path.join(dn, 'db3'))
986            std_variants.append(os.path.join(dn, 'db4'))
987            for x in gen_db_minor_ver_nums(4):
988                std_variants.append(os.path.join(dn, "db4%d"%x))
989                std_variants.append(os.path.join(dn, "db4.%d"%x))
990            for x in gen_db_minor_ver_nums(3):
991                std_variants.append(os.path.join(dn, "db3%d"%x))
992                std_variants.append(os.path.join(dn, "db3.%d"%x))
993
994        db_inc_paths = std_variants + db_inc_paths
995        db_inc_paths = [p for p in db_inc_paths if os.path.exists(p)]
996
997        db_ver_inc_map = {}
998
999        if host_platform == 'darwin':
1000            sysroot = macosx_sdk_root()
1001
1002        class db_found(Exception): pass
1003        try:
1004            # See whether there is a Sleepycat header in the standard
1005            # search path.
1006            for d in inc_dirs + db_inc_paths:
1007                f = os.path.join(d, "db.h")
1008
1009                if host_platform == 'darwin' and is_macosx_sdk_path(d):
1010                    f = os.path.join(sysroot, d[1:], "db.h")
1011
1012                if db_setup_debug: print "db: looking for db.h in", f
1013                if os.path.exists(f):
1014                    f = open(f).read()
1015                    m = re.search(r"#define\WDB_VERSION_MAJOR\W(\d+)", f)
1016                    if m:
1017                        db_major = int(m.group(1))
1018                        m = re.search(r"#define\WDB_VERSION_MINOR\W(\d+)", f)
1019                        db_minor = int(m.group(1))
1020                        db_ver = (db_major, db_minor)
1021
1022                        # Avoid 4.6 prior to 4.6.21 due to a BerkeleyDB bug
1023                        if db_ver == (4, 6):
1024                            m = re.search(r"#define\WDB_VERSION_PATCH\W(\d+)", f)
1025                            db_patch = int(m.group(1))
1026                            if db_patch < 21:
1027                                print "db.h:", db_ver, "patch", db_patch,
1028                                print "being ignored (4.6.x must be >= 4.6.21)"
1029                                continue
1030
1031                        if ( (db_ver not in db_ver_inc_map) and
1032                            allow_db_ver(db_ver) ):
1033                            # save the include directory with the db.h version
1034                            # (first occurrence only)
1035                            db_ver_inc_map[db_ver] = d
1036                            if db_setup_debug:
1037                                print "db.h: found", db_ver, "in", d
1038                        else:
1039                            # we already found a header for this library version
1040                            if db_setup_debug: print "db.h: ignoring", d
1041                    else:
1042                        # ignore this header, it didn't contain a version number
1043                        if db_setup_debug:
1044                            print "db.h: no version number version in", d
1045
1046            db_found_vers = db_ver_inc_map.keys()
1047            db_found_vers.sort()
1048
1049            while db_found_vers:
1050                db_ver = db_found_vers.pop()
1051                db_incdir = db_ver_inc_map[db_ver]
1052
1053                # check lib directories parallel to the location of the header
1054                db_dirs_to_check = [
1055                    db_incdir.replace("include", 'lib64'),
1056                    db_incdir.replace("include", 'lib'),
1057                ]
1058
1059                if host_platform != 'darwin':
1060                    db_dirs_to_check = filter(os.path.isdir, db_dirs_to_check)
1061
1062                else:
1063                    # Same as other branch, but takes OSX SDK into account
1064                    tmp = []
1065                    for dn in db_dirs_to_check:
1066                        if is_macosx_sdk_path(dn):
1067                            if os.path.isdir(os.path.join(sysroot, dn[1:])):
1068                                tmp.append(dn)
1069                        else:
1070                            if os.path.isdir(dn):
1071                                tmp.append(dn)
1072                    db_dirs_to_check = tmp
1073
1074                # Look for a version specific db-X.Y before an ambiguous dbX
1075                # XXX should we -ever- look for a dbX name?  Do any
1076                # systems really not name their library by version and
1077                # symlink to more general names?
1078                for dblib in (('db-%d.%d' % db_ver),
1079                              ('db%d%d' % db_ver),
1080                              ('db%d' % db_ver[0])):
1081                    dblib_file = self.compiler.find_library_file(
1082                                    db_dirs_to_check + lib_dirs, dblib )
1083                    if dblib_file:
1084                        dblib_dir = [ os.path.abspath(os.path.dirname(dblib_file)) ]
1085                        raise db_found
1086                    else:
1087                        if db_setup_debug: print "db lib: ", dblib, "not found"
1088
1089        except db_found:
1090            if db_setup_debug:
1091                print "bsddb using BerkeleyDB lib:", db_ver, dblib
1092                print "bsddb lib dir:", dblib_dir, " inc dir:", db_incdir
1093            db_incs = [db_incdir]
1094            dblibs = [dblib]
1095            # We add the runtime_library_dirs argument because the
1096            # BerkeleyDB lib we're linking against often isn't in the
1097            # system dynamic library search path.  This is usually
1098            # correct and most trouble free, but may cause problems in
1099            # some unusual system configurations (e.g. the directory
1100            # is on an NFS server that goes away).
1101            exts.append(Extension('_bsddb', ['_bsddb.c'],
1102                                  depends = ['bsddb.h'],
1103                                  library_dirs=dblib_dir,
1104                                  runtime_library_dirs=dblib_dir,
1105                                  include_dirs=db_incs,
1106                                  libraries=dblibs))
1107        else:
1108            if db_setup_debug: print "db: no appropriate library found"
1109            db_incs = None
1110            dblibs = []
1111            dblib_dir = None
1112            missing.append('_bsddb')
1113
1114        # The sqlite interface
1115        sqlite_setup_debug = False   # verbose debug prints from this script?
1116
1117        # We hunt for #define SQLITE_VERSION "n.n.n"
1118        # We need to find >= sqlite version 3.0.8
1119        sqlite_incdir = sqlite_libdir = None
1120        sqlite_inc_paths = [ '/usr/include',
1121                             '/usr/include/sqlite',
1122                             '/usr/include/sqlite3',
1123                             '/usr/local/include',
1124                             '/usr/local/include/sqlite',
1125                             '/usr/local/include/sqlite3',
1126                           ]
1127        if cross_compiling:
1128            sqlite_inc_paths = []
1129        MIN_SQLITE_VERSION_NUMBER = (3, 0, 8)
1130        MIN_SQLITE_VERSION = ".".join([str(x)
1131                                    for x in MIN_SQLITE_VERSION_NUMBER])
1132
1133        # Scan the default include directories before the SQLite specific
1134        # ones. This allows one to override the copy of sqlite on OSX,
1135        # where /usr/include contains an old version of sqlite.
1136        if host_platform == 'darwin':
1137            sysroot = macosx_sdk_root()
1138
1139        for d_ in inc_dirs + sqlite_inc_paths:
1140            d = d_
1141            if host_platform == 'darwin' and is_macosx_sdk_path(d):
1142                d = os.path.join(sysroot, d[1:])
1143
1144            f = os.path.join(d, "sqlite3.h")
1145            if os.path.exists(f):
1146                if sqlite_setup_debug: print "sqlite: found %s"%f
1147                incf = open(f).read()
1148                m = re.search(
1149                    r'\s*.*#\s*.*define\s.*SQLITE_VERSION\W*"([\d\.]*)"', incf)
1150                if m:
1151                    sqlite_version = m.group(1)
1152                    sqlite_version_tuple = tuple([int(x)
1153                                        for x in sqlite_version.split(".")])
1154                    if sqlite_version_tuple >= MIN_SQLITE_VERSION_NUMBER:
1155                        # we win!
1156                        if sqlite_setup_debug:
1157                            print "%s/sqlite3.h: version %s"%(d, sqlite_version)
1158                        sqlite_incdir = d
1159                        break
1160                    else:
1161                        if sqlite_setup_debug:
1162                            print "%s: version %d is too old, need >= %s"%(d,
1163                                        sqlite_version, MIN_SQLITE_VERSION)
1164                elif sqlite_setup_debug:
1165                    print "sqlite: %s had no SQLITE_VERSION"%(f,)
1166
1167        if sqlite_incdir:
1168            sqlite_dirs_to_check = [
1169                os.path.join(sqlite_incdir, '..', 'lib64'),
1170                os.path.join(sqlite_incdir, '..', 'lib'),
1171                os.path.join(sqlite_incdir, '..', '..', 'lib64'),
1172                os.path.join(sqlite_incdir, '..', '..', 'lib'),
1173            ]
1174            sqlite_libfile = self.compiler.find_library_file(
1175                                sqlite_dirs_to_check + lib_dirs, 'sqlite3')
1176            if sqlite_libfile:
1177                sqlite_libdir = [os.path.abspath(os.path.dirname(sqlite_libfile))]
1178
1179        if sqlite_incdir and sqlite_libdir:
1180            sqlite_srcs = ['_sqlite/cache.c',
1181                '_sqlite/connection.c',
1182                '_sqlite/cursor.c',
1183                '_sqlite/microprotocols.c',
1184                '_sqlite/module.c',
1185                '_sqlite/prepare_protocol.c',
1186                '_sqlite/row.c',
1187                '_sqlite/statement.c',
1188                '_sqlite/util.c', ]
1189
1190            sqlite_defines = []
1191            if host_platform != "win32":
1192                sqlite_defines.append(('MODULE_NAME', '"sqlite3"'))
1193            else:
1194                sqlite_defines.append(('MODULE_NAME', '\\"sqlite3\\"'))
1195
1196            # Comment this out if you want the sqlite3 module to be able to load extensions.
1197            sqlite_defines.append(("SQLITE_OMIT_LOAD_EXTENSION", "1"))
1198
1199            if host_platform == 'darwin':
1200                # In every directory on the search path search for a dynamic
1201                # library and then a static library, instead of first looking
1202                # for dynamic libraries on the entire path.
1203                # This way a statically linked custom sqlite gets picked up
1204                # before the dynamic library in /usr/lib.
1205                sqlite_extra_link_args = ('-Wl,-search_paths_first',)
1206            else:
1207                sqlite_extra_link_args = ()
1208
1209            exts.append(Extension('_sqlite3', sqlite_srcs,
1210                                  define_macros=sqlite_defines,
1211                                  include_dirs=["Modules/_sqlite",
1212                                                sqlite_incdir],
1213                                  library_dirs=sqlite_libdir,
1214                                  extra_link_args=sqlite_extra_link_args,
1215                                  libraries=["sqlite3",]))
1216        else:
1217            missing.append('_sqlite3')
1218
1219        # Look for Berkeley db 1.85.   Note that it is built as a different
1220        # module name so it can be included even when later versions are
1221        # available.  A very restrictive search is performed to avoid
1222        # accidentally building this module with a later version of the
1223        # underlying db library.  May BSD-ish Unixes incorporate db 1.85
1224        # symbols into libc and place the include file in /usr/include.
1225        #
1226        # If the better bsddb library can be built (db_incs is defined)
1227        # we do not build this one.  Otherwise this build will pick up
1228        # the more recent berkeleydb's db.h file first in the include path
1229        # when attempting to compile and it will fail.
1230        f = "/usr/include/db.h"
1231
1232        if host_platform == 'darwin':
1233            if is_macosx_sdk_path(f):
1234                sysroot = macosx_sdk_root()
1235                f = os.path.join(sysroot, f[1:])
1236
1237        if os.path.exists(f) and not db_incs:
1238            data = open(f).read()
1239            m = re.search(r"#s*define\s+HASHVERSION\s+2\s*", data)
1240            if m is not None:
1241                # bingo - old version used hash file format version 2
1242                ### XXX this should be fixed to not be platform-dependent
1243                ### but I don't have direct access to an osf1 platform and
1244                ### seemed to be muffing the search somehow
1245                libraries = host_platform == "osf1" and ['db'] or None
1246                if libraries is not None:
1247                    exts.append(Extension('bsddb185', ['bsddbmodule.c'],
1248                                          libraries=libraries))
1249                else:
1250                    exts.append(Extension('bsddb185', ['bsddbmodule.c']))
1251            else:
1252                missing.append('bsddb185')
1253        else:
1254            missing.append('bsddb185')
1255
1256        dbm_order = ['gdbm']
1257        # The standard Unix dbm module:
1258        if host_platform not in ['cygwin']:
1259            config_args = [arg.strip("'")
1260                           for arg in sysconfig.get_config_var("CONFIG_ARGS").split()]
1261            dbm_args = [arg for arg in config_args
1262                        if arg.startswith('--with-dbmliborder=')]
1263            if dbm_args:
1264                dbm_order = [arg.split('=')[-1] for arg in dbm_args][-1].split(":")
1265            else:
1266                dbm_order = "ndbm:gdbm:bdb".split(":")
1267            dbmext = None
1268            for cand in dbm_order:
1269                if cand == "ndbm":
1270                    if find_file("ndbm.h", inc_dirs, []) is not None:
1271                        # Some systems have -lndbm, others have -lgdbm_compat,
1272                        # others don't have either
1273                        if self.compiler.find_library_file(lib_dirs,
1274                                                               'ndbm'):
1275                            ndbm_libs = ['ndbm']
1276                        elif self.compiler.find_library_file(lib_dirs,
1277                                                             'gdbm_compat'):
1278                            ndbm_libs = ['gdbm_compat']
1279                        else:
1280                            ndbm_libs = []
1281                        print "building dbm using ndbm"
1282                        dbmext = Extension('dbm', ['dbmmodule.c'],
1283                                           define_macros=[
1284                                               ('HAVE_NDBM_H',None),
1285                                               ],
1286                                           libraries=ndbm_libs)
1287                        break
1288
1289                elif cand == "gdbm":
1290                    if self.compiler.find_library_file(lib_dirs, 'gdbm'):
1291                        gdbm_libs = ['gdbm']
1292                        if self.compiler.find_library_file(lib_dirs,
1293                                                               'gdbm_compat'):
1294                            gdbm_libs.append('gdbm_compat')
1295                        if find_file("gdbm/ndbm.h", inc_dirs, []) is not None:
1296                            print "building dbm using gdbm"
1297                            dbmext = Extension(
1298                                'dbm', ['dbmmodule.c'],
1299                                define_macros=[
1300                                    ('HAVE_GDBM_NDBM_H', None),
1301                                    ],
1302                                libraries = gdbm_libs)
1303                            break
1304                        if find_file("gdbm-ndbm.h", inc_dirs, []) is not None:
1305                            print "building dbm using gdbm"
1306                            dbmext = Extension(
1307                                'dbm', ['dbmmodule.c'],
1308                                define_macros=[
1309                                    ('HAVE_GDBM_DASH_NDBM_H', None),
1310                                    ],
1311                                libraries = gdbm_libs)
1312                            break
1313                elif cand == "bdb":
1314                    if db_incs is not None:
1315                        print "building dbm using bdb"
1316                        dbmext = Extension('dbm', ['dbmmodule.c'],
1317                                           library_dirs=dblib_dir,
1318                                           runtime_library_dirs=dblib_dir,
1319                                           include_dirs=db_incs,
1320                                           define_macros=[
1321                                               ('HAVE_BERKDB_H', None),
1322                                               ('DB_DBM_HSEARCH', None),
1323                                               ],
1324                                           libraries=dblibs)
1325                        break
1326            if dbmext is not None:
1327                exts.append(dbmext)
1328            else:
1329                missing.append('dbm')
1330
1331        # Anthony Baxter's gdbm module.  GNU dbm(3) will require -lgdbm:
1332        if ('gdbm' in dbm_order and
1333            self.compiler.find_library_file(lib_dirs, 'gdbm')):
1334            exts.append( Extension('gdbm', ['gdbmmodule.c'],
1335                                   libraries = ['gdbm'] ) )
1336        else:
1337            missing.append('gdbm')
1338
1339        # Unix-only modules
1340        if host_platform not in ['win32']:
1341            # Steen Lumholt's termios module
1342            exts.append( Extension('termios', ['termios.c']) )
1343            # Jeremy Hylton's rlimit interface
1344            if host_platform not in ['atheos']:
1345                exts.append( Extension('resource', ['resource.c']) )
1346            else:
1347                missing.append('resource')
1348
1349            nis = self._detect_nis(inc_dirs, lib_dirs)
1350            if nis is not None:
1351                exts.append(nis)
1352            else:
1353                missing.append('nis')
1354
1355        # Curses support, requiring the System V version of curses, often
1356        # provided by the ncurses library.
1357        panel_library = 'panel'
1358        curses_incs = None
1359        if curses_library.startswith('ncurses'):
1360            if curses_library == 'ncursesw':
1361                # Bug 1464056: If _curses.so links with ncursesw,
1362                # _curses_panel.so must link with panelw.
1363                panel_library = 'panelw'
1364            curses_libs = [curses_library]
1365            curses_incs = find_file('curses.h', inc_dirs,
1366                                    [os.path.join(d, 'ncursesw') for d in inc_dirs])
1367            exts.append( Extension('_curses', ['_cursesmodule.c'],
1368                                   include_dirs = curses_incs,
1369                                   libraries = curses_libs) )
1370        elif curses_library == 'curses' and host_platform != 'darwin':
1371                # OSX has an old Berkeley curses, not good enough for
1372                # the _curses module.
1373            if (self.compiler.find_library_file(lib_dirs, 'terminfo')):
1374                curses_libs = ['curses', 'terminfo']
1375            elif (self.compiler.find_library_file(lib_dirs, 'termcap')):
1376                curses_libs = ['curses', 'termcap']
1377            else:
1378                curses_libs = ['curses']
1379
1380            exts.append( Extension('_curses', ['_cursesmodule.c'],
1381                                   libraries = curses_libs) )
1382        else:
1383            missing.append('_curses')
1384
1385        # If the curses module is enabled, check for the panel module
1386        if (module_enabled(exts, '_curses') and
1387            self.compiler.find_library_file(lib_dirs, panel_library)):
1388            exts.append( Extension('_curses_panel', ['_curses_panel.c'],
1389                                   include_dirs = curses_incs,
1390                                   libraries = [panel_library] + curses_libs) )
1391        else:
1392            missing.append('_curses_panel')
1393
1394        # Andrew Kuchling's zlib module.  Note that some versions of zlib
1395        # 1.1.3 have security problems.  See CERT Advisory CA-2002-07:
1396        # http://www.cert.org/advisories/CA-2002-07.html
1397        #
1398        # zlib 1.1.4 is fixed, but at least one vendor (RedHat) has decided to
1399        # patch its zlib 1.1.3 package instead of upgrading to 1.1.4.  For
1400        # now, we still accept 1.1.3, because we think it's difficult to
1401        # exploit this in Python, and we'd rather make it RedHat's problem
1402        # than our problem <wink>.
1403        #
1404        # You can upgrade zlib to version 1.1.4 yourself by going to
1405        # http://www.gzip.org/zlib/
1406        zlib_inc = find_file('zlib.h', [], inc_dirs)
1407        have_zlib = False
1408        if zlib_inc is not None:
1409            zlib_h = zlib_inc[0] + '/zlib.h'
1410            version = '"0.0.0"'
1411            version_req = '"1.1.3"'
1412            if host_platform == 'darwin' and is_macosx_sdk_path(zlib_h):
1413                zlib_h = os.path.join(macosx_sdk_root(), zlib_h[1:])
1414            fp = open(zlib_h)
1415            while 1:
1416                line = fp.readline()
1417                if not line:
1418                    break
1419                if line.startswith('#define ZLIB_VERSION'):
1420                    version = line.split()[2]
1421                    break
1422            if version >= version_req:
1423                if (self.compiler.find_library_file(lib_dirs, 'z')):
1424                    if host_platform == "darwin":
1425                        zlib_extra_link_args = ('-Wl,-search_paths_first',)
1426                    else:
1427                        zlib_extra_link_args = ()
1428                    exts.append( Extension('zlib', ['zlibmodule.c'],
1429                                           libraries = ['z'],
1430                                           extra_link_args = zlib_extra_link_args))
1431                    have_zlib = True
1432                else:
1433                    missing.append('zlib')
1434            else:
1435                missing.append('zlib')
1436        else:
1437            missing.append('zlib')
1438
1439        # Helper module for various ascii-encoders.  Uses zlib for an optimized
1440        # crc32 if we have it.  Otherwise binascii uses its own.
1441        if have_zlib:
1442            extra_compile_args = ['-DUSE_ZLIB_CRC32']
1443            libraries = ['z']
1444            extra_link_args = zlib_extra_link_args
1445        else:
1446            extra_compile_args = []
1447            libraries = []
1448            extra_link_args = []
1449        exts.append( Extension('binascii', ['binascii.c'],
1450                               extra_compile_args = extra_compile_args,
1451                               libraries = libraries,
1452                               extra_link_args = extra_link_args) )
1453
1454        # Gustavo Niemeyer's bz2 module.
1455        if (self.compiler.find_library_file(lib_dirs, 'bz2')):
1456            if host_platform == "darwin":
1457                bz2_extra_link_args = ('-Wl,-search_paths_first',)
1458            else:
1459                bz2_extra_link_args = ()
1460            exts.append( Extension('bz2', ['bz2module.c'],
1461                                   libraries = ['bz2'],
1462                                   extra_link_args = bz2_extra_link_args) )
1463        else:
1464            missing.append('bz2')
1465
1466        # Interface to the Expat XML parser
1467        #
1468        # Expat was written by James Clark and is now maintained by a group of
1469        # developers on SourceForge; see www.libexpat.org for more information.
1470        # The pyexpat module was written by Paul Prescod after a prototype by
1471        # Jack Jansen.  The Expat source is included in Modules/expat/.  Usage
1472        # of a system shared libexpat.so is possible with --with-system-expat
1473        # configure option.
1474        #
1475        # More information on Expat can be found at www.libexpat.org.
1476        #
1477        if '--with-system-expat' in sysconfig.get_config_var("CONFIG_ARGS"):
1478            expat_inc = []
1479            define_macros = []
1480            expat_lib = ['expat']
1481            expat_sources = []
1482            expat_depends = []
1483        else:
1484            expat_inc = [os.path.join(os.getcwd(), srcdir, 'Modules', 'expat')]
1485            define_macros = [
1486                ('HAVE_EXPAT_CONFIG_H', '1'),
1487                # bpo-30947: Python uses best available entropy sources to
1488                # call XML_SetHashSalt(), expat entropy sources are not needed
1489                ('XML_POOR_ENTROPY', '1'),
1490            ]
1491            expat_lib = []
1492            expat_sources = ['expat/xmlparse.c',
1493                             'expat/xmlrole.c',
1494                             'expat/xmltok.c']
1495            expat_depends = ['expat/ascii.h',
1496                             'expat/asciitab.h',
1497                             'expat/expat.h',
1498                             'expat/expat_config.h',
1499                             'expat/expat_external.h',
1500                             'expat/internal.h',
1501                             'expat/latin1tab.h',
1502                             'expat/utf8tab.h',
1503                             'expat/xmlrole.h',
1504                             'expat/xmltok.h',
1505                             'expat/xmltok_impl.h'
1506                             ]
1507
1508        exts.append(Extension('pyexpat',
1509                              define_macros = define_macros,
1510                              include_dirs = expat_inc,
1511                              libraries = expat_lib,
1512                              sources = ['pyexpat.c'] + expat_sources,
1513                              depends = expat_depends,
1514                              ))
1515
1516        # Fredrik Lundh's cElementTree module.  Note that this also
1517        # uses expat (via the CAPI hook in pyexpat).
1518
1519        if os.path.isfile(os.path.join(srcdir, 'Modules', '_elementtree.c')):
1520            define_macros.append(('USE_PYEXPAT_CAPI', None))
1521            exts.append(Extension('_elementtree',
1522                                  define_macros = define_macros,
1523                                  include_dirs = expat_inc,
1524                                  libraries = expat_lib,
1525                                  sources = ['_elementtree.c'],
1526                                  depends = ['pyexpat.c'] + expat_sources +
1527                                      expat_depends,
1528                                  ))
1529        else:
1530            missing.append('_elementtree')
1531
1532        # Hye-Shik Chang's CJKCodecs modules.
1533        if have_unicode:
1534            exts.append(Extension('_multibytecodec',
1535                                  ['cjkcodecs/multibytecodec.c']))
1536            for loc in ('kr', 'jp', 'cn', 'tw', 'hk', 'iso2022'):
1537                exts.append(Extension('_codecs_%s' % loc,
1538                                      ['cjkcodecs/_codecs_%s.c' % loc]))
1539        else:
1540            missing.append('_multibytecodec')
1541            for loc in ('kr', 'jp', 'cn', 'tw', 'hk', 'iso2022'):
1542                missing.append('_codecs_%s' % loc)
1543
1544        # Dynamic loading module
1545        if sys.maxint == 0x7fffffff:
1546            # This requires sizeof(int) == sizeof(long) == sizeof(char*)
1547            dl_inc = find_file('dlfcn.h', [], inc_dirs)
1548            if (dl_inc is not None) and (host_platform not in ['atheos']):
1549                exts.append( Extension('dl', ['dlmodule.c']) )
1550            else:
1551                missing.append('dl')
1552        else:
1553            missing.append('dl')
1554
1555        # Thomas Heller's _ctypes module
1556        self.detect_ctypes(inc_dirs, lib_dirs)
1557
1558        # Richard Oudkerk's multiprocessing module
1559        if host_platform == 'win32':             # Windows
1560            macros = dict()
1561            libraries = ['ws2_32']
1562
1563        elif host_platform == 'darwin':          # Mac OSX
1564            macros = dict()
1565            libraries = []
1566
1567        elif host_platform == 'cygwin':          # Cygwin
1568            macros = dict()
1569            libraries = []
1570
1571        elif host_platform in ('freebsd4', 'freebsd5', 'freebsd6', 'freebsd7', 'freebsd8'):
1572            # FreeBSD's P1003.1b semaphore support is very experimental
1573            # and has many known problems. (as of June 2008)
1574            macros = dict()
1575            libraries = []
1576
1577        elif host_platform.startswith('openbsd'):
1578            macros = dict()
1579            libraries = []
1580
1581        elif host_platform.startswith('netbsd'):
1582            macros = dict()
1583            libraries = []
1584
1585        else:                                   # Linux and other unices
1586            macros = dict()
1587            libraries = ['rt']
1588
1589        if host_platform == 'win32':
1590            multiprocessing_srcs = [ '_multiprocessing/multiprocessing.c',
1591                                     '_multiprocessing/semaphore.c',
1592                                     '_multiprocessing/pipe_connection.c',
1593                                     '_multiprocessing/socket_connection.c',
1594                                     '_multiprocessing/win32_functions.c'
1595                                   ]
1596
1597        else:
1598            multiprocessing_srcs = [ '_multiprocessing/multiprocessing.c',
1599                                     '_multiprocessing/socket_connection.c'
1600                                   ]
1601            if (sysconfig.get_config_var('HAVE_SEM_OPEN') and not
1602                sysconfig.get_config_var('POSIX_SEMAPHORES_NOT_ENABLED')):
1603                multiprocessing_srcs.append('_multiprocessing/semaphore.c')
1604
1605        if sysconfig.get_config_var('WITH_THREAD'):
1606            exts.append ( Extension('_multiprocessing', multiprocessing_srcs,
1607                                    define_macros=macros.items(),
1608                                    include_dirs=["Modules/_multiprocessing"]))
1609        else:
1610            missing.append('_multiprocessing')
1611
1612        # End multiprocessing
1613
1614
1615        # Platform-specific libraries
1616        if host_platform == 'linux2':
1617            # Linux-specific modules
1618            exts.append( Extension('linuxaudiodev', ['linuxaudiodev.c']) )
1619        else:
1620            missing.append('linuxaudiodev')
1621
1622        if (host_platform in ('linux2', 'freebsd4', 'freebsd5', 'freebsd6',
1623                        'freebsd7', 'freebsd8')
1624            or host_platform.startswith("gnukfreebsd")):
1625            exts.append( Extension('ossaudiodev', ['ossaudiodev.c']) )
1626        else:
1627            missing.append('ossaudiodev')
1628
1629        if host_platform == 'sunos5':
1630            # SunOS specific modules
1631            exts.append( Extension('sunaudiodev', ['sunaudiodev.c']) )
1632        else:
1633            missing.append('sunaudiodev')
1634
1635        if host_platform == 'darwin':
1636            # _scproxy
1637            exts.append(Extension("_scproxy", [os.path.join(srcdir, "Mac/Modules/_scproxy.c")],
1638                extra_link_args= [
1639                    '-framework', 'SystemConfiguration',
1640                    '-framework', 'CoreFoundation'
1641                ]))
1642
1643
1644        if host_platform == 'darwin' and ("--disable-toolbox-glue" not in
1645                sysconfig.get_config_var("CONFIG_ARGS")):
1646
1647            if int(os.uname()[2].split('.')[0]) >= 8:
1648                # We're on Mac OS X 10.4 or later, the compiler should
1649                # support '-Wno-deprecated-declarations'. This will
1650                # suppress deprecation warnings for the Carbon extensions,
1651                # these extensions wrap the Carbon APIs and even those
1652                # parts that are deprecated.
1653                carbon_extra_compile_args = ['-Wno-deprecated-declarations']
1654            else:
1655                carbon_extra_compile_args = []
1656
1657            # Mac OS X specific modules.
1658            def macSrcExists(name1, name2=''):
1659                if not name1:
1660                    return None
1661                names = (name1,)
1662                if name2:
1663                    names = (name1, name2)
1664                path = os.path.join(srcdir, 'Mac', 'Modules', *names)
1665                return os.path.exists(path)
1666
1667            def addMacExtension(name, kwds, extra_srcs=[]):
1668                dirname = ''
1669                if name[0] == '_':
1670                    dirname = name[1:].lower()
1671                cname = name + '.c'
1672                cmodulename = name + 'module.c'
1673                # Check for NNN.c, NNNmodule.c, _nnn/NNN.c, _nnn/NNNmodule.c
1674                if macSrcExists(cname):
1675                    srcs = [cname]
1676                elif macSrcExists(cmodulename):
1677                    srcs = [cmodulename]
1678                elif macSrcExists(dirname, cname):
1679                    # XXX(nnorwitz): If all the names ended with module, we
1680                    # wouldn't need this condition.  ibcarbon is the only one.
1681                    srcs = [os.path.join(dirname, cname)]
1682                elif macSrcExists(dirname, cmodulename):
1683                    srcs = [os.path.join(dirname, cmodulename)]
1684                else:
1685                    raise RuntimeError("%s not found" % name)
1686
1687                # Here's the whole point:  add the extension with sources
1688                exts.append(Extension(name, srcs + extra_srcs, **kwds))
1689
1690            # Core Foundation
1691            core_kwds = {'extra_compile_args': carbon_extra_compile_args,
1692                         'extra_link_args': ['-framework', 'CoreFoundation'],
1693                        }
1694            addMacExtension('_CF', core_kwds, ['cf/pycfbridge.c'])
1695            addMacExtension('autoGIL', core_kwds)
1696
1697
1698
1699            # Carbon
1700            carbon_kwds = {'extra_compile_args': carbon_extra_compile_args,
1701                           'extra_link_args': ['-framework', 'Carbon'],
1702                          }
1703            CARBON_EXTS = ['ColorPicker', 'gestalt', 'MacOS', 'Nav',
1704                           'OSATerminology', 'icglue',
1705                           # All these are in subdirs
1706                           '_AE', '_AH', '_App', '_CarbonEvt', '_Cm', '_Ctl',
1707                           '_Dlg', '_Drag', '_Evt', '_File', '_Folder', '_Fm',
1708                           '_Help', '_Icn', '_IBCarbon', '_List',
1709                           '_Menu', '_Mlte', '_OSA', '_Res', '_Qd', '_Qdoffs',
1710                           '_Scrap', '_Snd', '_TE',
1711                          ]
1712            for name in CARBON_EXTS:
1713                addMacExtension(name, carbon_kwds)
1714
1715            # Workaround for a bug in the version of gcc shipped with Xcode 3.
1716            # The _Win extension should build just like the other Carbon extensions, but
1717            # this actually results in a hard crash of the linker.
1718            #
1719            if '-arch ppc64' in cflags and '-arch ppc' in cflags:
1720                win_kwds = {'extra_compile_args': carbon_extra_compile_args + ['-arch', 'i386', '-arch', 'ppc'],
1721                               'extra_link_args': ['-framework', 'Carbon', '-arch', 'i386', '-arch', 'ppc'],
1722                           }
1723                addMacExtension('_Win', win_kwds)
1724            else:
1725                addMacExtension('_Win', carbon_kwds)
1726
1727
1728            # Application Services & QuickTime
1729            app_kwds = {'extra_compile_args': carbon_extra_compile_args,
1730                        'extra_link_args': ['-framework','ApplicationServices'],
1731                       }
1732            addMacExtension('_Launch', app_kwds)
1733            addMacExtension('_CG', app_kwds)
1734
1735            exts.append( Extension('_Qt', ['qt/_Qtmodule.c'],
1736                        extra_compile_args=carbon_extra_compile_args,
1737                        extra_link_args=['-framework', 'QuickTime',
1738                                     '-framework', 'Carbon']) )
1739
1740
1741        self.extensions.extend(exts)
1742
1743        # Call the method for detecting whether _tkinter can be compiled
1744        self.detect_tkinter(inc_dirs, lib_dirs)
1745
1746        if '_tkinter' not in [e.name for e in self.extensions]:
1747            missing.append('_tkinter')
1748
1749##         # Uncomment these lines if you want to play with xxmodule.c
1750##         ext = Extension('xx', ['xxmodule.c'])
1751##         self.extensions.append(ext)
1752
1753        return missing
1754
1755    def detect_tkinter_explicitly(self):
1756        # Build _tkinter using explicit locations for Tcl/Tk.
1757        #
1758        # This is enabled when both arguments are given to ./configure:
1759        #
1760        #     --with-tcltk-includes="-I/path/to/tclincludes \
1761        #                            -I/path/to/tkincludes"
1762        #     --with-tcltk-libs="-L/path/to/tcllibs -ltclm.n \
1763        #                        -L/path/to/tklibs -ltkm.n"
1764        #
1765        # These values can also be specified or overridden via make:
1766        #    make TCLTK_INCLUDES="..." TCLTK_LIBS="..."
1767        #
1768        # This can be useful for building and testing tkinter with multiple
1769        # versions of Tcl/Tk.  Note that a build of Tk depends on a particular
1770        # build of Tcl so you need to specify both arguments and use care when
1771        # overriding.
1772
1773        # The _TCLTK variables are created in the Makefile sharedmods target.
1774        tcltk_includes = os.environ.get('_TCLTK_INCLUDES')
1775        tcltk_libs = os.environ.get('_TCLTK_LIBS')
1776        if not (tcltk_includes and tcltk_libs):
1777            # Resume default configuration search.
1778            return 0
1779
1780        extra_compile_args = tcltk_includes.split()
1781        extra_link_args = tcltk_libs.split()
1782        ext = Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
1783                        define_macros=[('WITH_APPINIT', 1)],
1784                        extra_compile_args = extra_compile_args,
1785                        extra_link_args = extra_link_args,
1786                        )
1787        self.extensions.append(ext)
1788        return 1
1789
1790    def detect_tkinter_darwin(self, inc_dirs, lib_dirs):
1791        # The _tkinter module, using frameworks. Since frameworks are quite
1792        # different the UNIX search logic is not sharable.
1793        from os.path import join, exists
1794        framework_dirs = [
1795            '/Library/Frameworks',
1796            '/System/Library/Frameworks/',
1797            join(os.getenv('HOME'), '/Library/Frameworks')
1798        ]
1799
1800        sysroot = macosx_sdk_root()
1801
1802        # Find the directory that contains the Tcl.framework and Tk.framework
1803        # bundles.
1804        # XXX distutils should support -F!
1805        for F in framework_dirs:
1806            # both Tcl.framework and Tk.framework should be present
1807
1808
1809            for fw in 'Tcl', 'Tk':
1810                if is_macosx_sdk_path(F):
1811                    if not exists(join(sysroot, F[1:], fw + '.framework')):
1812                        break
1813                else:
1814                    if not exists(join(F, fw + '.framework')):
1815                        break
1816            else:
1817                # ok, F is now directory with both frameworks. Continure
1818                # building
1819                break
1820        else:
1821            # Tk and Tcl frameworks not found. Normal "unix" tkinter search
1822            # will now resume.
1823            return 0
1824
1825        # For 8.4a2, we must add -I options that point inside the Tcl and Tk
1826        # frameworks. In later release we should hopefully be able to pass
1827        # the -F option to gcc, which specifies a framework lookup path.
1828        #
1829        include_dirs = [
1830            join(F, fw + '.framework', H)
1831            for fw in 'Tcl', 'Tk'
1832            for H in 'Headers', 'Versions/Current/PrivateHeaders'
1833        ]
1834
1835        # For 8.4a2, the X11 headers are not included. Rather than include a
1836        # complicated search, this is a hard-coded path. It could bail out
1837        # if X11 libs are not found...
1838        include_dirs.append('/usr/X11R6/include')
1839        frameworks = ['-framework', 'Tcl', '-framework', 'Tk']
1840
1841        # All existing framework builds of Tcl/Tk don't support 64-bit
1842        # architectures.
1843        cflags = sysconfig.get_config_vars('CFLAGS')[0]
1844        archs = re.findall('-arch\s+(\w+)', cflags)
1845
1846        if is_macosx_sdk_path(F):
1847            fp = os.popen("file %s/Tk.framework/Tk | grep 'for architecture'"%(os.path.join(sysroot, F[1:]),))
1848        else:
1849            fp = os.popen("file %s/Tk.framework/Tk | grep 'for architecture'"%(F,))
1850
1851        detected_archs = []
1852        for ln in fp:
1853            a = ln.split()[-1]
1854            if a in archs:
1855                detected_archs.append(ln.split()[-1])
1856        fp.close()
1857
1858        for a in detected_archs:
1859            frameworks.append('-arch')
1860            frameworks.append(a)
1861
1862        ext = Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
1863                        define_macros=[('WITH_APPINIT', 1)],
1864                        include_dirs = include_dirs,
1865                        libraries = [],
1866                        extra_compile_args = frameworks[2:],
1867                        extra_link_args = frameworks,
1868                        )
1869        self.extensions.append(ext)
1870        return 1
1871
1872    def detect_tkinter(self, inc_dirs, lib_dirs):
1873        # The _tkinter module.
1874
1875        # Check whether --with-tcltk-includes and --with-tcltk-libs were
1876        # configured or passed into the make target.  If so, use these values
1877        # to build tkinter and bypass the searches for Tcl and TK in standard
1878        # locations.
1879        if self.detect_tkinter_explicitly():
1880            return
1881
1882        # Rather than complicate the code below, detecting and building
1883        # AquaTk is a separate method. Only one Tkinter will be built on
1884        # Darwin - either AquaTk, if it is found, or X11 based Tk.
1885        if (host_platform == 'darwin' and
1886            self.detect_tkinter_darwin(inc_dirs, lib_dirs)):
1887            return
1888
1889        # Assume we haven't found any of the libraries or include files
1890        # The versions with dots are used on Unix, and the versions without
1891        # dots on Windows, for detection by cygwin.
1892        tcllib = tklib = tcl_includes = tk_includes = None
1893        for version in ['8.6', '86', '8.5', '85', '8.4', '84', '8.3', '83',
1894                        '8.2', '82', '8.1', '81', '8.0', '80']:
1895            tklib = self.compiler.find_library_file(lib_dirs,
1896                                                        'tk' + version)
1897            tcllib = self.compiler.find_library_file(lib_dirs,
1898                                                         'tcl' + version)
1899            if tklib and tcllib:
1900                # Exit the loop when we've found the Tcl/Tk libraries
1901                break
1902
1903        # Now check for the header files
1904        if tklib and tcllib:
1905            # Check for the include files on Debian and {Free,Open}BSD, where
1906            # they're put in /usr/include/{tcl,tk}X.Y
1907            dotversion = version
1908            if '.' not in dotversion and "bsd" in host_platform.lower():
1909                # OpenBSD and FreeBSD use Tcl/Tk library names like libtcl83.a,
1910                # but the include subdirs are named like .../include/tcl8.3.
1911                dotversion = dotversion[:-1] + '.' + dotversion[-1]
1912            tcl_include_sub = []
1913            tk_include_sub = []
1914            for dir in inc_dirs:
1915                tcl_include_sub += [dir + os.sep + "tcl" + dotversion]
1916                tk_include_sub += [dir + os.sep + "tk" + dotversion]
1917            tk_include_sub += tcl_include_sub
1918            tcl_includes = find_file('tcl.h', inc_dirs, tcl_include_sub)
1919            tk_includes = find_file('tk.h', inc_dirs, tk_include_sub)
1920
1921        if (tcllib is None or tklib is None or
1922            tcl_includes is None or tk_includes is None):
1923            self.announce("INFO: Can't locate Tcl/Tk libs and/or headers", 2)
1924            return
1925
1926        # OK... everything seems to be present for Tcl/Tk.
1927
1928        include_dirs = [] ; libs = [] ; defs = [] ; added_lib_dirs = []
1929        for dir in tcl_includes + tk_includes:
1930            if dir not in include_dirs:
1931                include_dirs.append(dir)
1932
1933        # Check for various platform-specific directories
1934        if host_platform == 'sunos5':
1935            include_dirs.append('/usr/openwin/include')
1936            added_lib_dirs.append('/usr/openwin/lib')
1937        elif os.path.exists('/usr/X11R6/include'):
1938            include_dirs.append('/usr/X11R6/include')
1939            added_lib_dirs.append('/usr/X11R6/lib64')
1940            added_lib_dirs.append('/usr/X11R6/lib')
1941        elif os.path.exists('/usr/X11R5/include'):
1942            include_dirs.append('/usr/X11R5/include')
1943            added_lib_dirs.append('/usr/X11R5/lib')
1944        else:
1945            # Assume default location for X11
1946            include_dirs.append('/usr/X11/include')
1947            added_lib_dirs.append('/usr/X11/lib')
1948
1949        # If Cygwin, then verify that X is installed before proceeding
1950        if host_platform == 'cygwin':
1951            x11_inc = find_file('X11/Xlib.h', [], include_dirs)
1952            if x11_inc is None:
1953                return
1954
1955        # Check for BLT extension
1956        if self.compiler.find_library_file(lib_dirs + added_lib_dirs,
1957                                               'BLT8.0'):
1958            defs.append( ('WITH_BLT', 1) )
1959            libs.append('BLT8.0')
1960        elif self.compiler.find_library_file(lib_dirs + added_lib_dirs,
1961                                                'BLT'):
1962            defs.append( ('WITH_BLT', 1) )
1963            libs.append('BLT')
1964
1965        # Add the Tcl/Tk libraries
1966        libs.append('tk'+ version)
1967        libs.append('tcl'+ version)
1968
1969        if host_platform in ['aix3', 'aix4']:
1970            libs.append('ld')
1971
1972        # Finally, link with the X11 libraries (not appropriate on cygwin)
1973        if host_platform != "cygwin":
1974            libs.append('X11')
1975
1976        ext = Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
1977                        define_macros=[('WITH_APPINIT', 1)] + defs,
1978                        include_dirs = include_dirs,
1979                        libraries = libs,
1980                        library_dirs = added_lib_dirs,
1981                        )
1982        self.extensions.append(ext)
1983
1984        # XXX handle these, but how to detect?
1985        # *** Uncomment and edit for PIL (TkImaging) extension only:
1986        #       -DWITH_PIL -I../Extensions/Imaging/libImaging  tkImaging.c \
1987        # *** Uncomment and edit for TOGL extension only:
1988        #       -DWITH_TOGL togl.c \
1989        # *** Uncomment these for TOGL extension only:
1990        #       -lGL -lGLU -lXext -lXmu \
1991
1992    def configure_ctypes_darwin(self, ext):
1993        # Darwin (OS X) uses preconfigured files, in
1994        # the Modules/_ctypes/libffi_osx directory.
1995        srcdir = sysconfig.get_config_var('srcdir')
1996        ffi_srcdir = os.path.abspath(os.path.join(srcdir, 'Modules',
1997                                                  '_ctypes', 'libffi_osx'))
1998        sources = [os.path.join(ffi_srcdir, p)
1999                   for p in ['ffi.c',
2000                             'x86/darwin64.S',
2001                             'x86/x86-darwin.S',
2002                             'x86/x86-ffi_darwin.c',
2003                             'x86/x86-ffi64.c',
2004                             'powerpc/ppc-darwin.S',
2005                             'powerpc/ppc-darwin_closure.S',
2006                             'powerpc/ppc-ffi_darwin.c',
2007                             'powerpc/ppc64-darwin_closure.S',
2008                             ]]
2009
2010        # Add .S (preprocessed assembly) to C compiler source extensions.
2011        self.compiler.src_extensions.append('.S')
2012
2013        include_dirs = [os.path.join(ffi_srcdir, 'include'),
2014                        os.path.join(ffi_srcdir, 'powerpc')]
2015        ext.include_dirs.extend(include_dirs)
2016        ext.sources.extend(sources)
2017        return True
2018
2019    def configure_ctypes(self, ext):
2020        if not self.use_system_libffi:
2021            if host_platform == 'darwin':
2022                return self.configure_ctypes_darwin(ext)
2023
2024            srcdir = sysconfig.get_config_var('srcdir')
2025            ffi_builddir = os.path.join(self.build_temp, 'libffi')
2026            ffi_srcdir = os.path.abspath(os.path.join(srcdir, 'Modules',
2027                                         '_ctypes', 'libffi'))
2028            ffi_configfile = os.path.join(ffi_builddir, 'fficonfig.py')
2029
2030            from distutils.dep_util import newer_group
2031
2032            config_sources = [os.path.join(ffi_srcdir, fname)
2033                              for fname in os.listdir(ffi_srcdir)
2034                              if os.path.isfile(os.path.join(ffi_srcdir, fname))]
2035            if self.force or newer_group(config_sources,
2036                                         ffi_configfile):
2037                from distutils.dir_util import mkpath
2038                mkpath(ffi_builddir)
2039                config_args = [arg for arg in sysconfig.get_config_var("CONFIG_ARGS").split()
2040                               if (('--host=' in arg) or ('--build=' in arg))]
2041                if not self.verbose:
2042                    config_args.append("-q")
2043
2044                # Pass empty CFLAGS because we'll just append the resulting
2045                # CFLAGS to Python's; -g or -O2 is to be avoided.
2046                cmd = "cd %s && env CFLAGS='' '%s/configure' %s" \
2047                      % (ffi_builddir, ffi_srcdir, " ".join(config_args))
2048
2049                res = os.system(cmd)
2050                if res or not os.path.exists(ffi_configfile):
2051                    print "Failed to configure _ctypes module"
2052                    return False
2053
2054            fficonfig = {}
2055            with open(ffi_configfile) as f:
2056                exec f in fficonfig
2057
2058            # Add .S (preprocessed assembly) to C compiler source extensions.
2059            self.compiler.src_extensions.append('.S')
2060
2061            include_dirs = [os.path.join(ffi_builddir, 'include'),
2062                            ffi_builddir,
2063                            os.path.join(ffi_srcdir, 'src')]
2064            extra_compile_args = fficonfig['ffi_cflags'].split()
2065
2066            ext.sources.extend(os.path.join(ffi_srcdir, f) for f in
2067                               fficonfig['ffi_sources'])
2068            ext.include_dirs.extend(include_dirs)
2069            ext.extra_compile_args.extend(extra_compile_args)
2070        return True
2071
2072    def detect_ctypes(self, inc_dirs, lib_dirs):
2073        self.use_system_libffi = False
2074        include_dirs = []
2075        extra_compile_args = []
2076        extra_link_args = []
2077        sources = ['_ctypes/_ctypes.c',
2078                   '_ctypes/callbacks.c',
2079                   '_ctypes/callproc.c',
2080                   '_ctypes/stgdict.c',
2081                   '_ctypes/cfield.c']
2082        depends = ['_ctypes/ctypes.h']
2083
2084        if host_platform == 'darwin':
2085            sources.append('_ctypes/malloc_closure.c')
2086            sources.append('_ctypes/darwin/dlfcn_simple.c')
2087            extra_compile_args.append('-DMACOSX')
2088            include_dirs.append('_ctypes/darwin')
2089# XXX Is this still needed?
2090##            extra_link_args.extend(['-read_only_relocs', 'warning'])
2091
2092        elif host_platform == 'sunos5':
2093            # XXX This shouldn't be necessary; it appears that some
2094            # of the assembler code is non-PIC (i.e. it has relocations
2095            # when it shouldn't. The proper fix would be to rewrite
2096            # the assembler code to be PIC.
2097            # This only works with GCC; the Sun compiler likely refuses
2098            # this option. If you want to compile ctypes with the Sun
2099            # compiler, please research a proper solution, instead of
2100            # finding some -z option for the Sun compiler.
2101            extra_link_args.append('-mimpure-text')
2102
2103        elif host_platform.startswith('hp-ux'):
2104            extra_link_args.append('-fPIC')
2105
2106        ext = Extension('_ctypes',
2107                        include_dirs=include_dirs,
2108                        extra_compile_args=extra_compile_args,
2109                        extra_link_args=extra_link_args,
2110                        libraries=[],
2111                        sources=sources,
2112                        depends=depends)
2113        ext_test = Extension('_ctypes_test',
2114                             sources=['_ctypes/_ctypes_test.c'])
2115        self.extensions.extend([ext, ext_test])
2116
2117        if not '--with-system-ffi' in sysconfig.get_config_var("CONFIG_ARGS"):
2118            return
2119
2120        if host_platform == 'darwin':
2121            # OS X 10.5 comes with libffi.dylib; the include files are
2122            # in /usr/include/ffi
2123            inc_dirs.append('/usr/include/ffi')
2124
2125        ffi_inc = [sysconfig.get_config_var("LIBFFI_INCLUDEDIR")]
2126        if not ffi_inc or ffi_inc[0] == '':
2127            ffi_inc = find_file('ffi.h', [], inc_dirs)
2128        if ffi_inc is not None:
2129            ffi_h = ffi_inc[0] + '/ffi.h'
2130            with open(ffi_h) as f:
2131                for line in f:
2132                    line = line.strip()
2133                    if line.startswith(('#define LIBFFI_H',
2134                                        '#define ffi_wrapper_h')):
2135                        break
2136                else:
2137                    ffi_inc = None
2138                    print('Header file {} does not define LIBFFI_H or '
2139                          'ffi_wrapper_h'.format(ffi_h))
2140        ffi_lib = None
2141        if ffi_inc is not None:
2142            for lib_name in ('ffi_convenience', 'ffi_pic', 'ffi'):
2143                if (self.compiler.find_library_file(lib_dirs, lib_name)):
2144                    ffi_lib = lib_name
2145                    break
2146
2147        if ffi_inc and ffi_lib:
2148            ext.include_dirs.extend(ffi_inc)
2149            ext.libraries.append(ffi_lib)
2150            self.use_system_libffi = True
2151
2152        if sysconfig.get_config_var('HAVE_LIBDL'):
2153            # for dlopen, see bpo-32647
2154            ext.libraries.append('dl')
2155
2156    def _detect_nis(self, inc_dirs, lib_dirs):
2157        if host_platform in {'win32', 'cygwin', 'qnx6'}:
2158            return None
2159
2160        libs = []
2161        library_dirs = []
2162        includes_dirs = []
2163
2164        # bpo-32521: glibc has deprecated Sun RPC for some time. Fedora 28
2165        # moved headers and libraries to libtirpc and libnsl. The headers
2166        # are in tircp and nsl sub directories.
2167        rpcsvc_inc = find_file(
2168            'rpcsvc/yp_prot.h', inc_dirs,
2169            [os.path.join(inc_dir, 'nsl') for inc_dir in inc_dirs]
2170        )
2171        rpc_inc = find_file(
2172            'rpc/rpc.h', inc_dirs,
2173            [os.path.join(inc_dir, 'tirpc') for inc_dir in inc_dirs]
2174        )
2175        if rpcsvc_inc is None or rpc_inc is None:
2176            # not found
2177            return None
2178        includes_dirs.extend(rpcsvc_inc)
2179        includes_dirs.extend(rpc_inc)
2180
2181        if self.compiler.find_library_file(lib_dirs, 'nsl'):
2182            libs.append('nsl')
2183        else:
2184            # libnsl-devel: check for libnsl in nsl/ subdirectory
2185            nsl_dirs = [os.path.join(lib_dir, 'nsl') for lib_dir in lib_dirs]
2186            libnsl = self.compiler.find_library_file(nsl_dirs, 'nsl')
2187            if libnsl is not None:
2188                library_dirs.append(os.path.dirname(libnsl))
2189                libs.append('nsl')
2190
2191        if self.compiler.find_library_file(lib_dirs, 'tirpc'):
2192            libs.append('tirpc')
2193
2194        return Extension(
2195            'nis', ['nismodule.c'],
2196            libraries=libs,
2197            library_dirs=library_dirs,
2198            include_dirs=includes_dirs
2199        )
2200
2201
2202class PyBuildInstall(install):
2203    # Suppress the warning about installation into the lib_dynload
2204    # directory, which is not in sys.path when running Python during
2205    # installation:
2206    def initialize_options (self):
2207        install.initialize_options(self)
2208        self.warn_dir=0
2209
2210class PyBuildInstallLib(install_lib):
2211    # Do exactly what install_lib does but make sure correct access modes get
2212    # set on installed directories and files. All installed files with get
2213    # mode 644 unless they are a shared library in which case they will get
2214    # mode 755. All installed directories will get mode 755.
2215
2216    so_ext = sysconfig.get_config_var("SO")
2217
2218    def install(self):
2219        outfiles = install_lib.install(self)
2220        self.set_file_modes(outfiles, 0644, 0755)
2221        self.set_dir_modes(self.install_dir, 0755)
2222        return outfiles
2223
2224    def set_file_modes(self, files, defaultMode, sharedLibMode):
2225        if not self.is_chmod_supported(): return
2226        if not files: return
2227
2228        for filename in files:
2229            if os.path.islink(filename): continue
2230            mode = defaultMode
2231            if filename.endswith(self.so_ext): mode = sharedLibMode
2232            log.info("changing mode of %s to %o", filename, mode)
2233            if not self.dry_run: os.chmod(filename, mode)
2234
2235    def set_dir_modes(self, dirname, mode):
2236        if not self.is_chmod_supported(): return
2237        os.path.walk(dirname, self.set_dir_modes_visitor, mode)
2238
2239    def set_dir_modes_visitor(self, mode, dirname, names):
2240        if os.path.islink(dirname): return
2241        log.info("changing mode of %s to %o", dirname, mode)
2242        if not self.dry_run: os.chmod(dirname, mode)
2243
2244    def is_chmod_supported(self):
2245        return hasattr(os, 'chmod')
2246
2247SUMMARY = """
2248Python is an interpreted, interactive, object-oriented programming
2249language. It is often compared to Tcl, Perl, Scheme or Java.
2250
2251Python combines remarkable power with very clear syntax. It has
2252modules, classes, exceptions, very high level dynamic data types, and
2253dynamic typing. There are interfaces to many system calls and
2254libraries, as well as to various windowing systems (X11, Motif, Tk,
2255Mac, MFC). New built-in modules are easily written in C or C++. Python
2256is also usable as an extension language for applications that need a
2257programmable interface.
2258
2259The Python implementation is portable: it runs on many brands of UNIX,
2260on Windows, DOS, OS/2, Mac, Amiga... If your favorite system isn't
2261listed here, it may still be supported, if there's a C compiler for
2262it. Ask around on comp.lang.python -- or just try compiling Python
2263yourself.
2264"""
2265
2266CLASSIFIERS = """
2267Development Status :: 6 - Mature
2268License :: OSI Approved :: Python Software Foundation License
2269Natural Language :: English
2270Programming Language :: C
2271Programming Language :: Python
2272Topic :: Software Development
2273"""
2274
2275def main():
2276    # turn off warnings when deprecated modules are imported
2277    import warnings
2278    warnings.filterwarnings("ignore",category=DeprecationWarning)
2279    setup(# PyPI Metadata (PEP 301)
2280          name = "Python",
2281          version = sys.version.split()[0],
2282          url = "http://www.python.org/%s" % sys.version[:3],
2283          maintainer = "Guido van Rossum and the Python community",
2284          maintainer_email = "python-dev@python.org",
2285          description = "A high-level object-oriented programming language",
2286          long_description = SUMMARY.strip(),
2287          license = "PSF license",
2288          classifiers = filter(None, CLASSIFIERS.split("\n")),
2289          platforms = ["Many"],
2290
2291          # Build info
2292          cmdclass = {'build_ext':PyBuildExt, 'install':PyBuildInstall,
2293                      'install_lib':PyBuildInstallLib},
2294          # The struct module is defined here, because build_ext won't be
2295          # called unless there's at least one extension module defined.
2296          ext_modules=[Extension('_struct', ['_struct.c'])],
2297
2298          # Scripts to install
2299          scripts = ['Tools/scripts/pydoc', 'Tools/scripts/idle',
2300                     'Tools/scripts/2to3',
2301                     'Lib/smtpd.py']
2302        )
2303
2304# --install-platlib
2305if __name__ == '__main__':
2306    main()
2307