~ubuntu-branches/ubuntu/wily/python-imaging/wily

« back to all changes in this revision

Viewing changes to .pc/toplevel-setup.py/setup.py

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2013-01-31 20:49:20 UTC
  • mfrom: (1.1.4)
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130131204920-7tnuhqhlsqdza4c2
Rewrite build dependencies to allow cross builds.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
from __future__ import print_function
 
2
import glob
 
3
import os
 
4
import platform
 
5
import re
 
6
import struct
 
7
import sys
 
8
 
 
9
from distutils.command.build_ext import build_ext
 
10
from distutils import sysconfig
 
11
from setuptools import Extension, setup, find_packages
 
12
 
 
13
 
 
14
_IMAGING = (
 
15
    "decode", "encode", "map", "display", "outline", "path",
 
16
    )
 
17
 
 
18
_LIB_IMAGING = (
 
19
    "Access", "AlphaComposite", "Antialias", "Bands", "BitDecode", "Blend",
 
20
    "Chops", "Convert", "ConvertYCbCr", "Copy", "Crc32", "Crop", "Dib", "Draw",
 
21
    "Effects", "EpsEncode", "File", "Fill", "Filter", "FliDecode",
 
22
    "Geometry", "GetBBox", "GifDecode", "GifEncode", "HexDecode",
 
23
    "Histo", "JpegDecode", "JpegEncode", "LzwDecode", "Matrix",
 
24
    "ModeFilter", "MspDecode", "Negative", "Offset", "Pack",
 
25
    "PackDecode", "Palette", "Paste", "Quant", "QuantHash",
 
26
    "QuantHeap", "PcdDecode", "PcxDecode", "PcxEncode", "Point",
 
27
    "RankFilter", "RawDecode", "RawEncode", "Storage", "SunRleDecode",
 
28
    "TgaRleDecode", "Unpack", "UnpackYCC", "UnsharpMask", "XbmDecode",
 
29
    "XbmEncode", "ZipDecode", "ZipEncode")
 
30
 
 
31
 
 
32
def _add_directory(path, dir, where=None):
 
33
    if dir and os.path.isdir(dir) and dir not in path:
 
34
        if where is None:
 
35
            path.append(dir)
 
36
        else:
 
37
            path.insert(where, dir)
 
38
 
 
39
 
 
40
def _find_include_file(self, include):
 
41
    for directory in self.compiler.include_dirs:
 
42
        if os.path.isfile(os.path.join(directory, include)):
 
43
            return 1
 
44
    return 0
 
45
 
 
46
 
 
47
def _find_library_file(self, library):
 
48
    return self.compiler.find_library_file(self.compiler.library_dirs, library)
 
49
 
 
50
 
 
51
def _find_version(filename):
 
52
    for line in open(filename).readlines():
 
53
        m = re.search("VERSION\s*=\s*\"([^\"]+)\"", line)
 
54
        if m:
 
55
            return m.group(1)
 
56
    return None
 
57
 
 
58
 
 
59
def _lib_include(root):
 
60
    # map root to (root/lib, root/include)
 
61
    return os.path.join(root, "lib"), os.path.join(root, "include")
 
62
 
 
63
 
 
64
def _read(file):
 
65
    return open(file, 'rb').read()
 
66
 
 
67
try:
 
68
    import _tkinter
 
69
except ImportError:
 
70
    _tkinter = None
 
71
 
 
72
 
 
73
NAME = 'Pillow'
 
74
VERSION = '1.7.8'
 
75
PIL_VERSION = '1.1.7'
 
76
TCL_ROOT = None
 
77
JPEG_ROOT = None
 
78
ZLIB_ROOT = None
 
79
TIFF_ROOT = None
 
80
FREETYPE_ROOT = None
 
81
LCMS_ROOT = None
 
82
 
 
83
 
 
84
class pil_build_ext(build_ext):
 
85
 
 
86
    def build_extensions(self):
 
87
 
 
88
        global TCL_ROOT
 
89
 
 
90
        library_dirs = []
 
91
        include_dirs = []
 
92
 
 
93
        _add_directory(include_dirs, "libImaging")
 
94
 
 
95
        #
 
96
        # add configured kits
 
97
 
 
98
        for root in (TCL_ROOT, JPEG_ROOT, TCL_ROOT, TIFF_ROOT, ZLIB_ROOT,
 
99
                     FREETYPE_ROOT, LCMS_ROOT):
 
100
            if isinstance(root, type(())):
 
101
                lib_root, include_root = root
 
102
            else:
 
