Pillow/setup.py
2014-03-31 18:59:29 +00:00

683 lines
26 KiB
Python

# > pyroma .
# ------------------------------
# Checking .
# Found Pillow
# ------------------------------
# Final rating: 10/10
# Your cheese is so fresh most people think it's a cream: Mascarpone
# ------------------------------
from __future__ import print_function
import glob
import os
import platform as plat
import re
import struct
import sys
from distutils.command.build_ext import build_ext
from distutils import sysconfig
from setuptools import Extension, setup, find_packages
_IMAGING = (
"decode", "encode", "map", "display", "outline", "path")
_LIB_IMAGING = (
"Access", "AlphaComposite", "Antialias", "Bands", "BitDecode", "Blend",
"Chops", "Convert", "ConvertYCbCr", "Copy", "Crc32", "Crop", "Dib", "Draw",
"Effects", "EpsEncode", "File", "Fill", "Filter", "FliDecode",
"Geometry", "GetBBox", "GifDecode", "GifEncode", "HexDecode",
"Histo", "JpegDecode", "JpegEncode", "LzwDecode", "Matrix",
"ModeFilter", "MspDecode", "Negative", "Offset", "Pack",
"PackDecode", "Palette", "Paste", "Quant", "QuantOctree", "QuantHash",
"QuantHeap", "PcdDecode", "PcxDecode", "PcxEncode", "Point",
"RankFilter", "RawDecode", "RawEncode", "Storage", "SunRleDecode",
"TgaRleDecode", "Unpack", "UnpackYCC", "UnsharpMask", "XbmDecode",
"XbmEncode", "ZipDecode", "ZipEncode", "TiffDecode", "Incremental",
"Jpeg2KDecode", "Jpeg2KEncode")
def _add_directory(path, dir, where=None):
if dir is None:
return
dir = os.path.realpath(dir)
if os.path.isdir(dir) and dir not in path:
if where is None:
path.append(dir)
else:
path.insert(where, dir)
def _find_include_file(self, include):
for directory in self.compiler.include_dirs:
if os.path.isfile(os.path.join(directory, include)):
return 1
return 0
def _find_library_file(self, library):
# Fix for 3.2.x <3.2.4, 3.3.0, shared lib extension is the python shared
# lib extension, not the system shared lib extension: e.g. .cpython-33.so
# vs .so. See Python bug http://bugs.python.org/16754
if 'cpython' in self.compiler.shared_lib_extension:
existing = self.compiler.shared_lib_extension
self.compiler.shared_lib_extension = "." + existing.split('.')[-1]
ret = self.compiler.find_library_file(
self.compiler.library_dirs, library)
self.compiler.shared_lib_extension = existing
return ret
else:
return self.compiler.find_library_file(
self.compiler.library_dirs, library)
def _lib_include(root):
# map root to (root/lib, root/include)
return os.path.join(root, "lib"), os.path.join(root, "include")
def _read(file):
return open(file, 'rb').read()
try:
import _tkinter
except (ImportError, OSError):
# pypy emits an oserror
_tkinter = None
NAME = 'Pillow'
VERSION = '2.3.0'
TCL_ROOT = None
JPEG_ROOT = None
JPEG2K_ROOT = None
ZLIB_ROOT = None
TIFF_ROOT = None
FREETYPE_ROOT = None
LCMS_ROOT = None
class pil_build_ext(build_ext):
class feature:
zlib = jpeg = tiff = freetype = tcl = tk = lcms = webp = webpmux = None
jpeg2000 = None
required = []
def require(self, feat):
return feat in self.required
def want(self, feat):
return getattr(self, feat) is None
def __iter__(self):
for x in dir(self):
if x[1] != '_':
yield x
feature = feature()
user_options = build_ext.user_options + [
('disable-%s' % x, None, 'Disable support for %s' % x)
for x in feature
] + [
('enable-%s' % x, None, 'Enable support for %s' % x)
for x in feature
]
def initialize_options(self):
build_ext.initialize_options(self)
for x in self.feature:
setattr(self, 'disable_%s' % x, None)
setattr(self, 'enable_%s' % x, None)
def finalize_options(self):
build_ext.finalize_options(self)
for x in self.feature:
if getattr(self, 'disable_%s' % x):
setattr(self.feature, x, False)
if getattr(self, 'enable_%s' % x):
raise ValueError(
'Conflicting options: --enable-%s and --disable-%s'
% (x, x))
if getattr(self, 'enable_%s' % x):
self.feature.required.append(x)
def build_extensions(self):
global TCL_ROOT
library_dirs = []
include_dirs = []
_add_directory(include_dirs, "libImaging")
#
# add configured kits
for root in (TCL_ROOT, JPEG_ROOT, JPEG2K_ROOT, TIFF_ROOT, ZLIB_ROOT,
FREETYPE_ROOT, LCMS_ROOT):
if isinstance(root, type(())):
lib_root, include_root = root
else:
lib_root = include_root = root
_add_directory(library_dirs, lib_root)
_add_directory(include_dirs, include_root)
# respect CFLAGS/LDFLAGS
for k in ('CFLAGS', 'LDFLAGS'):
if k in os.environ:
for match in re.finditer(r'-I([^\s]+)', os.environ[k]):
_add_directory(include_dirs, match.group(1))
for match in re.finditer(r'-L([^\s]+)', os.environ[k]):
_add_directory(library_dirs, match.group(1))
# include, rpath, if set as environment variables:
for k in ('C_INCLUDE_PATH', 'CPATH', 'INCLUDE'):
if k in os.environ:
for d in os.environ[k].split(os.path.pathsep):
_add_directory(include_dirs, d)
for k in ('LD_RUN_PATH', 'LIBRARY_PATH', 'LIB'):
if k in os.environ:
for d in os.environ[k].split(os.path.pathsep):
_add_directory(library_dirs, d)
prefix = sysconfig.get_config_var("prefix")
if prefix:
_add_directory(library_dirs, os.path.join(prefix, "lib"))
_add_directory(include_dirs, os.path.join(prefix, "include"))
#
# add platform directories
if sys.platform == "cygwin":
# pythonX.Y.dll.a is in the /usr/lib/pythonX.Y/config directory
_add_directory(library_dirs, os.path.join(
"/usr/lib", "python%s" % sys.version[:3], "config"))
elif sys.platform == "darwin":
# attempt to make sure we pick freetype2 over other versions
_add_directory(include_dirs, "/sw/include/freetype2")
_add_directory(include_dirs, "/sw/lib/freetype2/include")
# fink installation directories
_add_directory(library_dirs, "/sw/lib")
_add_directory(include_dirs, "/sw/include")
# darwin ports installation directories
_add_directory(library_dirs, "/opt/local/lib")
_add_directory(include_dirs, "/opt/local/include")
# if homebrew is installed, use its lib and include directories
import subprocess
try:
prefix = subprocess.check_output(['brew', '--prefix'])
if prefix:
prefix = prefix.strip()
_add_directory(library_dirs, os.path.join(prefix, 'lib'))
_add_directory(include_dirs, os.path.join(prefix, 'include'))
# freetype2 is a key-only brew under opt/
_add_directory(library_dirs, os.path.join(prefix, 'opt', 'freetype', 'lib'))
_add_directory(include_dirs, os.path.join(prefix, 'opt', 'freetype', 'include'))
except:
pass # homebrew not installed
# freetype2 ships with X11 (after homebrew, so that homebrew freetype is preferred)
_add_directory(library_dirs, "/usr/X11/lib")
_add_directory(include_dirs, "/usr/X11/include")
elif sys.platform.startswith("linux"):
arch_tp = (plat.processor(), plat.architecture()[0])
if arch_tp == ("x86_64","32bit"):
# 32 bit build on 64 bit machine.
_add_directory(library_dirs, "/usr/lib/i386-linux-gnu")
else:
for platform_ in arch_tp:
if not platform_:
continue
if platform_ in ["x86_64", "64bit"]:
_add_directory(library_dirs, "/lib64")
_add_directory(library_dirs, "/usr/lib64")
_add_directory(library_dirs, "/usr/lib/x86_64-linux-gnu")
break
elif platform_ in ["i386", "i686", "32bit"]:
_add_directory(library_dirs, "/usr/lib/i386-linux-gnu")
break
elif platform_ in ["aarch64"]:
_add_directory(library_dirs, "/usr/lib64")
_add_directory(library_dirs, "/usr/lib/aarch64-linux-gnu")
break
elif platform_ in ["arm", "armv7l"]:
_add_directory(library_dirs, "/usr/lib/arm-linux-gnueabi")
break
elif platform_ in ["ppc64"]:
_add_directory(library_dirs, "/usr/lib64")
_add_directory(library_dirs, "/usr/lib/ppc64-linux-gnu")
_add_directory(library_dirs, "/usr/lib/powerpc64-linux-gnu")
break
elif platform_ in ["ppc"]:
_add_directory(library_dirs, "/usr/lib/ppc-linux-gnu")
_add_directory(library_dirs, "/usr/lib/powerpc-linux-gnu")
break
elif platform_ in ["s390x"]:
_add_directory(library_dirs, "/usr/lib64")
_add_directory(library_dirs, "/usr/lib/s390x-linux-gnu")
break
elif platform_ in ["s390"]:
_add_directory(library_dirs, "/usr/lib/s390-linux-gnu")
break
else:
raise ValueError(
"Unable to identify Linux platform: `%s`" % platform_)
# XXX Kludge. Above /\ we brute force support multiarch. Here we
# try Barry's more general approach. Afterward, something should
# work ;-)
self.add_multiarch_paths()
elif sys.platform.startswith("gnu"):
self.add_multiarch_paths()
elif sys.platform.startswith("netbsd"):
_add_directory(library_dirs, "/usr/pkg/lib")
_add_directory(include_dirs, "/usr/pkg/include")
# FIXME: check /opt/stuff directories here?
#
# locate tkinter libraries
if _tkinter:
TCL_VERSION = _tkinter.TCL_VERSION[:3]
if _tkinter and not TCL_ROOT:
# we have Tkinter but the TCL_ROOT variable was not set;
# try to locate appropriate Tcl/Tk libraries
PYVERSION = sys.version[0] + sys.version[2]
TCLVERSION = TCL_VERSION[0] + TCL_VERSION[2]
roots = [
# common installation directories, mostly for Windows
# (for Unix-style platforms, we'll check in well-known
# locations later)
os.path.join("/py" + PYVERSION, "Tcl"),
os.path.join("/python" + PYVERSION, "Tcl"),
"/Tcl", "/Tcl" + TCLVERSION, "/Tcl" + TCL_VERSION,
os.path.join(os.environ.get("ProgramFiles", ""), "Tcl"), ]
for TCL_ROOT in roots:
TCL_ROOT = os.path.abspath(TCL_ROOT)
if os.path.isfile(os.path.join(TCL_ROOT, "include", "tk.h")):
# FIXME: use distutils logging (?)
print("--- using Tcl/Tk libraries at", TCL_ROOT)
print("--- using Tcl/Tk version", TCL_VERSION)
TCL_ROOT = _lib_include(TCL_ROOT)
break
else:
TCL_ROOT = None
# add standard directories
# look for tcl specific subdirectory (e.g debian)
if _tkinter:
tcl_dir = "/usr/include/tcl" + TCL_VERSION
if os.path.isfile(os.path.join(tcl_dir, "tk.h")):
_add_directory(include_dirs, tcl_dir)
# standard locations
_add_directory(library_dirs, "/usr/local/lib")
_add_directory(include_dirs, "/usr/local/include")
_add_directory(library_dirs, "/usr/lib")
_add_directory(include_dirs, "/usr/include")
# on Windows, look for the OpenJPEG libraries in the location that
# the official installed puts them
if sys.platform == "win32":
_add_directory(library_dirs,
os.path.join(os.environ.get("ProgramFiles", ""),
"OpenJPEG 2.0", "lib"))
_add_directory(include_dirs,
os.path.join(os.environ.get("ProgramFiles", ""),
"OpenJPEG 2.0", "include"))
#
# insert new dirs *before* default libs, to avoid conflicts
# between Python PYD stub libs and real libraries
self.compiler.library_dirs = library_dirs + self.compiler.library_dirs
self.compiler.include_dirs = include_dirs + self.compiler.include_dirs
#
# look for available libraries
feature = self.feature
if feature.want('zlib'):
if _find_include_file(self, "zlib.h"):
if _find_library_file(self, "z"):
feature.zlib = "z"
elif sys.platform == "win32" and _find_library_file(self, "zlib"):
feature.zlib = "zlib" # alternative name
if feature.want('jpeg'):
if _find_include_file(self, "jpeglib.h"):
if _find_library_file(self, "jpeg"):
feature.jpeg = "jpeg"
elif (
sys.platform == "win32" and
_find_library_file(self, "libjpeg")):
feature.jpeg = "libjpeg" # alternative name
if feature.want('jpeg2000'):
if _find_include_file(self, "openjpeg-2.0/openjpeg.h"):
if _find_library_file(self, "openjp2"):
feature.jpeg2000 = "openjp2"
if feature.want('tiff'):
if _find_library_file(self, "tiff"):
feature.tiff = "tiff"
if sys.platform == "win32" and _find_library_file(self, "libtiff"):
feature.tiff = "libtiff"
if sys.platform == "darwin" and _find_library_file(self, "libtiff"):
feature.tiff = "libtiff"
if feature.want('freetype'):
if _find_library_file(self, "freetype"):
# look for freetype2 include files
freetype_version = 0
for dir in self.compiler.include_dirs:
if os.path.isfile(os.path.join(dir, "ft2build.h")):
freetype_version = 21
dir = os.path.join(dir, "freetype2")
break
dir = os.path.join(dir, "freetype2")
if os.path.isfile(os.path.join(dir, "ft2build.h")):
freetype_version = 21
break
if os.path.isdir(os.path.join(dir, "freetype")):
freetype_version = 20
break
if freetype_version:
feature.freetype = "freetype"
feature.freetype_version = freetype_version
if dir:
_add_directory(self.compiler.include_dirs, dir, 0)
if feature.want('lcms'):
if _find_include_file(self, "lcms2.h"):
if _find_library_file(self, "lcms2"):
feature.lcms = "lcms"
if _tkinter and _find_include_file(self, "tk.h"):
# the library names may vary somewhat (e.g. tcl84 or tcl8.4)
version = TCL_VERSION[0] + TCL_VERSION[2]
if feature.want('tcl'):
if _find_library_file(self, "tcl" + version):
feature.tcl = "tcl" + version
elif _find_library_file(self, "tcl" + TCL_VERSION):
feature.tcl = "tcl" + TCL_VERSION
if feature.want('tk'):
if _find_library_file(self, "tk" + version):
feature.tk = "tk" + version
elif _find_library_file(self, "tk" + TCL_VERSION):
feature.tk = "tk" + TCL_VERSION
if feature.want('webp'):
if (_find_include_file(self, "webp/encode.h") and
_find_include_file(self, "webp/decode.h")):
if _find_library_file(self, "webp"): # in googles precompiled zip it is call "libwebp"
feature.webp = "webp"
if feature.want('webpmux'):
if (_find_include_file(self, "webp/mux.h") and
_find_include_file(self, "webp/demux.h")):
if _find_library_file(self, "webpmux") and _find_library_file(self, "webpdemux"):
feature.webpmux = "webpmux"
for f in feature:
if not getattr(feature, f) and feature.require(f):
raise ValueError(
'--enable-%s requested but %s not found, aborting.'
% (f, f))
#
# core library
files = ["_imaging.c"]
for file in _IMAGING:
files.append(file + ".c")
for file in _LIB_IMAGING:
files.append(os.path.join("libImaging", file + ".c"))
libs = []
defs = []
if feature.jpeg:
libs.append(feature.jpeg)
defs.append(("HAVE_LIBJPEG", None))
if feature.jpeg2000:
libs.append(feature.jpeg2000)
defs.append(("HAVE_OPENJPEG", None))
if sys.platform == "win32":
defs.append(("OPJ_STATIC", None))
if feature.zlib:
libs.append(feature.zlib)
defs.append(("HAVE_LIBZ", None))
if feature.tiff:
libs.append(feature.tiff)
defs.append(("HAVE_LIBTIFF", None))
if sys.platform == "win32":
libs.extend(["kernel32", "user32", "gdi32"])
if struct.unpack("h", "\0\1".encode('ascii'))[0] == 1:
defs.append(("WORDS_BIGENDIAN", None))
exts = [(Extension(
"PIL._imaging", files, libraries=libs, define_macros=defs))]
#
# additional libraries
if feature.freetype:
defs = []
if feature.freetype_version == 20:
defs.append(("USE_FREETYPE_2_0", None))
exts.append(Extension(
"PIL._imagingft", ["_imagingft.c"], libraries=["freetype"],
define_macros=defs))
if os.path.isfile("_imagingtiff.c") and feature.tiff:
exts.append(Extension(
"PIL._imagingtiff", ["_imagingtiff.c"], libraries=["tiff"]))
if os.path.isfile("_imagingcms.c") and feature.lcms:
extra = []
if sys.platform == "win32":
extra.extend(["user32", "gdi32"])
exts.append(Extension(
"PIL._imagingcms", ["_imagingcms.c"], libraries=["lcms2"] + extra))
if os.path.isfile("_webp.c") and feature.webp:
libs = ["webp"]
defs = []
if feature.webpmux:
defs.append(("HAVE_WEBPMUX", None))
libs.append("webpmux")
libs.append("webpdemux")
exts.append(Extension(
"PIL._webp", ["_webp.c"], libraries=libs, define_macros=defs))
if sys.platform == "darwin":
# locate Tcl/Tk frameworks
frameworks = []
framework_roots = [
"/Library/Frameworks",
"/System/Library/Frameworks"]
for root in framework_roots:
if (
os.path.exists(os.path.join(root, "Tcl.framework")) and
os.path.exists(os.path.join(root, "Tk.framework"))):
print("--- using frameworks at %s" % root)
frameworks = ["-framework", "Tcl", "-framework", "Tk"]
dir = os.path.join(root, "Tcl.framework", "Headers")
_add_directory(self.compiler.include_dirs, dir, 0)
dir = os.path.join(root, "Tk.framework", "Headers")
_add_directory(self.compiler.include_dirs, dir, 1)
break
if frameworks:
exts.append(Extension(
"PIL._imagingtk", ["_imagingtk.c", "Tk/tkImaging.c"],
extra_compile_args=frameworks, extra_link_args=frameworks))
feature.tcl = feature.tk = 1 # mark as present
elif feature.tcl and feature.tk:
exts.append(Extension(
"PIL._imagingtk", ["_imagingtk.c", "Tk/tkImaging.c"],
libraries=[feature.tcl, feature.tk]))
if os.path.isfile("_imagingmath.c"):
exts.append(Extension("PIL._imagingmath", ["_imagingmath.c"]))
self.extensions[:] = exts
build_ext.build_extensions(self)
#
# sanity and security checks
unsafe_zlib = None
if feature.zlib:
unsafe_zlib = self.check_zlib_version(self.compiler.include_dirs)
self.summary_report(feature, unsafe_zlib)
def summary_report(self, feature, unsafe_zlib):
print("-" * 68)
print("PIL SETUP SUMMARY")
print("-" * 68)
print("version Pillow %s" % VERSION)
v = sys.version.split("[")
print("platform %s %s" % (sys.platform, v[0].strip()))
for v in v[1:]:
print(" [%s" % v.strip())
print("-" * 68)
options = [
(feature.tcl and feature.tk, "TKINTER"),
(feature.jpeg, "JPEG"),
(feature.jpeg2000, "OPENJPEG (JPEG2000)"),
(feature.zlib, "ZLIB (PNG/ZIP)"),
(feature.tiff, "LIBTIFF"),
(feature.freetype, "FREETYPE2"),
(feature.lcms, "LITTLECMS2"),
(feature.webp, "WEBP"),
(feature.webpmux, "WEBPMUX"), ]
all = 1
for option in options:
if option[0]:
print("--- %s support available" % option[1])
else:
print("*** %s support not available" % option[1])
if option[1] == "TKINTER" and _tkinter:
version = _tkinter.TCL_VERSION
print("(Tcl/Tk %s libraries needed)" % version)
all = 0
if feature.zlib and unsafe_zlib:
print("")
print("*** Warning: zlib", unsafe_zlib)
print("may contain a security vulnerability.")
print("*** Consider upgrading to zlib 1.2.3 or newer.")
print("*** See: http://www.kb.cert.org/vuls/id/238678")
print(" http://www.kb.cert.org/vuls/id/680620")
print(" http://www.gzip.org/zlib/advisory-2002-03-11.txt")
print("")
print("-" * 68)
if not all:
print("To add a missing option, make sure you have the required")
print("library, and set the corresponding ROOT variable in the")
print("setup.py script.")
print("")
print("To check the build, run the selftest.py script.")
print("")
def check_zlib_version(self, include_dirs):
# look for unsafe versions of zlib
for dir in include_dirs:
zlibfile = os.path.join(dir, "zlib.h")
if os.path.isfile(zlibfile):
break
else:
return
for line in open(zlibfile).readlines():
m = re.match('#define\s+ZLIB_VERSION\s+"([^"]*)"', line)
if not m:
continue
if m.group(1) < "1.2.3":
return m.group(1)
# http://hg.python.org/users/barry/rev/7e8deab93d5a
def add_multiarch_paths(self):
# Debian/Ubuntu multiarch support.
# https://wiki.ubuntu.com/MultiarchSpec
# self.build_temp
tmpfile = os.path.join(self.build_temp, 'multiarch')
if not os.path.exists(self.build_temp):
os.makedirs(self.build_temp)
ret = os.system(
'dpkg-architecture -qDEB_HOST_MULTIARCH > %s 2> /dev/null' %
tmpfile)
try:
if ret >> 8 == 0:
fp = open(tmpfile, 'r')
multiarch_path_component = fp.readline().strip()
_add_directory(
self.compiler.library_dirs,
'/usr/lib/' + multiarch_path_component)
_add_directory(
self.compiler.include_dirs,
'/usr/include/' + multiarch_path_component)
finally:
os.unlink(tmpfile)
setup(
name=NAME,
version=VERSION,
description='Python Imaging Library (Fork)',
long_description=(
_read('README.rst') + b'\n' +
_read('CHANGES.rst')).decode('utf-8'),
author='Alex Clark (fork author)',
author_email='aclark@aclark.net',
url='http://python-imaging.github.io/',
classifiers=[
"Development Status :: 6 - Mature",
"Topic :: Multimedia :: Graphics",
"Topic :: Multimedia :: Graphics :: Capture :: Digital Camera",
"Topic :: Multimedia :: Graphics :: Capture :: Scanners",
"Topic :: Multimedia :: Graphics :: Capture :: Screen Capture",
"Topic :: Multimedia :: Graphics :: Graphics Conversion",
"Topic :: Multimedia :: Graphics :: Viewers",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.2",
"Programming Language :: Python :: 3.3", ],
cmdclass={"build_ext": pil_build_ext},
ext_modules=[Extension("PIL._imaging", ["_imaging.c"])],
include_package_data=True,
packages=find_packages(),
scripts=glob.glob("Scripts/pil*.py"),
test_suite='PIL.tests',
keywords=["Imaging",],
license='Standard PIL License',
zip_safe=True,
)