From f869ecd8084e1d1310e6fde6bb6d278e72d28357 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Wed, 30 Mar 2016 08:19:23 -0700 Subject: [PATCH 1/7] Dir is not a variable name --- setup.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/setup.py b/setup.py index b252bc620..75e6a9322 100644 --- a/setup.py +++ b/setup.py @@ -38,15 +38,15 @@ _LIB_IMAGING = ( "Jpeg2KDecode", "Jpeg2KEncode", "BoxBlur") -def _add_directory(path, dir, where=None): - if dir is None: +def _add_directory(path, subdir, where=None): + if subdir is None: return - dir = os.path.realpath(dir) - if os.path.isdir(dir) and dir not in path: + subdir = os.path.realpath(subdir) + if os.path.isdir(subdir) and subdir not in path: if where is None: - path.append(dir) + path.append(subdir) else: - path.insert(where, dir) + path.insert(where, subdir) def _find_include_file(self, include): @@ -448,20 +448,20 @@ class pil_build_ext(build_ext): 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")): + for subdir in self.compiler.include_dirs: + if os.path.isfile(os.path.join(subdir, "ft2build.h")): freetype_version = 21 - dir = os.path.join(dir, "freetype2") + subdir = os.path.join(subdir, "freetype2") break - dir = os.path.join(dir, "freetype2") - if os.path.isfile(os.path.join(dir, "ft2build.h")): + subdir = os.path.join(subdir, "freetype2") + if os.path.isfile(os.path.join(subdir, "ft2build.h")): freetype_version = 21 break if freetype_version: feature.freetype = "freetype" feature.freetype_version = freetype_version - if dir: - _add_directory(self.compiler.include_dirs, dir, 0) + if subdir: + _add_directory(self.compiler.include_dirs, subdir, 0) if feature.want('lcms'): if _find_include_file(self, "lcms2.h"): @@ -592,10 +592,10 @@ class pil_build_ext(build_ext): if (os.path.exists(root_tcl) and os.path.exists(root_tk)): print("--- using frameworks at %s" % root) frameworks = ["-framework", "Tcl", "-framework", "Tk"] - dir = os.path.join(root_tcl, "Headers") - _add_directory(self.compiler.include_dirs, dir, 0) - dir = os.path.join(root_tk, "Headers") - _add_directory(self.compiler.include_dirs, dir, 1) + subdir = os.path.join(root_tcl, "Headers") + _add_directory(self.compiler.include_dirs, subdir, 0) + subdir = os.path.join(root_tk, "Headers") + _add_directory(self.compiler.include_dirs, subdir, 1) break if frameworks: exts.append(Extension("PIL._imagingtk", @@ -689,8 +689,8 @@ class pil_build_ext(build_ext): 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") + for subdir in include_dirs: + zlibfile = os.path.join(subdir, "zlib.h") if os.path.isfile(zlibfile): break else: From bf2df86807597384126842f35132bf4f935332ec Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Wed, 30 Mar 2016 08:20:27 -0700 Subject: [PATCH 2/7] require, required, and want are not features --- setup.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 75e6a9322..88ad75387 100644 --- a/setup.py +++ b/setup.py @@ -100,10 +100,15 @@ LCMS_ROOT = None class pil_build_ext(build_ext): class feature: - zlib = jpeg = tiff = freetype = tcl = tk = lcms = webp = webpmux = None - jpeg2000 = None + features = ['zlib', 'jpeg', 'tiff', 'freetype', 'tcl', 'tk', + 'lcms', 'webp', 'webpmux', 'jpeg2000'] + required = set(['jpeg', 'zlib']) + def __init__(self): + for f in self.features: + setattr(self, f, None) + def require(self, feat): return feat in self.required @@ -111,9 +116,8 @@ class pil_build_ext(build_ext): return getattr(self, feat) is None def __iter__(self): - for x in dir(self): - if x[1] != '_': - yield x + for x in self.features: + yield x feature = feature() From 999b0a1e8c3d9c265c71370a452acf3e6e9555c0 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Wed, 30 Mar 2016 09:13:10 -0700 Subject: [PATCH 3/7] file is not a variable name --- setup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 88ad75387..2ab9c870b 100644 --- a/setup.py +++ b/setup.py @@ -522,10 +522,10 @@ class pil_build_ext(build_ext): # 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")) + for src_file in _IMAGING: + files.append(src_file + ".c") + for src_file in _LIB_IMAGING: + files.append(os.path.join("libImaging", src_file + ".c")) libs = [] defs = [] From 6ab84373be8f43aa779ca433855694994b1f7716 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Wed, 30 Mar 2016 09:16:10 -0700 Subject: [PATCH 4/7] debug logging for setup.py --- setup.py | 87 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 20 deletions(-) diff --git a/setup.py b/setup.py index 2ab9c870b..1e55855a9 100644 --- a/setup.py +++ b/setup.py @@ -37,6 +37,15 @@ _LIB_IMAGING = ( "XbmEncode", "ZipDecode", "ZipEncode", "TiffDecode", "Incremental", "Jpeg2KDecode", "Jpeg2KEncode", "BoxBlur") +DEBUG = False + +def _dbg(s, tp=None): + if DEBUG: + if tp: + print(s % tp) + return + print(s) + def _add_directory(path, subdir, where=None): if subdir is None: @@ -44,14 +53,18 @@ def _add_directory(path, subdir, where=None): subdir = os.path.realpath(subdir) if os.path.isdir(subdir) and subdir not in path: if where is None: + _dbg('Appending path %s', subdir) path.append(subdir) else: + _dbg('Inserting path %s', subdir) path.insert(where, subdir) def _find_include_file(self, include): for directory in self.compiler.include_dirs: + _dbg('Checking for include file %s in %s', (include, directory)) if os.path.isfile(os.path.join(directory, include)): + _dbg('Found %s', include) return 1 return 0 @@ -61,15 +74,22 @@ def _find_library_file(self, library): # 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: + _dbg('stripping cpython from shared library extension %s', + 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) + ret = self.compiler.find_library_file(self.compiler.library_dirs, + library) + if ret: + _dbg('Found library %s at %s', (library, ret)) + else: + _dbg("Couldn't find library %s in %s", + (library, self.compiler.library_dirs)) + return ret def _lib_include(root): @@ -125,7 +145,7 @@ class pil_build_ext(build_ext): ('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 - ] + ] + [('debug', None, 'Debug logging')] def initialize_options(self): build_ext.initialize_options(self) @@ -135,15 +155,20 @@ class pil_build_ext(build_ext): def finalize_options(self): build_ext.finalize_options(self) + if self.debug: + global DEBUG + DEBUG = True for x in self.feature: if getattr(self, 'disable_%s' % x): setattr(self.feature, x, False) self.feature.required.discard(x) + _dbg('Disabling %s', x) if getattr(self, 'enable_%s' % x): raise ValueError( 'Conflicting options: --enable-%s and --disable-%s' % (x, x)) if getattr(self, 'enable_%s' % x): + _dbg('Requiring %s', x) self.feature.required.add(x) def build_extensions(self): @@ -318,6 +343,9 @@ class pil_build_ext(build_ext): if _tkinter: TCL_VERSION = _tkinter.TCL_VERSION[:3] + _dbg('Tkinter found, will check for Tcl/Tk') + else: + _dbg('Tkinter not found') if _tkinter and not TCL_ROOT: # we have Tkinter but the TCL_ROOT variable was not set; @@ -338,6 +366,7 @@ class pil_build_ext(build_ext): ] for TCL_ROOT in roots: TCL_ROOT = os.path.abspath(TCL_ROOT) + _dbg('Checking %s for tk.h', 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) @@ -346,6 +375,7 @@ class pil_build_ext(build_ext): break else: TCL_ROOT = None + _dbg('Tcl/tk not found') # add standard directories @@ -377,6 +407,7 @@ class pil_build_ext(build_ext): best_path = os.path.join(program_files, name) if best_path: + _dbg('Adding %s to search list', best_path) _add_directory(library_dirs, os.path.join(best_path, 'lib')) _add_directory(include_dirs, os.path.join(best_path, 'include')) @@ -394,6 +425,7 @@ class pil_build_ext(build_ext): feature = self.feature if feature.want('zlib'): + _dbg('Looking for zlib') if _find_include_file(self, "zlib.h"): if _find_library_file(self, "z"): feature.zlib = "z" @@ -402,6 +434,7 @@ class pil_build_ext(build_ext): feature.zlib = "zlib" # alternative name if feature.want('jpeg'): + _dbg('Looking for jpeg') if _find_include_file(self, "jpeglib.h"): if _find_library_file(self, "jpeg"): feature.jpeg = "jpeg" @@ -411,11 +444,13 @@ class pil_build_ext(build_ext): feature.openjpeg_version = None if feature.want('jpeg2000'): + _dbg('Looking for jpeg2000') best_version = None best_path = None # Find the best version for directory in self.compiler.include_dirs: + _dbg('Checking for openjpeg-#.# in %s', directory) try: listdir = os.listdir(directory) except Exception: @@ -425,10 +460,12 @@ class pil_build_ext(build_ext): if name.startswith('openjpeg-') and \ os.path.isfile(os.path.join(directory, name, 'openjpeg.h')): + _dbg('Found openjpeg.h in %s/%s',(directory, name)) version = tuple([int(x) for x in name[9:].split('.')]) if best_version is None or version > best_version: best_version = version best_path = os.path.join(directory, name) + _dbg('Best openjpeg version %s so far in %s', (best_version, best_path)) if best_version and _find_library_file(self, 'openjp2'): # Add the directory to the include path so we can include @@ -440,25 +477,32 @@ class pil_build_ext(build_ext): best_version]) 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" + _dbg('Looking for tiff') + if _find_include_file(self, 'tiff.h'): + 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'): + _dbg('Looking for freetype') if _find_library_file(self, "freetype"): # look for freetype2 include files freetype_version = 0 for subdir in self.compiler.include_dirs: + _dbg('Checking for include file %s in %s', ("ft2build.h", subdir)) if os.path.isfile(os.path.join(subdir, "ft2build.h")): + _dbg('Found %s in %s', ("ft2build.h", subdir)) freetype_version = 21 subdir = os.path.join(subdir, "freetype2") break subdir = os.path.join(subdir, "freetype2") + _dbg('Checking for include file %s in %s', ("ft2build.h", subdir)) if os.path.isfile(os.path.join(subdir, "ft2build.h")): + _dbg('Found %s in %s', ("ft2build.h", subdir)) freetype_version = 21 break if freetype_version: @@ -468,6 +512,7 @@ class pil_build_ext(build_ext): _add_directory(self.compiler.include_dirs, subdir, 0) if feature.want('lcms'): + _dbg('Looking for lcms') if _find_include_file(self, "lcms2.h"): if _find_library_file(self, "lcms2"): feature.lcms = "lcms2" @@ -479,17 +524,20 @@ class pil_build_ext(build_ext): # the library names may vary somewhat (e.g. tcl85 or tcl8.5) version = TCL_VERSION[0] + TCL_VERSION[2] if feature.want('tcl'): + _dbg('Looking for 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'): + _dbg('Looking for 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'): + _dbg('Looking for webp') if (_find_include_file(self, "webp/encode.h") and _find_include_file(self, "webp/decode.h")): # In Google's precompiled zip it is call "libwebp": @@ -499,6 +547,7 @@ class pil_build_ext(build_ext): feature.webp = "libwebp" if feature.want('webpmux'): + _dbg('Looking for webpmux') if (_find_include_file(self, "webp/mux.h") and _find_include_file(self, "webp/demux.h")): if (_find_library_file(self, "webpmux") and @@ -561,7 +610,7 @@ class pil_build_ext(build_ext): ["_imagingft.c"], libraries=["freetype"])) - if os.path.isfile("_imagingcms.c") and feature.lcms: + if feature.lcms: extra = [] if sys.platform == "win32": extra.extend(["user32", "gdi32"]) @@ -569,7 +618,7 @@ class pil_build_ext(build_ext): ["_imagingcms.c"], libraries=[feature.lcms] + extra)) - if os.path.isfile("_webp.c") and feature.webp: + if feature.webp: libs = [feature.webp] defs = [] @@ -590,6 +639,7 @@ class pil_build_ext(build_ext): framework_roots = [ "/Library/Frameworks", "/System/Library/Frameworks" ] + _dbg('Looking for TclTk Framework Build') for root in framework_roots: root_tcl = os.path.join(root, "Tcl.framework") root_tk = os.path.join(root, "Tk.framework") @@ -611,11 +661,8 @@ class pil_build_ext(build_ext): ["_imagingtk.c", "Tk/tkImaging.c"], libraries=[feature.tcl, feature.tk])) - if os.path.isfile("_imagingmath.c"): - exts.append(Extension("PIL._imagingmath", ["_imagingmath.c"])) - - if os.path.isfile("_imagingmorph.c"): - exts.append(Extension("PIL._imagingmorph", ["_imagingmorph.c"])) + exts.append(Extension("PIL._imagingmath", ["_imagingmath.c"])) + exts.append(Extension("PIL._imagingmorph", ["_imagingmorph.c"])) self.extensions[:] = exts @@ -684,8 +731,8 @@ class pil_build_ext(build_ext): 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("library and headers.") + print("See http://pillow.readthedocs.org/en/latest/installation.html#building-from-source") print("") print("To check the build, run the selftest.py script.") From 33ed45c762959b1b6fa20ca29dd8f66dba9e1301 Mon Sep 17 00:00:00 2001 From: Alex Clark Date: Wed, 30 Mar 2016 15:47:27 -0400 Subject: [PATCH 5/7] Clean up (yapf) Sorry, couldn't resist. As for the issues you raised, they are unfortunately not surprising. Our setup.py has to be complex, but doesn't need to be complicated. I've been trying to avoid a complete rewrite, but maybe it's time. --- setup.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index 1e55855a9..c618a56e7 100644 --- a/setup.py +++ b/setup.py @@ -39,6 +39,7 @@ _LIB_IMAGING = ( DEBUG = False + def _dbg(s, tp=None): if DEBUG: if tp: @@ -83,12 +84,12 @@ def _find_library_file(self, library): self.compiler.shared_lib_extension = existing else: ret = self.compiler.find_library_file(self.compiler.library_dirs, - library) + library) if ret: _dbg('Found library %s at %s', (library, ret)) else: _dbg("Couldn't find library %s in %s", - (library, self.compiler.library_dirs)) + (library, self.compiler.library_dirs)) return ret @@ -120,8 +121,8 @@ LCMS_ROOT = None class pil_build_ext(build_ext): class feature: - features = ['zlib', 'jpeg', 'tiff', 'freetype', 'tcl', 'tk', - 'lcms', 'webp', 'webpmux', 'jpeg2000'] + features = ['zlib', 'jpeg', 'tiff', 'freetype', 'tcl', 'tk', 'lcms', + 'webp', 'webpmux', 'jpeg2000'] required = set(['jpeg', 'zlib']) @@ -460,12 +461,13 @@ class pil_build_ext(build_ext): if name.startswith('openjpeg-') and \ os.path.isfile(os.path.join(directory, name, 'openjpeg.h')): - _dbg('Found openjpeg.h in %s/%s',(directory, name)) + _dbg('Found openjpeg.h in %s/%s', (directory, name)) version = tuple([int(x) for x in name[9:].split('.')]) if best_version is None or version > best_version: best_version = version best_path = os.path.join(directory, name) - _dbg('Best openjpeg version %s so far in %s', (best_version, best_path)) + _dbg('Best openjpeg version %s so far in %s', + (best_version, best_path)) if best_version and _find_library_file(self, 'openjp2'): # Add the directory to the include path so we can include From 233afecb905617f02270458a1c7ca3c6757bf851 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Sat, 9 Apr 2016 08:15:24 -0700 Subject: [PATCH 6/7] Documentation of --debug flag --- docs/installation.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/installation.rst b/docs/installation.rst index 45b0c3351..1f4e8038e 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -181,6 +181,11 @@ Build Options the libraries are not found. Webpmux (WebP metadata) relies on WebP support. Tcl and Tk also must be used together. +* Build flags: ``--debug``. Adds a debugging flag to the include and + library search process to dump all paths searched for and found to + stdout. + + Sample Usage:: $ MAX_CONCURRENCY=1 python setup.py build_ext --enable-[feature] install From a2bc14c52611398b7e92c698f49b671eadcb19ed Mon Sep 17 00:00:00 2001 From: wiredfool Date: Sun, 10 Apr 2016 02:11:56 -0700 Subject: [PATCH 7/7] changed docs link to https --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index c618a56e7..844206a7b 100644 --- a/setup.py +++ b/setup.py @@ -734,7 +734,7 @@ class pil_build_ext(build_ext): if not all: print("To add a missing option, make sure you have the required") print("library and headers.") - print("See http://pillow.readthedocs.org/en/latest/installation.html#building-from-source") + print("See https://pillow.readthedocs.org/en/latest/installation.html#building-from-source") print("") print("To check the build, run the selftest.py script.")