103
                lib_root = include_root = root
 
104
            _add_directory(library_dirs, lib_root)
 
105
            _add_directory(include_dirs, include_root)
 
106
 
 
107
        #
 
108
        # add platform directories
 
109
 
 
110
        if sys.platform == "cygwin":
 
111
            # pythonX.Y.dll.a is in the /usr/lib/pythonX.Y/config directory
 
112
            _add_directory(library_dirs, os.path.join(
 
113
                "/usr/lib", "python%s" % sys.version[:3], "config"))
 
114
 
 
115
        elif sys.platform == "darwin":
 
116
            # attempt to make sure we pick freetype2 over other versions
 
117
            _add_directory(include_dirs, "/sw/include/freetype2")
 
118
            _add_directory(include_dirs, "/sw/lib/freetype2/include")
 
119
            # fink installation directories
 
120
            _add_directory(library_dirs, "/sw/lib")
 
121
            _add_directory(include_dirs, "/sw/include")
 
122
            # darwin ports installation directories
 
123
            _add_directory(library_dirs, "/opt/local/lib")
 
124
            _add_directory(include_dirs, "/opt/local/include")
 
125
            # freetype2 ships with X11
 
126
            _add_directory(library_dirs, "/usr/X11/lib")
 
127
            _add_directory(include_dirs, "/usr/X11/include")
 
128
 
 
129
        elif sys.platform.startswith("linux"):
 
130
            # XXX Kludge. Above /\ we brute force support multiarch. Here we
 
131
            # try Barry's more general approach. Afterward, something should
 
132
            # work ;-)
 
133
            self.add_multiarch_paths()
 
134
 
 
135
        _add_directory(library_dirs, "/usr/local/lib")
 
136
        # FIXME: check /opt/stuff directories here?
 
137
 
 
138
        prefix = sysconfig.get_config_var("prefix")
 
139
        if prefix:
 
140
            _add_directory(library_dirs, os.path.join(prefix, "lib"))
 
141
            _add_directory(include_dirs, os.path.join(prefix, "include"))
 
142
 
 
143
        #
 
144
        # locate tkinter libraries
 
145
 
 
146
        if _tkinter:
 
147
            TCL_VERSION = _tkinter.TCL_VERSION[:3]
 
148
 
 
149
        if _tkinter and not TCL_ROOT:
 
150
            # we have Tkinter but the TCL_ROOT variable was not set;
 
151
            # try to locate appropriate Tcl/Tk libraries
 
152
            PYVERSION = sys.version[0] + sys.version[2]
 
153
            TCLVERSION = TCL_VERSION[0] + TCL_VERSION[2]
 
154
            roots = [
 
155
                # common installation directories, mostly for Windows
 
156
                # (for Unix-style platforms, we'll check in well-known
 
157
                # locations later)
 
158
                os.path.join("/py" + PYVERSION, "Tcl"),
 
159
                os.path.join("/python" + PYVERSION, "Tcl"),
 
160
                "/Tcl", "/Tcl" + TCLVERSION, "/Tcl" + TCL_VERSION,
 
161
                os.path.join(os.environ.get("ProgramFiles", ""), "Tcl"),
 
162
                ]
 
163
            for TCL_ROOT in roots:
 
164
                TCL_ROOT = os.path.abspath(TCL_ROOT)
 
165
                if os.path.isfile(os.path.join(TCL_ROOT, "include", "tk.h")):
 
166
                    # FIXME: use distutils logging (?)
 
167
                    print("--- using Tcl/Tk libraries at", TCL_ROOT)
 
168
                    print("--- using Tcl/Tk version", TCL_VERSION)
 
169
                    TCL_ROOT = _lib_include(TCL_ROOT)
 
170
                    break
 
171
            else:
 
172
                TCL_ROOT = None
 
173
 
 
174
        #
 
175
        # add standard directories
 
176
 
 
177
        # look for tcl specific subdirectory (e.g debian)
 
178
        if _tkinter:
 
179
            tcl_dir = "/usr/include/tcl" + TCL_VERSION
 
180
            if os.path.isfile(os.path.join(tcl_dir, "tk.h")):
 
181
                _add_directory(include_dirs, tcl_dir)
 
182
 
 
183
        # standard locations
 
184
        _add_directory(library_dirs, "/usr/local/lib")
 
185
        _add_directory(include_dirs, "/usr/local/include")
 
186
 
 
187
        _add_directory(library_dirs, "/usr/lib")
 
188
        _add_directory(include_dirs, "/usr/include")
 
189
 
 
190
        #
 
