setup.py revision 96f7d875b7092ec92a24647702757c76cdf9b6a5
1# Autodetecting setup.py script for building the Python extensions
2#
3
4__version__ = "$Revision$"
5
6import sys, os, getopt, imp, re
7
8from distutils import log
9from distutils import sysconfig
10from distutils import text_file
11from distutils.errors import *
12from distutils.core import Extension, setup
13from distutils.command.build_ext import build_ext
14from distutils.command.install import install
15from distutils.command.install_lib import install_lib
16
17# This global variable is used to hold the list of modules to be disabled.
18disabled_module_list = []
19
20def add_dir_to_list(dirlist, dir):
21    """Add the directory 'dir' to the list 'dirlist' (at the front) if
22    1) 'dir' is not already in 'dirlist'
23    2) 'dir' actually exists, and is a directory."""
24    if dir is not None and os.path.isdir(dir) and dir not in dirlist:
25        dirlist.insert(0, dir)
26
27def find_file(filename, std_dirs, paths):
28    """Searches for the directory where a given file is located,
29    and returns a possibly-empty list of additional directories, or None
30    if the file couldn't be found at all.
31
32    'filename' is the name of a file, such as readline.h or libcrypto.a.
33    'std_dirs' is the list of standard system directories; if the
34        file is found in one of them, no additional directives are needed.
35    'paths' is a list of additional locations to check; if the file is
36        found in one of them, the resulting list will contain the directory.
37    """
38
39    # Check the standard locations
40    for dir in std_dirs:
41        f = os.path.join(dir, filename)
42        if os.path.exists(f): return []
43
44    # Check the additional directories
45    for dir in paths:
46        f = os.path.join(dir, filename)
47        if os.path.exists(f):
48            return [dir]
49
50    # Not found anywhere
51    return None
52
53def find_library_file(compiler, libname, std_dirs, paths):
54    result = compiler.find_library_file(std_dirs + paths, libname)
55    if result is None:
56        return None
57
58    # Check whether the found file is in one of the standard directories
59    dirname = os.path.dirname(result)
60    for p in std_dirs:
61        # Ensure path doesn't end with path separator
62        if p.endswith(os.sep):
63            p = p.strip(os.sep)
64        if p == dirname:
65            return [ ]
66
67    # Otherwise, it must have been in one of the additional directories,
68    # so we have to figure out which one.
69    for p in paths:
70        # Ensure path doesn't end with path separator
71        if p.endswith(os.sep):
72            p = p.strip(os.sep)
73        if p == dirname:
74            return [p]
75    else:
76        assert False, "Internal error: Path not found in std_dirs or paths"
77
78def module_enabled(extlist, modname):
79    """Returns whether the module 'modname' is present in the list
80    of extensions 'extlist'."""
81    extlist = [ext for ext in extlist if ext.name == modname]
82    return len(extlist)
83
84def find_module_file(module, dirlist):
85    """Find a module in a set of possible folders. If it is not found
86    return the unadorned filename"""
87    list = find_file(module, [], dirlist)
88    if not list:
89        return module
90    if len(list) > 1:
91        log.info("WARNING: multiple copies of %s found"%module)
92    return os.path.join(list[0], module)
93
94class PyBuildExt(build_ext):
95
96    def build_extensions(self):
97
98        # Detect which modules should be compiled
99        self.detect_modules()
100
101        # Remove modules that are present on the disabled list
102        self.extensions = [ext for ext in self.extensions
103                           if ext.name not in disabled_module_list]
104
105        # Fix up the autodetected modules, prefixing all the source files
106        # with Modules/ and adding Python's include directory to the path.
107        (srcdir,) = sysconfig.get_config_vars('srcdir')
108        if not srcdir:
109            # Maybe running on Windows but not using CYGWIN?
110            raise ValueError("No source directory; cannot proceed.")
111
112        # Figure out the location of the source code for extension modules
113        moddir = os.path.join(os.getcwd(), srcdir, 'Modules')
114        moddir = os.path.normpath(moddir)
115        srcdir, tail = os.path.split(moddir)
116        srcdir = os.path.normpath(srcdir)
117        moddir = os.path.normpath(moddir)
118
119        moddirlist = [moddir]
120        incdirlist = ['./Include']
121
122        # Platform-dependent module source and include directories
123        platform = self.get_platform()
124        if platform in ('darwin', 'mac'):
125            # Mac OS X also includes some mac-specific modules
126            macmoddir = os.path.join(os.getcwd(), srcdir, 'Mac/Modules')
127            moddirlist.append(macmoddir)
128            incdirlist.append('./Mac/Include')
129
130        alldirlist = moddirlist + incdirlist
131
132        # Fix up the paths for scripts, too
133        self.distribution.scripts = [os.path.join(srcdir, filename)
134                                     for filename in self.distribution.scripts]
135
136        for ext in self.extensions[:]:
137            ext.sources = [ find_module_file(filename, moddirlist)
138                            for filename in ext.sources ]
139            if ext.depends is not None:
140                ext.depends = [find_module_file(filename, alldirlist)
141                               for filename in ext.depends]
142            ext.include_dirs.append( '.' ) # to get config.h
143            for incdir in incdirlist:
144                ext.include_dirs.append( os.path.join(srcdir, incdir) )
145
146            # If a module has already been built statically,
147            # don't build it here
148            if ext.name in sys.builtin_module_names:
149                self.extensions.remove(ext)
150
151        if platform != 'mac':
152            # Parse Modules/Setup to figure out which modules are turned
153            # on in the file.
154            input = text_file.TextFile('Modules/Setup', join_lines=1)
155            remove_modules = []
156            while 1:
157                line = input.readline()
158                if not line: break
159                line = line.split()
160                remove_modules.append( line[0] )
161            input.close()
162
163            for ext in self.extensions[:]:
164                if ext.name in remove_modules:
165                    self.extensions.remove(ext)
166
167        # When you run "make CC=altcc" or something similar, you really want
168        # those environment variables passed into the setup.py phase.  Here's
169        # a small set of useful ones.
170        compiler = os.environ.get('CC')
171        linker_so = os.environ.get('LDSHARED')
172        args = {}
173        # unfortunately, distutils doesn't let us provide separate C and C++
174        # compilers
175        if compiler is not None:
176            (ccshared,opt,base) = sysconfig.get_config_vars('CCSHARED','OPT','BASECFLAGS')
177            args['compiler_so'] = compiler + ' ' + opt + ' ' + ccshared + ' ' + base
178        if linker_so is not None:
179            args['linker_so'] = linker_so
180        self.compiler.set_executables(**args)
181
182        build_ext.build_extensions(self)
183
184    def build_extension(self, ext):
185
186        try:
187            build_ext.build_extension(self, ext)
188        except (CCompilerError, DistutilsError), why:
189            self.announce('WARNING: building of extension "%s" failed: %s' %
190                          (ext.name, sys.exc_info()[1]))
191            return
192        # Workaround for Mac OS X: The Carbon-based modules cannot be
193        # reliably imported into a command-line Python
194        if 'Carbon' in ext.extra_link_args:
195            self.announce(
196                'WARNING: skipping import check for Carbon-based "%s"' %
197                ext.name)
198            return
199        # Workaround for Cygwin: Cygwin currently has fork issues when many
200        # modules have been imported
201        if self.get_platform() == 'cygwin':
202            self.announce('WARNING: skipping import check for Cygwin-based "%s"'
203                % ext.name)
204            return
205        ext_filename = os.path.join(
206            self.build_lib,
207            self.get_ext_filename(self.get_ext_fullname(ext.name)))
208        try:
209            imp.load_dynamic(ext.name, ext_filename)
210        except ImportError, why:
211            self.announce('*** WARNING: renaming "%s" since importing it'
212                          ' failed: %s' % (ext.name, why), level=3)
213            assert not self.inplace
214            basename, tail = os.path.splitext(ext_filename)
215            newname = basename + "_failed" + tail
216            if os.path.exists(newname):
217                os.remove(newname)
218            os.rename(ext_filename, newname)
219
220            # XXX -- This relies on a Vile HACK in
221            # distutils.command.build_ext.build_extension().  The
222            # _built_objects attribute is stored there strictly for
223            # use here.
224            # If there is a failure, _built_objects may not be there,
225            # so catch the AttributeError and move on.
226            try:
227                for filename in self._built_objects:
228                    os.remove(filename)
229            except AttributeError:
230                self.announce('unable to remove files (ignored)')
231        except:
232            exc_type, why, tb = sys.exc_info()
233            self.announce('*** WARNING: importing extension "%s" '
234                          'failed with %s: %s' % (ext.name, exc_type, why),
235                          level=3)
236
237    def get_platform (self):
238        # Get value of sys.platform
239        platform = sys.platform
240        if platform[:6] =='cygwin':
241            platform = 'cygwin'
242        elif platform[:4] =='beos':
243            platform = 'beos'
244        elif platform[:6] == 'darwin':
245            platform = 'darwin'
246        elif platform[:6] == 'atheos':
247            platform = 'atheos'
248
249        return platform
250
251    def detect_modules(self):
252        # Ensure that /usr/local is always used
253        add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib')
254        add_dir_to_list(self.compiler.include_dirs, '/usr/local/include')
255
256        # fink installs lots of goodies in /sw/... - make sure we
257        # check there
258        if sys.platform == "darwin":
259            add_dir_to_list(self.compiler.library_dirs, '/sw/lib')
260            add_dir_to_list(self.compiler.include_dirs, '/sw/include')
261
262        if os.path.normpath(sys.prefix) != '/usr':
263            add_dir_to_list(self.compiler.library_dirs,
264                            sysconfig.get_config_var("LIBDIR"))
265            add_dir_to_list(self.compiler.include_dirs,
266                            sysconfig.get_config_var("INCLUDEDIR"))
267
268        try:
269            have_unicode = unicode
270        except NameError:
271            have_unicode = 0
272
273        # lib_dirs and inc_dirs are used to search for files;
274        # if a file is found in one of those directories, it can
275        # be assumed that no additional -I,-L directives are needed.
276        lib_dirs = self.compiler.library_dirs + ['/lib', '/usr/lib']
277        inc_dirs = self.compiler.include_dirs + ['/usr/include']
278        exts = []
279
280        platform = self.get_platform()
281        (srcdir,) = sysconfig.get_config_vars('srcdir')
282
283        # Check for AtheOS which has libraries in non-standard locations
284        if platform == 'atheos':
285            lib_dirs += ['/system/libs', '/atheos/autolnk/lib']
286            lib_dirs += os.getenv('LIBRARY_PATH', '').split(os.pathsep)
287            inc_dirs += ['/system/include', '/atheos/autolnk/include']
288            inc_dirs += os.getenv('C_INCLUDE_PATH', '').split(os.pathsep)
289
290        # Check for MacOS X, which doesn't need libm.a at all
291        math_libs = ['m']
292        if platform in ['darwin', 'beos', 'mac']:
293            math_libs = []
294
295        # XXX Omitted modules: gl, pure, dl, SGI-specific modules
296
297        #
298        # The following modules are all pretty straightforward, and compile
299        # on pretty much any POSIXish platform.
300        #
301
302        # Some modules that are normally always on:
303        exts.append( Extension('regex', ['regexmodule.c', 'regexpr.c']) )
304        exts.append( Extension('pcre', ['pcremodule.c', 'pypcre.c']) )
305
306        exts.append( Extension('_hotshot', ['_hotshot.c']) )
307        exts.append( Extension('_weakref', ['_weakref.c']) )
308        exts.append( Extension('xreadlines', ['xreadlinesmodule.c']) )
309
310        # array objects
311        exts.append( Extension('array', ['arraymodule.c']) )
312        # complex math library functions
313        exts.append( Extension('cmath', ['cmathmodule.c'],
314                               libraries=math_libs) )
315
316        # math library functions, e.g. sin()
317        exts.append( Extension('math',  ['mathmodule.c'],
318                               libraries=math_libs) )
319        # fast string operations implemented in C
320        exts.append( Extension('strop', ['stropmodule.c']) )
321        # time operations and variables
322        exts.append( Extension('time', ['timemodule.c'],
323                               libraries=math_libs) )
324        exts.append( Extension('datetime', ['datetimemodule.c'],
325                               libraries=math_libs) )
326        # random number generator implemented in C
327        exts.append( Extension("_random", ["_randommodule.c"]) )
328        # fast iterator tools implemented in C
329        exts.append( Extension("itertools", ["itertoolsmodule.c"]) )
330        # operator.add() and similar goodies
331        exts.append( Extension('operator', ['operator.c']) )
332        # Python C API test module
333        exts.append( Extension('_testcapi', ['_testcapimodule.c']) )
334        # static Unicode character database
335        if have_unicode:
336            exts.append( Extension('unicodedata', ['unicodedata.c']) )
337        # access to ISO C locale support
338        if platform in ['cygwin', 'aix4']:
339            locale_libs = ['intl']
340        else:
341            locale_libs = []
342        exts.append( Extension('_locale', ['_localemodule.c'],
343                               libraries=locale_libs ) )
344
345        # Modules with some UNIX dependencies -- on by default:
346        # (If you have a really backward UNIX, select and socket may not be
347        # supported...)
348
349        # fcntl(2) and ioctl(2)
350        exts.append( Extension('fcntl', ['fcntlmodule.c']) )
351        if platform not in ['mac']:
352                # pwd(3)
353            exts.append( Extension('pwd', ['pwdmodule.c']) )
354            # grp(3)
355            exts.append( Extension('grp', ['grpmodule.c']) )
356        # select(2); not on ancient System V
357        exts.append( Extension('select', ['selectmodule.c']) )
358
359        # The md5 module implements the RSA Data Security, Inc. MD5
360        # Message-Digest Algorithm, described in RFC 1321.  The
361        # necessary files md5c.c and md5.h are included here.
362        exts.append( Extension('md5', ['md5module.c', 'md5c.c']) )
363
364        # The sha module implements the SHA checksum algorithm.
365        # (NIST's Secure Hash Algorithm.)
366        exts.append( Extension('sha', ['shamodule.c']) )
367
368        # Helper module for various ascii-encoders
369        exts.append( Extension('binascii', ['binascii.c']) )
370
371        # Fred Drake's interface to the Python parser
372        exts.append( Extension('parser', ['parsermodule.c']) )
373
374        # cStringIO and cPickle
375        exts.append( Extension('cStringIO', ['cStringIO.c']) )
376        exts.append( Extension('cPickle', ['cPickle.c']) )
377
378        # Memory-mapped files (also works on Win32).
379        if platform not in ['atheos', 'mac']:
380            exts.append( Extension('mmap', ['mmapmodule.c']) )
381
382        # Lance Ellinghaus's modules:
383        # enigma-inspired encryption
384        exts.append( Extension('rotor', ['rotormodule.c']) )
385        if platform not in ['mac']:
386            # syslog daemon interface
387            exts.append( Extension('syslog', ['syslogmodule.c']) )
388
389        # George Neville-Neil's timing module:
390        exts.append( Extension('timing', ['timingmodule.c']) )
391
392        #
393        # Here ends the simple stuff.  From here on, modules need certain
394        # libraries, are platform-specific, or present other surprises.
395        #
396
397        # Multimedia modules
398        # These don't work for 64-bit platforms!!!
399        # These represent audio samples or images as strings:
400
401        # Disabled on 64-bit platforms
402        if sys.maxint != 9223372036854775807L:
403            # Operations on audio samples
404            exts.append( Extension('audioop', ['audioop.c']) )
405            # Operations on images
406            exts.append( Extension('imageop', ['imageop.c']) )
407            # Read SGI RGB image files (but coded portably)
408            exts.append( Extension('rgbimg', ['rgbimgmodule.c']) )
409
410        # readline
411        if self.compiler.find_library_file(lib_dirs, 'readline'):
412            readline_libs = ['readline']
413            if self.compiler.find_library_file(lib_dirs,
414                                                 'ncurses'):
415                readline_libs.append('ncurses')
416            elif self.compiler.find_library_file(lib_dirs, 'curses'):
417                readline_libs.append('curses')
418            elif self.compiler.find_library_file(lib_dirs +
419                                               ['/usr/lib/termcap'],
420                                               'termcap'):
421                readline_libs.append('termcap')
422            exts.append( Extension('readline', ['readline.c'],
423                                   library_dirs=['/usr/lib/termcap'],
424                                   libraries=readline_libs) )
425        if platform not in ['mac']:
426                # crypt module.
427
428            if self.compiler.find_library_file(lib_dirs, 'crypt'):
429                libs = ['crypt']
430            else:
431                libs = []
432            exts.append( Extension('crypt', ['cryptmodule.c'], libraries=libs) )
433
434        # CSV files
435        exts.append( Extension('_csv', ['_csv.c']) )
436
437        # socket(2)
438        exts.append( Extension('_socket', ['socketmodule.c'],
439                               depends = ['socketmodule.h']) )
440        # Detect SSL support for the socket module (via _ssl)
441        ssl_incs = find_file('openssl/ssl.h', inc_dirs,
442                             ['/usr/local/ssl/include',
443                              '/usr/contrib/ssl/include/'
444                             ]
445                             )
446        krb5_h = find_file('krb5.h', inc_dirs,
447                           ['/usr/kerberos/include'])
448        if krb5_h:
449            ssl_incs += krb5_h
450        ssl_libs = find_library_file(self.compiler, 'ssl',lib_dirs,
451                                     ['/usr/local/ssl/lib',
452                                      '/usr/contrib/ssl/lib/'
453                                     ] )
454
455        if (ssl_incs is not None and
456            ssl_libs is not None):
457            exts.append( Extension('_ssl', ['_ssl.c'],
458                                   include_dirs = ssl_incs,
459                                   library_dirs = ssl_libs,
460                                   libraries = ['ssl', 'crypto'],
461                                   depends = ['socketmodule.h']), )
462
463        # Modules that provide persistent dictionary-like semantics.  You will
464        # probably want to arrange for at least one of them to be available on
465        # your machine, though none are defined by default because of library
466        # dependencies.  The Python module anydbm.py provides an
467        # implementation independent wrapper for these; dumbdbm.py provides
468        # similar functionality (but slower of course) implemented in Python.
469
470        # Sleepycat Berkeley DB interface.  http://www.sleepycat.com
471        #
472        # This requires the Sleepycat DB code. The earliest supported version
473        # of that library is 3.0, the latest supported version is 4.1.  A list
474        # of available releases can be found at
475        #
476        # http://www.sleepycat.com/update/index.html
477
478        # when sorted in reverse order, keys for this dict must appear in the
479        # order you wish to search - e.g., search for db4 before db3
480        db_try_this = {
481            'db4': {'libs': ('db-4.1', 'db-4.0',),
482                    'libdirs': ('/usr/local/BerkeleyDB.4.1/lib',
483                                '/usr/local/BerkeleyDB.4.0/lib',
484                                '/usr/local/lib',
485                                '/opt/sfw',
486                                '/sw/lib',
487                                ),
488                    'incdirs': ('/usr/local/BerkeleyDB.4.1/include',
489                                '/usr/local/BerkeleyDB.4.0/include',
490                                '/usr/local/include/db4',
491                                '/opt/sfw/include/db4',
492                                '/sw/include/db4',
493                                '/usr/include/db4',
494                                )},
495            'db3': {'libs': ('db-3.3', 'db-3.2', 'db-3.1'),
496                    'libdirs': ('/usr/local/BerkeleyDB.3.3/lib',
497                                '/usr/local/BerkeleyDB.3.2/lib',
498                                '/usr/local/BerkeleyDB.3.1/lib',
499                                '/usr/local/lib',
500                                '/opt/sfw/lib',
501                                '/sw/lib',
502                                ),
503                    'incdirs': ('/usr/local/BerkeleyDB.3.3/include',
504                                '/usr/local/BerkeleyDB.3.2/include',
505                                '/usr/local/BerkeleyDB.3.1/include',
506                                '/usr/local/include/db3',
507                                '/opt/sfw/include/db3',
508                                '/sw/include/db3',
509                                '/usr/include/db3',
510                                )},
511            }
512
513        db_search_order = db_try_this.keys()
514        db_search_order.sort()
515        db_search_order.reverse()
516
517        class found(Exception): pass
518        try:
519            # See whether there is a Sleepycat header in the standard
520            # search path.
521            std_dbinc = None
522            for d in inc_dirs:
523                f = os.path.join(d, "db.h")
524                if os.path.exists(f):
525                    f = open(f).read()
526                    m = re.search(r"#define\WDB_VERSION_MAJOR\W([1-9]+)", f)
527                    if m:
528                        std_dbinc = 'db' + m.group(1)
529            for dbkey in db_search_order:
530                dbd = db_try_this[dbkey]
531                for dblib in dbd['libs']:
532                    # Prefer version-specific includes over standard
533                    # include locations.
534                    db_incs = find_file('db.h', [], dbd['incdirs'])
535                    dblib_dir = find_library_file(self.compiler,
536                                                  dblib,
537                                                  lib_dirs,
538                                                  list(dbd['libdirs']))
539                    if (db_incs or dbkey == std_dbinc) and \
540                           dblib_dir is not None:
541                        dblibs = [dblib]
542                        raise found
543        except found:
544            dblibs = [dblib]
545            # A default source build puts Berkeley DB in something like
546            # /usr/local/Berkeley.3.3 and the lib dir under that isn't
547            # normally on ld.so's search path, unless the sysadmin has hacked
548            # /etc/ld.so.conf.  We add the directory to runtime_library_dirs
549            # so the proper -R/--rpath flags get passed to the linker.  This
550            # is usually correct and most trouble free, but may cause problems
551            # in some unusual system configurations (e.g. the directory is on
552            # an NFS server that goes away).
553            exts.append(Extension('_bsddb', ['_bsddb.c'],
554                                  library_dirs=dblib_dir,
555                                  runtime_library_dirs=dblib_dir,
556                                  include_dirs=db_incs,
557                                  libraries=dblibs))
558        else:
559            db_incs = None
560            dblibs = []
561            dblib_dir = None
562
563        # The standard Unix dbm module:
564        if platform not in ['cygwin']:
565            if find_file("ndbm.h", inc_dirs, []) is not None:
566                # Some systems have -lndbm, others don't
567                if self.compiler.find_library_file(lib_dirs, 'ndbm'):
568                    ndbm_libs = ['ndbm']
569                else:
570                    ndbm_libs = []
571                exts.append( Extension('dbm', ['dbmmodule.c'],
572                                       define_macros=[('HAVE_NDBM_H',None)],
573                                       libraries = ndbm_libs ) )
574            elif (self.compiler.find_library_file(lib_dirs, 'gdbm')
575                  and find_file("gdbm/ndbm.h", inc_dirs, []) is not None):
576                exts.append( Extension('dbm', ['dbmmodule.c'],
577                                       define_macros=[('HAVE_GDBM_NDBM_H',None)],
578                                       libraries = ['gdbm'] ) )
579            elif db_incs is not None:
580                exts.append( Extension('dbm', ['dbmmodule.c'],
581                                       library_dirs=dblib_dir,
582                                       runtime_library_dirs=dblib_dir,
583                                       include_dirs=db_incs,
584                                       define_macros=[('HAVE_BERKDB_H',None),
585                                                      ('DB_DBM_HSEARCH',None)],
586                                       libraries=dblibs))
587
588        # Anthony Baxter's gdbm module.  GNU dbm(3) will require -lgdbm:
589        if (self.compiler.find_library_file(lib_dirs, 'gdbm')):
590            exts.append( Extension('gdbm', ['gdbmmodule.c'],
591                                   libraries = ['gdbm'] ) )
592
593        # The mpz module interfaces to the GNU Multiple Precision library.
594        # You need to ftp the GNU MP library.
595        # This was originally written and tested against GMP 1.2 and 1.3.2.
596        # It has been modified by Rob Hooft to work with 2.0.2 as well, but I
597        # haven't tested it recently, and it definitely doesn't work with
598        # GMP 4.0.  For more complete modules, refer to
599        # http://gmpy.sourceforge.net and
600        # http://www.egenix.com/files/python/mxNumber.html
601
602        # A compatible MP library unencumbered by the GPL also exists.  It was
603        # posted to comp.sources.misc in volume 40 and is widely available from
604        # FTP archive sites. One URL for it is:
605        # ftp://gatekeeper.dec.com/.b/usenet/comp.sources.misc/volume40/fgmp/part01.Z
606
607        if (self.compiler.find_library_file(lib_dirs, 'gmp')):
608            exts.append( Extension('mpz', ['mpzmodule.c'],
609                                   libraries = ['gmp'] ) )
610
611
612        # Unix-only modules
613        if platform not in ['mac', 'win32']:
614            # Steen Lumholt's termios module
615            exts.append( Extension('termios', ['termios.c']) )
616            # Jeremy Hylton's rlimit interface
617            if platform not in ['atheos']:
618                exts.append( Extension('resource', ['resource.c']) )
619
620            # Sun yellow pages. Some systems have the functions in libc.
621            if platform not in ['cygwin', 'atheos']:
622                if (self.compiler.find_library_file(lib_dirs, 'nsl')):
623                    libs = ['nsl']
624                else:
625                    libs = []
626                exts.append( Extension('nis', ['nismodule.c'],
627                                       libraries = libs) )
628
629        # Curses support, requring the System V version of curses, often
630        # provided by the ncurses library.
631        if platform == 'sunos4':
632            inc_dirs += ['/usr/5include']
633            lib_dirs += ['/usr/5lib']
634
635        if (self.compiler.find_library_file(lib_dirs, 'ncurses')):
636            curses_libs = ['ncurses']
637            exts.append( Extension('_curses', ['_cursesmodule.c'],
638                                   libraries = curses_libs) )
639        elif (self.compiler.find_library_file(lib_dirs, 'curses')
640              and platform != 'darwin'):
641                # OSX has an old Berkeley curses, not good enough for
642                # the _curses module.
643            if (self.compiler.find_library_file(lib_dirs, 'terminfo')):
644                curses_libs = ['curses', 'terminfo']
645            elif (self.compiler.find_library_file(lib_dirs, 'termcap')):
646                curses_libs = ['curses', 'termcap']
647            else:
648                curses_libs = ['curses']
649
650            exts.append( Extension('_curses', ['_cursesmodule.c'],
651                                   libraries = curses_libs) )
652
653        # If the curses module is enabled, check for the panel module
654        if (module_enabled(exts, '_curses') and
655            self.compiler.find_library_file(lib_dirs, 'panel')):
656            exts.append( Extension('_curses_panel', ['_curses_panel.c'],
657                                   libraries = ['panel'] + curses_libs) )
658
659
660        # Andrew Kuchling's zlib module.  Note that some versions of zlib
661        # 1.1.3 have security problems.  See CERT Advisory CA-2002-07:
662        # http://www.cert.org/advisories/CA-2002-07.html
663        #
664        # zlib 1.1.4 is fixed, but at least one vendor (RedHat) has decided to
665        # patch its zlib 1.1.3 package instead of upgrading to 1.1.4.  For
666        # now, we still accept 1.1.3, because we think it's difficult to
667        # exploit this in Python, and we'd rather make it RedHat's problem
668        # than our problem <wink>.
669        #
670        # You can upgrade zlib to version 1.1.4 yourself by going to
671        # http://www.gzip.org/zlib/
672        zlib_inc = find_file('zlib.h', [], inc_dirs)
673        if zlib_inc is not None:
674            zlib_h = zlib_inc[0] + '/zlib.h'
675            version = '"0.0.0"'
676            version_req = '"1.1.3"'
677            fp = open(zlib_h)
678            while 1:
679                line = fp.readline()
680                if not line:
681                    break
682                if line.startswith('#define ZLIB_VERSION'):
683                    version = line.split()[2]
684                    break
685            if version >= version_req:
686                if (self.compiler.find_library_file(lib_dirs, 'z')):
687                    exts.append( Extension('zlib', ['zlibmodule.c'],
688                                           libraries = ['z']) )
689
690        # Gustavo Niemeyer's bz2 module.
691        if (self.compiler.find_library_file(lib_dirs, 'bz2')):
692            exts.append( Extension('bz2', ['bz2module.c'],
693                                   libraries = ['bz2']) )
694
695        # Interface to the Expat XML parser
696        #
697        # Expat was written by James Clark and is now maintained by a
698        # group of developers on SourceForge; see www.libexpat.org for
699        # more information.  The pyexpat module was written by Paul
700        # Prescod after a prototype by Jack Jansen.  Source of Expat
701        # 1.95.2 is included in Modules/expat/.  Usage of a system
702        # shared libexpat.so/expat.dll is not advised.
703        #
704        # More information on Expat can be found at www.libexpat.org.
705        #
706        if sys.byteorder == "little":
707            xmlbo = "1234"
708        else:
709            xmlbo = "4321"
710        expatinc = os.path.join(os.getcwd(), srcdir, 'Modules', 'expat')
711        exts.append(Extension('pyexpat',
712                              sources = [
713            'pyexpat.c',
714            'expat/xmlparse.c',
715            'expat/xmlrole.c',
716            'expat/xmltok.c',
717            ],
718                              define_macros = [
719            ('XML_NS', '1'),
720            ('XML_DTD', '1'),
721            ('BYTEORDER', xmlbo),
722            ('XML_CONTEXT_BYTES','1024'),
723            ],
724                              include_dirs = [expatinc]
725                               ))
726
727        # Dynamic loading module
728        if sys.maxint == 0x7fffffff:
729            # This requires sizeof(int) == sizeof(long) == sizeof(char*)
730            dl_inc = find_file('dlfcn.h', [], inc_dirs)
731            if (dl_inc is not None) and (platform not in ['atheos', 'darwin']):
732                exts.append( Extension('dl', ['dlmodule.c']) )
733
734        # Platform-specific libraries
735        if platform == 'linux2':
736            # Linux-specific modules
737            exts.append( Extension('linuxaudiodev', ['linuxaudiodev.c']) )
738
739        if platform in ('linux2', 'freebsd4'):
740            exts.append( Extension('ossaudiodev', ['ossaudiodev.c']) )
741
742        if platform == 'sunos5':
743            # SunOS specific modules
744            exts.append( Extension('sunaudiodev', ['sunaudiodev.c']) )
745
746        if platform == 'darwin':
747            # Mac OS X specific modules.
748            exts.append( Extension('_CF', ['cf/_CFmodule.c', 'cf/pycfbridge.c'],
749                        extra_link_args=['-framework', 'CoreFoundation']) )
750
751            exts.append( Extension('autoGIL', ['autoGIL.c'],
752                        extra_link_args=['-framework', 'CoreFoundation']) )
753            exts.append( Extension('gestalt', ['gestaltmodule.c'],
754                        extra_link_args=['-framework', 'Carbon']) )
755            exts.append( Extension('MacOS', ['macosmodule.c'],
756                        extra_link_args=['-framework', 'Carbon']) )
757            exts.append( Extension('OSATerminology', ['OSATerminology.c'],
758                        extra_link_args=['-framework', 'Carbon']) )
759            exts.append( Extension('icglue', ['icgluemodule.c'],
760                        extra_link_args=['-framework', 'Carbon']) )
761            exts.append( Extension('_Res', ['res/_Resmodule.c'],
762                        extra_link_args=['-framework', 'Carbon']) )
763            exts.append( Extension('_Snd', ['snd/_Sndmodule.c'],
764                        extra_link_args=['-framework', 'Carbon']) )
765            exts.append( Extension('Nav', ['Nav.c'],
766                    extra_link_args=['-framework', 'Carbon']) )
767            exts.append( Extension('_AE', ['ae/_AEmodule.c'],
768                    extra_link_args=['-framework', 'Carbon']) )
769            exts.append( Extension('_AH', ['ah/_AHmodule.c'],
770                    extra_link_args=['-framework', 'Carbon']) )
771            exts.append( Extension('_App', ['app/_Appmodule.c'],
772                    extra_link_args=['-framework', 'Carbon']) )
773            exts.append( Extension('_CarbonEvt', ['carbonevt/_CarbonEvtmodule.c'],
774                    extra_link_args=['-framework', 'Carbon']) )
775            exts.append( Extension('_CG', ['cg/_CGmodule.c'],
776                    extra_link_args=['-framework', 'ApplicationServices']) )
777            exts.append( Extension('_Cm', ['cm/_Cmmodule.c'],
778                    extra_link_args=['-framework', 'Carbon']) )
779            exts.append( Extension('_Ctl', ['ctl/_Ctlmodule.c'],
780                    extra_link_args=['-framework', 'Carbon']) )
781            exts.append( Extension('_Dlg', ['dlg/_Dlgmodule.c'],
782                    extra_link_args=['-framework', 'Carbon']) )
783            exts.append( Extension('_Drag', ['drag/_Dragmodule.c'],
784                    extra_link_args=['-framework', 'Carbon']) )
785            exts.append( Extension('_Evt', ['evt/_Evtmodule.c'],
786                    extra_link_args=['-framework', 'Carbon']) )
787            exts.append( Extension('_File', ['file/_Filemodule.c'],
788                    extra_link_args=['-framework', 'Carbon']) )
789            exts.append( Extension('_Folder', ['folder/_Foldermodule.c'],
790                    extra_link_args=['-framework', 'Carbon']) )
791            exts.append( Extension('_Fm', ['fm/_Fmmodule.c'],
792                    extra_link_args=['-framework', 'Carbon']) )
793            exts.append( Extension('_Help', ['help/_Helpmodule.c'],
794                    extra_link_args=['-framework', 'Carbon']) )
795            exts.append( Extension('_Icn', ['icn/_Icnmodule.c'],
796                    extra_link_args=['-framework', 'Carbon']) )
797            exts.append( Extension('_IBCarbon', ['ibcarbon/_IBCarbon.c'],
798                    extra_link_args=['-framework', 'Carbon']) )
799            exts.append( Extension('_List', ['list/_Listmodule.c'],
800                    extra_link_args=['-framework', 'Carbon']) )
801            exts.append( Extension('_Menu', ['menu/_Menumodule.c'],
802                    extra_link_args=['-framework', 'Carbon']) )
803            exts.append( Extension('_Mlte', ['mlte/_Mltemodule.c'],
804                    extra_link_args=['-framework', 'Carbon']) )
805            exts.append( Extension('_Qd', ['qd/_Qdmodule.c'],
806                    extra_link_args=['-framework', 'Carbon']) )
807            exts.append( Extension('_Qdoffs', ['qdoffs/_Qdoffsmodule.c'],
808                    extra_link_args=['-framework', 'Carbon']) )
809            exts.append( Extension('_Qt', ['qt/_Qtmodule.c'],
810                    extra_link_args=['-framework', 'QuickTime',
811                                     '-framework', 'Carbon']) )
812            exts.append( Extension('_Scrap', ['scrap/_Scrapmodule.c'],
813                    extra_link_args=['-framework', 'Carbon']) )
814            exts.append( Extension('_TE', ['te/_TEmodule.c'],
815                    extra_link_args=['-framework', 'Carbon']) )
816            # As there is no standardized place (yet) to put
817            # user-installed Mac libraries on OSX, we search for "waste"
818            # in parent directories of the Python source tree. You
819            # should put a symlink to your Waste installation in the
820            # same folder as your python source tree.  Or modify the
821            # next few lines:-)
822            waste_incs = find_file("WASTE.h", [],
823                    ['../'*n + 'waste/C_C++ Headers' for n in (0,1,2,3,4)])
824            waste_libs = find_library_file(self.compiler, "WASTE", [],
825                    ["../"*n + "waste/Static Libraries" for n in (0,1,2,3,4)])
826            if waste_incs != None and waste_libs != None:
827                (srcdir,) = sysconfig.get_config_vars('srcdir')
828                exts.append( Extension('waste',
829                               ['waste/wastemodule.c'] + [
830                                os.path.join(srcdir, d) for d in
831                                'Mac/Wastemods/WEObjectHandlers.c',
832                                'Mac/Wastemods/WETabHooks.c',
833                                'Mac/Wastemods/WETabs.c'
834                               ],
835                               include_dirs = waste_incs + [os.path.join(srcdir, 'Mac/Wastemods')],
836                               library_dirs = waste_libs,
837                               libraries = ['WASTE'],
838                               extra_link_args = ['-framework', 'Carbon'],
839                ) )
840            exts.append( Extension('_Win', ['win/_Winmodule.c'],
841                    extra_link_args=['-framework', 'Carbon']) )
842
843        self.extensions.extend(exts)
844
845        # Call the method for detecting whether _tkinter can be compiled
846        self.detect_tkinter(inc_dirs, lib_dirs)
847
848    def detect_tkinter_darwin(self, inc_dirs, lib_dirs):
849        # The _tkinter module, using frameworks. Since frameworks are quite
850        # different the UNIX search logic is not sharable.
851        from os.path import join, exists
852        framework_dirs = [
853            '/System/Library/Frameworks/',
854            '/Library/Frameworks',
855            join(os.getenv('HOME'), '/Library/Frameworks')
856        ]
857
858        # Find the directory that contains the Tcl.framwork and Tk.framework
859        # bundles.
860        # XXX distutils should support -F!
861        for F in framework_dirs:
862            # both Tcl.framework and Tk.framework should be present
863            for fw in 'Tcl', 'Tk':
864                if not exists(join(F, fw + '.framework')):
865                    break
866            else:
867                # ok, F is now directory with both frameworks. Continure
868                # building
869                break
870        else:
871            # Tk and Tcl frameworks not found. Normal "unix" tkinter search
872            # will now resume.
873            return 0
874
875        # For 8.4a2, we must add -I options that point inside the Tcl and Tk
876        # frameworks. In later release we should hopefully be able to pass
877        # the -F option to gcc, which specifies a framework lookup path.
878        #
879        include_dirs = [
880            join(F, fw + '.framework', H)
881            for fw in 'Tcl', 'Tk'
882            for H in 'Headers', 'Versions/Current/PrivateHeaders'
883        ]
884
885        # For 8.4a2, the X11 headers are not included. Rather than include a
886        # complicated search, this is a hard-coded path. It could bail out
887        # if X11 libs are not found...
888        include_dirs.append('/usr/X11R6/include')
889        frameworks = ['-framework', 'Tcl', '-framework', 'Tk']
890
891        ext = Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
892                        define_macros=[('WITH_APPINIT', 1)],
893                        include_dirs = include_dirs,
894                        libraries = [],
895                        extra_compile_args = frameworks,
896                        extra_link_args = frameworks,
897                        )
898        self.extensions.append(ext)
899        return 1
900
901
902    def detect_tkinter(self, inc_dirs, lib_dirs):
903        # The _tkinter module.
904
905        # Rather than complicate the code below, detecting and building
906        # AquaTk is a separate method. Only one Tkinter will be built on
907        # Darwin - either AquaTk, if it is found, or X11 based Tk.
908        platform = self.get_platform()
909        if platform == 'darwin' and \
910           self.detect_tkinter_darwin(inc_dirs, lib_dirs):
911            return
912
913        # Assume we haven't found any of the libraries or include files
914        # The versions with dots are used on Unix, and the versions without
915        # dots on Windows, for detection by cygwin.
916        tcllib = tklib = tcl_includes = tk_includes = None
917        for version in ['8.4', '84', '8.3', '83', '8.2',
918                        '82', '8.1', '81', '8.0', '80']:
919            tklib = self.compiler.find_library_file(lib_dirs, 'tk' + version)
920            tcllib = self.compiler.find_library_file(lib_dirs, 'tcl' + version)
921            if tklib and tcllib:
922                # Exit the loop when we've found the Tcl/Tk libraries
923                break
924
925        # Now check for the header files
926        if tklib and tcllib:
927            # Check for the include files on Debian, where
928            # they're put in /usr/include/{tcl,tk}X.Y
929            debian_tcl_include = [ '/usr/include/tcl' + version ]
930            debian_tk_include =  [ '/usr/include/tk'  + version ] + \
931                                 debian_tcl_include
932            tcl_includes = find_file('tcl.h', inc_dirs, debian_tcl_include)
933            tk_includes = find_file('tk.h', inc_dirs, debian_tk_include)
934
935        if (tcllib is None or tklib is None and
936            tcl_includes is None or tk_includes is None):
937            # Something's missing, so give up
938            return
939
940        # OK... everything seems to be present for Tcl/Tk.
941
942        include_dirs = [] ; libs = [] ; defs = [] ; added_lib_dirs = []
943        for dir in tcl_includes + tk_includes:
944            if dir not in include_dirs:
945                include_dirs.append(dir)
946
947        # Check for various platform-specific directories
948        if platform == 'sunos5':
949            include_dirs.append('/usr/openwin/include')
950            added_lib_dirs.append('/usr/openwin/lib')
951        elif os.path.exists('/usr/X11R6/include'):
952            include_dirs.append('/usr/X11R6/include')
953            added_lib_dirs.append('/usr/X11R6/lib')
954        elif os.path.exists('/usr/X11R5/include'):
955            include_dirs.append('/usr/X11R5/include')
956            added_lib_dirs.append('/usr/X11R5/lib')
957        else:
958            # Assume default location for X11
959            include_dirs.append('/usr/X11/include')
960            added_lib_dirs.append('/usr/X11/lib')
961
962        # If Cygwin, then verify that X is installed before proceeding
963        if platform == 'cygwin':
964            x11_inc = find_file('X11/Xlib.h', [], include_dirs)
965            if x11_inc is None:
966                return
967
968        # Check for BLT extension
969        if self.compiler.find_library_file(lib_dirs + added_lib_dirs,
970                                           'BLT8.0'):
971            defs.append( ('WITH_BLT', 1) )
972            libs.append('BLT8.0')
973        elif self.compiler.find_library_file(lib_dirs + added_lib_dirs,
974                                           'BLT'):
975            defs.append( ('WITH_BLT', 1) )
976            libs.append('BLT')
977
978        # Add the Tcl/Tk libraries
979        libs.append('tk'+ version)
980        libs.append('tcl'+ version)
981
982        if platform in ['aix3', 'aix4']:
983            libs.append('ld')
984
985        # Finally, link with the X11 libraries (not appropriate on cygwin)
986        if platform != "cygwin":
987            libs.append('X11')
988
989        ext = Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
990                        define_macros=[('WITH_APPINIT', 1)] + defs,
991                        include_dirs = include_dirs,
992                        libraries = libs,
993                        library_dirs = added_lib_dirs,
994                        )
995        self.extensions.append(ext)
996
997##         # Uncomment these lines if you want to play with xxmodule.c
998##         ext = Extension('xx', ['xxmodule.c'])
999##         self.extensions.append(ext)
1000
1001        # XXX handle these, but how to detect?
1002        # *** Uncomment and edit for PIL (TkImaging) extension only:
1003        #       -DWITH_PIL -I../Extensions/Imaging/libImaging  tkImaging.c \
1004        # *** Uncomment and edit for TOGL extension only:
1005        #       -DWITH_TOGL togl.c \
1006        # *** Uncomment these for TOGL extension only:
1007        #       -lGL -lGLU -lXext -lXmu \
1008
1009class PyBuildInstall(install):
1010    # Suppress the warning about installation into the lib_dynload
1011    # directory, which is not in sys.path when running Python during
1012    # installation:
1013    def initialize_options (self):
1014        install.initialize_options(self)
1015        self.warn_dir=0
1016
1017class PyBuildInstallLib(install_lib):
1018    # Do exactly what install_lib does but make sure correct access modes get
1019    # set on installed directories and files. All installed files with get
1020    # mode 644 unless they are a shared library in which case they will get
1021    # mode 755. All installed directories will get mode 755.
1022
1023    so_ext = sysconfig.get_config_var("SO")
1024
1025    def install(self):
1026        outfiles = install_lib.install(self)
1027        self.set_file_modes(outfiles, 0644, 0755)
1028        self.set_dir_modes(self.install_dir, 0755)
1029        return outfiles
1030
1031    def set_file_modes(self, files, defaultMode, sharedLibMode):
1032        if not self.is_chmod_supported(): return
1033        if not files: return
1034
1035        for filename in files:
1036            if os.path.islink(filename): continue
1037            mode = defaultMode
1038            if filename.endswith(self.so_ext): mode = sharedLibMode
1039            log.info("changing mode of %s to %o", filename, mode)
1040            if not self.dry_run: os.chmod(filename, mode)
1041
1042    def set_dir_modes(self, dirname, mode):
1043        if not self.is_chmod_supported(): return
1044        os.path.walk(dirname, self.set_dir_modes_visitor, mode)
1045
1046    def set_dir_modes_visitor(self, mode, dirname, names):
1047        if os.path.islink(dirname): return
1048        log.info("changing mode of %s to %o", dirname, mode)
1049        if not self.dry_run: os.chmod(dirname, mode)
1050
1051    def is_chmod_supported(self):
1052        return hasattr(os, 'chmod')
1053
1054SUMMARY = """
1055Python is an interpreted, interactive, object-oriented programming
1056language. It is often compared to Tcl, Perl, Scheme or Java.
1057
1058Python combines remarkable power with very clear syntax. It has
1059modules, classes, exceptions, very high level dynamic data types, and
1060dynamic typing. There are interfaces to many system calls and
1061libraries, as well as to various windowing systems (X11, Motif, Tk,
1062Mac, MFC). New built-in modules are easily written in C or C++. Python
1063is also usable as an extension language for applications that need a
1064programmable interface.
1065
1066The Python implementation is portable: it runs on many brands of UNIX,
1067on Windows, DOS, OS/2, Mac, Amiga... If your favorite system isn't
1068listed here, it may still be supported, if there's a C compiler for
1069it. Ask around on comp.lang.python -- or just try compiling Python
1070yourself.
1071"""
1072
1073CLASSIFIERS = """
1074Development Status :: 3 - Alpha
1075Development Status :: 6 - Mature
1076License :: OSI Approved :: Python Software Foundation License
1077Natural Language :: English
1078Programming Language :: C
1079Programming Language :: Python
1080Topic :: Software Development
1081"""
1082
1083def main():
1084    # turn off warnings when deprecated modules are imported
1085    import warnings
1086    warnings.filterwarnings("ignore",category=DeprecationWarning)
1087    setup(# PyPI Metadata (PEP 301)
1088          name = "Python",
1089          version = sys.version.split()[0],
1090          url = "http://www.python.org/%s" % sys.version[:3],
1091          maintainer = "Guido van Rossum and the Python community",
1092          maintainer_email = "python-dev@python.org",
1093          description = "A high-level object-oriented programming language",
1094          long_description = SUMMARY.strip(),
1095          license = "PSF license",
1096          classifiers = filter(None, CLASSIFIERS.split("\n")),
1097          platforms = ["Many"],
1098
1099          # Build info
1100          cmdclass = {'build_ext':PyBuildExt, 'install':PyBuildInstall,
1101                      'install_lib':PyBuildInstallLib},
1102          # The struct module is defined here, because build_ext won't be
1103          # called unless there's at least one extension module defined.
1104          ext_modules=[Extension('struct', ['structmodule.c'])],
1105
1106          # Scripts to install
1107          scripts = ['Tools/scripts/pydoc']
1108        )
1109
1110# --install-platlib
1111if __name__ == '__main__':
1112    main()
1113