191
        # insert new dirs *before* default libs, to avoid conflicts
 
192
        # between Python PYD stub libs and real libraries
 
193
 
 
194
        self.compiler.library_dirs = library_dirs + self.compiler.library_dirs
 
195
        self.compiler.include_dirs = include_dirs + self.compiler.include_dirs
 
196
 
 
197
        #
 
198
        # look for available libraries
 
199
 
 
200
        class feature:
 
201
            zlib = jpeg = tiff = freetype = tcl = tk = lcms = None
 
202
        feature = feature()
 
203
 
 
204
        if _find_include_file(self, "zlib.h"):
 
205
            if _find_library_file(self, "z"):
 
206
                feature.zlib = "z"
 
207
            elif sys.platform == "win32" and _find_library_file(self, "zlib"):
 
208
                feature.zlib = "zlib"  # alternative name
 
209
 
 
210
        if _find_include_file(self, "jpeglib.h"):
 
211
            if _find_library_file(self, "jpeg"):
 
212
                feature.jpeg = "jpeg"
 
213
            elif sys.platform == "win32" and _find_library_file(self,
 
214
                    "libjpeg"):
 
215
                feature.jpeg = "libjpeg"  # alternative name
 
216
 
 
217
        if _find_library_file(self, "tiff"):
 
218
            feature.tiff = "tiff"
 
219
 
 
220
        if _find_library_file(self, "freetype"):
 
221
            # look for freetype2 include files
 
222
            freetype_version = 0
 
223
            for dir in self.compiler.include_dirs:
 
224
                if os.path.isfile(os.path.join(dir, "ft2build.h")):
 
225
                    freetype_version = 21
 
226
                    dir = os.path.join(dir, "freetype2")
 
227
                    break
 
228
                dir = os.path.join(dir, "freetype2")
 
229
                if os.path.isfile(os.path.join(dir, "ft2build.h")):
 
230
                    freetype_version = 21
 
231
                    break
 
232
                if os.path.isdir(os.path.join(dir, "freetype")):
 
233
                    freetype_version = 20
 
234
                    break
 
235
            if freetype_version:
 
236
                feature.freetype = "freetype"
 
237
                feature.freetype_version = freetype_version
 
238
                if dir:
 
239
                    _add_directory(self.compiler.include_dirs, dir, 0)
 
240
 
 
241
        if _find_include_file(self, "lcms.h"):
 
242
            if _find_library_file(self, "lcms"):
 
243
                feature.lcms = "lcms"
 
244
 
 
245
        if _tkinter and _find_include_file(self, "tk.h"):
 
246
            # the library names may vary somewhat (e.g. tcl84 or tcl8.4)
 
247
            version = TCL_VERSION[0] + TCL_VERSION[2]
 
248
            if _find_library_file(self, "tcl" + version):
 
249
                feature.tcl = "tcl" + version
 
250
            elif _find_library_file(self, "tcl" + TCL_VERSION):
 
251
                feature.tcl = "tcl" + TCL_VERSION
 
252
            if _find_library_file(self, "tk" + version):
 
253
                feature.tk = "tk" + version
 
254
            elif _find_library_file(self, "tk" + TCL_VERSION):
 
255
                feature.tk = "tk" + TCL_VERSION
 
256
 
 
257
        #
 
258
        # core library
 
259
 
 
260
        files = ["_imaging.c"]
 
261
        for file in _IMAGING:
 
262
            files.append(file + ".c")
 
263
        for file in _LIB_IMAGING:
 
264
            files.append(os.path.join("libImaging", file + ".c"))
 
265
 
 
266
        libs = []
 
267
        defs = []
 
268
        if feature.jpeg:
 
269
            libs.append(feature.jpeg)
 
270
            defs.append(("HAVE_LIBJPEG", None))
 
271
        if feature.zlib:
 
272
            libs.append(feature.zlib)
 
273
            defs.append(("HAVE_LIBZ", None))
 
274
        if sys.platform == "win32":
 
275
            libs.extend(["kernel32", "user32", "gdi32"])
 
276
        if struct.unpack("h", "\0\1".encode('ascii'))[0] == 1:
 
277
            defs.append(("WORDS_BIGENDIAN", None))
 
278
 
 
279
        exts = [(Extension(
 
280
            "_imaging", files, libraries=libs, define_macros=defs))]
 
281
 
 
282
        #
 
283
        # additional libraries
 
284
 
 
285
        if feature.freetype:
 
286
            defs = []
 
287
            if feature.freetype_version == 20:
 
288
                defs.append(("USE_FREETYPE_2_0", None))
 
289
            exts.append(Extension(
 
290
                "_imagingft", ["_imagingft.c"], libraries=["freetype"],
 
291
                define_macros=defs))
 
292
 
 
293
        if os.path.isfile("_imagingtiff.c") and feature.tiff:
 
294
            exts.append(Extension(
 
295
                "_imagingtiff", ["_imagingtiff.c"], libraries=["tiff"]))
 
296
 
 
297
        if os.path.isfile("_imagingcms.c") and feature.lcms:
 
298
            extra = []
 
299
            if sys.platform == "win32":
 
300
                extra.extend(["user32", "gdi32"])
 
301
            exts.append(Extension(
 
302
                "_imagingcms", ["_imagingcms.c"], libraries=["lcms"] + extra))
 
303
 
 
304
        if sys.platform == "darwin":
 
305
            # locate Tcl/Tk frameworks
 
306
            frameworks = []
 
307
            framework_roots = [
 
308
                "/Library/Frameworks",
 
309
                "/System/Library/Frameworks"]
 
310
            for root in framework_roots:
 
311
                if (os.path.exists(os.path.join(root, "Tcl.framework")) and
 
312
                    os.path.exists(os.path.join(root, "Tk.framework"))):
 
313
                    print("--- using frameworks at %s" % root)
 
314
                    frameworks = ["-framework", "Tcl", "-framework", "Tk"]
 
315
                    dir = os.path.join(root, "Tcl.framework", "Headers")
 
316
                    _add_directory(self.compiler.include_dirs, dir, 0)
 
317
                    dir = os.path.join(root, "Tk.framework", "Headers")
 
318
                    _add_directory(self.compiler.include_dirs, dir, 1)
 
319
                    break
 
320
            if frameworks:
 
321
                exts.append(Extension(
 
322
                    "_imagingtk", ["_imagingtk.c", "Tk/tkImaging.c"],
 
323
                    extra_compile_args=frameworks, extra_link_args=frameworks))
 
324
                feature.tcl = feature.tk = 1  # mark as present
 
325
        elif feature.tcl and feature.tk:
 
326
            exts.append(Extension(
 
327
                "_imagingtk", ["_imagingtk.c", "Tk/tkImaging.c"],
 
328
                libraries=[feature.tcl, feature.tk]))
 
329
 
 
330
        if os.path.isfile("_imagingmath.c"):
 
331
            exts.append(Extension("_imagingmath", ["_imagingmath.c"]))
 
332
 
 
333
        self.extensions[:] = exts
 
334
 
 
335
        build_ext.build_extensions(self)
 
336
 
 
337
        #
 
338
        # sanity and security checks
 
339
 
 
340
        unsafe_zlib = None
 
341
 
 
342
        if feature.zlib:
 
343
            unsafe_zlib = self.check_zlib_version(self.compiler.include_dirs)
 
344
 
 
345
        self.summary_report(feature, unsafe_zlib)
 
346
 
 
347
    def summary_report(self, feature, unsafe_zlib):
 
348
 
 
349
        print("-" * 68)
 
350
        print("SETUP SUMMARY (Pillow %s / PIL %s)" % (VERSION, PIL_VERSION))
 
351
        print("-" * 68)
 
352
        print("version      %s" % VERSION)
 
353
        v = sys.version.split("[")
 
354
        print("platform     %s %s" % (sys.platform, v[0].strip()))
 
355
        for v in v[1:]:
 
356
            print("             [%s" % v.strip())
 
357
        print("-" * 68)
 
358
 
 
359
        options = [
 
360
            (feature.tcl and feature.tk, "TKINTER"),
 
361
            (feature.jpeg, "JPEG"),
 
362
            (feature.zlib, "ZLIB (PNG/ZIP)"),
 
363
            # (feature.tiff, "experimental TIFF G3/G4 read"),
 
364
            (feature.freetype, "FREETYPE2"),
 
365
            (feature.lcms, "LITTLECMS"),
 
366
            ]
 
367
 
 
368
        all = 1
 
369
        for option in options:
 
370
            if option[0]:
 
371
                print("--- %s support available" % option[1])
 
372
            else:
 
373
                print("*** %s support not available" % option[1])
 
374
                if option[1] == "TKINTER" and _tkinter:
 
375
                    version = _tkinter.TCL_VERSION
 
376
                    print("(Tcl/Tk %s libraries needed)" % version)
 
377
                print("")
 
378
                all = 0
 
379
 
 
380
        if feature.zlib and unsafe_zlib:
 
381
            print("")
 
382
            print("*** Warning: zlib", unsafe_zlib)
 
383
            print("may contain a security vulnerability.")
 
384
            print("*** Consider upgrading to zlib 1.2.3 or newer.")
 
385
            print("*** See: http://www.kb.cert.org/vuls/id/238678")
 
386
            print(" http://www.kb.cert.org/vuls/id/680620")
 
387
            print(" http://www.gzip.org/zlib/advisory-2002-03-11.txt")
 
388
            print("")
 
389
 
 
390
        print("-" * 68)
 
391
 
 
392
        if not all:
 
393
            print("To add a missing option, make sure you have the required")
 
394
            print("library, and set the corresponding ROOT variable in the")
 
395
            print("setup.py script.")
 
396
            print("\n")
 
397
 
 
398
        print("To check the build, run the selftest.py script.")
 
399
 
 
400
    def check_zlib_version(self, include_dirs):
 
401
        # look for unsafe versions of zlib
 
402
        for dir in include_dirs:
 
403
            zlibfile = os.path.join(dir, "zlib.h")
 
404
            if os.path.isfile(zlibfile):
 
405
                break
 
406
        else:
 
407
            return
 
408
        for line in open(zlibfile).readlines():
 
409
            m = re.match('#define\s+ZLIB_VERSION\s+"([^"]*)"', line)
 
410
            if not m:
 
411
                continue
 
412
            if m.group(1) < "1.2.3":
 
413
                return m.group(1)
 
414
 
 
415
    # http://hg.python.org/users/barry/rev/7e8deab93d5a
 
416
    def add_multiarch_paths(self):
 
417
        # Debian/Ubuntu multiarch support.
 
418
        # https://wiki.ubuntu.com/MultiarchSpec
 
419
        # self.build_temp
 
420
        tmpfile = os.path.join(self.build_temp, 'multiarch')
 
421
        if not os.path.exists(self.build_temp):
 
422
            os.makedirs(self.build_temp)
 
423
        ret = os.system('dpkg-architecture -qDEB_HOST_MULTIARCH > %s' %
 
424
                        tmpfile)
 
425
        ret = os.system(
 
426
            'dpkg-architecture -qDEB_HOST_MULTIARCH > %s 2> /dev/null' %
 
427
            tmpfile)
 
428
        try:
 
429
            if ret >> 8 == 0:
 
430
                fp = open(tmpfile, 'r')
 
431
                multiarch_path_component = fp.readline().strip()
 
432
                _add_directory(self.compiler.library_dirs,
 
433
                    '/usr/lib/' + multiarch_path_component)
 
434
                _add_directory(self.compiler.include_dirs,
 
435
                    '/usr/include/' + multiarch_path_component)
 
436
        finally:
 
437
            os.unlink(tmpfile)
 
438
 
 
439
setup(
 
440
    name=NAME,
 
441
    version=VERSION,
 
442
    description='Python Imaging Library (fork)',
 
443
    long_description=(
 
444
        _read('README.rst') +
 
445
        _read('docs/INSTALL.txt') +
 
446
        _read('docs/HISTORY.txt')).decode('utf-8'),
 
447
    author='Alex Clark (fork author)',
 
448
    author_email='aclark@aclark.net',
 
449
    url='http://github.com/python-imaging/Pillow',
 
450
    classifiers=[
 
451
        "Development Status :: 6 - Mature",
 
452
        "Topic :: Multimedia :: Graphics",
 
453
        "Topic :: Multimedia :: Graphics :: Capture :: Digital Camera",
 
454
        "Topic :: Multimedia :: Graphics :: Capture :: Scanners",
 
455
        "Topic :: Multimedia :: Graphics :: Capture :: Screen Capture",
 
456
        "Topic :: Multimedia :: Graphics :: Graphics Conversion",
 
457
        "Topic :: Multimedia :: Graphics :: Viewers",
 
458
        "Programming Language :: Python :: 2",
 
459
        "Programming Language :: Python :: 2.6",
 
460
        "Programming Language :: Python :: 2.7",
 
461
        "Programming Language :: Python :: 3",
 
462
        "Programming Language :: Python :: 3.2",
 
463
        "Programming Language :: Python :: 3.3",
 
464
        ],
 
465
    cmdclass={"build_ext": pil_build_ext},
 
466
    ext_modules=[Extension("_imaging", ["_imaging.c"])],
 
467
    packages=find_packages(),
 
468
    scripts=glob.glob("Scripts/pil*.py"),
 
469
    )