From bc9c911ad555f574538b2a09a021236af86718de Mon Sep 17 00:00:00 2001 From: Matt Terry Date: Fri, 30 Aug 2013 11:16:59 -0700 Subject: [PATCH 01/14] add support for freetype config --- setupext.py | 180 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 165 insertions(+), 15 deletions(-) diff --git a/setupext.py b/setupext.py index 02ef9ee54c86..62cd1d01b31d 100644 --- a/setupext.py +++ b/setupext.py @@ -320,7 +320,7 @@ def get_version(self, package): """ Get the version of the package from pkg-config. """ - if not self.has_pkgconfig: + if not self.ft_config: return None status, output = getstatusoutput( @@ -334,6 +334,99 @@ def get_version(self, package): pkg_config = PkgConfig() +class FTConfig(object): + """ + This is a class for communicating with freetype-config. + """ + def __init__(self): + """ + Determines whether freetype-config exists on this machine. + """ + if sys.platform == 'win32': + self.has_ftconfig = False + else: + self.set_pkgconfig_path() + status, output = getstatusoutput("freetype-config --help") + self.has_ftconfig = (status == 0) + + def set_pkgconfig_path(self): + pkgconfig_path = sysconfig.get_config_var('LIBDIR') + if pkgconfig_path is None: + return + + pkgconfig_path = os.path.join(pkgconfig_path, 'pkgconfig') + if not os.path.isdir(pkgconfig_path): + return + + try: + os.environ['PKG_CONFIG_PATH'] += ':' + pkgconfig_path + except KeyError: + os.environ['PKG_CONFIG_PATH'] = pkgconfig_path + + def setup_extension(self, ext, package, default_include_dirs=[], + default_library_dirs=[], default_libraries=[]): + """ + Add parameters to the given `ext` for the given `package`. + """ + flag_map = { + '-I': 'include_dirs', '-L': 'library_dirs', '-l': 'libraries'} + + if package != 'freetype2': + raise RuntimeError("FTConfig only works for the freetype2 package") + + use_defaults = True + + if self.has_ftconfig: + try: + output = check_output("freetype-config --libs --cflags", + shell=True, + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError: + pass + else: + output = output.decode(sys.getfilesystemencoding()) + use_defaults = False + for token in output.split(): + attr = flag_map.get(token[:2]) + if attr is not None: + getattr(ext, attr).append(token[2:]) + + if use_defaults: + basedirs = get_base_dirs() + for base in basedirs: + for include in default_include_dirs: + dir = os.path.join(base, include) + if os.path.exists(dir): + ext.include_dirs.append(dir) + for lib in default_library_dirs: + dir = os.path.join(base, lib) + if os.path.exists(dir): + ext.library_dirs.append(dir) + ext.libraries.extend(default_libraries) + return True + + return False + + def get_version(self, package): + """ + Get the version from freetype-config. + """ + if package != 'freetype2': + raise RuntimeError("FTConfig only works for the freetype2 package") + + if not self.ft_config: + return None + + status, output = getstatusoutput("freetype-config --ftversion") + if status == 0: + return output + return None + + +# The PkgConfig class should be used through this singleton +ft_config = FTConfig() + + class CheckFailed(Exception): """ Exception thrown when a `SetupPackage.check` method fails. @@ -774,26 +867,83 @@ def check(self): if sys.platform == 'win32': return "Unknown version" - status, output = getstatusoutput("freetype-config --version") + status, version = getstatusoutput("freetype-config --version") if status == 0: - version = output - else: - version = None + try: + return self._check_for_ft_config( + 'freetype2', 'ft2build.h', + min_version='2.4', version=version) + except CheckFailed: + pass return self._check_for_pkg_config( 'freetype2', 'ft2build.h', - min_version='2.4', version=version) + min_version='2.4', version=None) + + def _check_for_ft_config(self, package, include_file, min_version=None, + version=None): + """ + A convenience function for writing checks for a + pkg_config-defined dependency. + + `package` is the ft_config package name. + + `include_file` is a top-level include file we expect to find. + + `min_version` is the minimum version required. + + `version` will override the found version if this package + requires an alternate method for that. + """ + if version is None: + version = ft_config.get_version(package) + + if version is None: + raise CheckFailed( + "pkg-config information for '%s' could not be found." % + package) + + if min_version == 'PATCH': + raise CheckFailed( + "Requires patches that have not been merged upstream.") + + if min_version: + if (not is_min_version(version, min_version)): + raise CheckFailed( + "Requires %s %s or later. Found %s." % + (package, min_version, version)) + + ext = self.get_extension() + if ext is None: + ext = make_extension('test', []) + ft_config.setup_extension(ext, package) + + check_include_file(ext.include_dirs, include_file, package) + + return 'version %s' % version def add_flags(self, ext): - pkg_config.setup_extension( - ext, 'freetype2', - default_include_dirs=[ - 'freetype2', 'lib/freetype2/include', - 'lib/freetype2/include/freetype2'], - default_library_dirs=[ - 'freetype2/lib'], - default_libraries=['freetype', 'z'], - alt_exec='freetype-config') + if ft_config.has_ftconfig: + ft_config.setup_extension( + ext, 'freetype2', + default_include_dirs=[ + 'freetype2', + 'lib/freetype2/include', + 'lib/freetype2/include/freetype2', + ], + default_library_dirs=['freetype2/lib'], + default_libraries=['freetype', 'z']) + + else: + pkg_config.setup_extension( + ext, 'freetype2', + default_include_dirs=[ + 'freetype2', + 'lib/freetype2/include', + 'lib/freetype2/include/freetype2', + ], + default_library_dirs=['freetype2/lib'], + default_libraries=['freetype', 'z']) class FT2Font(SetupPackage): From fbc44fcdd7053a28f6044cb2570ea69f17c3da43 Mon Sep 17 00:00:00 2001 From: Matt Terry Date: Fri, 30 Aug 2013 12:18:17 -0700 Subject: [PATCH 02/14] refactor dependency managment --- setup.py | 161 ++++++++++++++++++++++++++++++---------------------- setupext.py | 52 +++++++---------- 2 files changed, 114 insertions(+), 99 deletions(-) diff --git a/setup.py b/setup.py index 20d088801044..5a1c8c2d31bf 100644 --- a/setup.py +++ b/setup.py @@ -4,6 +4,7 @@ """ from __future__ import print_function, absolute_import +from collections import OrderedDict, namedtuple # This needs to be the very first thing to use distribute from distribute_setup import use_setuptools @@ -55,52 +56,77 @@ # These are the packages in the order we want to display them. This # list may contain strings to create section headers for the display. -mpl_packages = [ - 'Building Matplotlib', - setupext.Matplotlib(), - setupext.Python(), - setupext.Platform(), - 'Required dependencies and extensions', - setupext.Numpy(), - setupext.Dateutil(), - setupext.Tornado(), - setupext.Pyparsing(), - setupext.CXX(), - setupext.LibAgg(), - setupext.FreeType(), - setupext.FT2Font(), - setupext.Png(), - setupext.Image(), - setupext.TTConv(), - setupext.Path(), - setupext.Contour(), - setupext.Delaunay(), - setupext.Tri(), - 'Optional subpackages', - setupext.SampleData(), - setupext.Toolkits(), - setupext.Tests(), - 'Optional backend extensions', - # These backends are listed in order of preference, the first - # being the most preferred. The first one that looks like it will - # work will be selected as the default backend. - setupext.BackendMacOSX(), - setupext.BackendQt4(), - setupext.BackendGtk3Agg(), - setupext.BackendGtk3Cairo(), - setupext.BackendGtkAgg(), - setupext.BackendTkAgg(), - setupext.BackendWxAgg(), - setupext.BackendGtk(), - setupext.BackendAgg(), - setupext.BackendCairo(), - setupext.Windowing(), - 'Optional LaTeX dependencies', - setupext.DviPng(), - setupext.Ghostscript(), - setupext.LaTeX(), - setupext.PdfToPs() - ] + +Spacer = namedtuple('Spacer', ['text']) + +mpl_packages = OrderedDict() + +mpl_packages['building'] = Spacer('Building Matplotlib') +mpl_packages['matplotlib'] = setupext.Matplotlib() +mpl_packages['python'] = setupext.Python() +mpl_packages['platform'] = setupext.Platform() + +mpl_packages['required'] = Spacer('Required dependencies and extensions') +mpl_packages['numpy'] = setupext.Numpy() +mpl_packages['dateutil'] = setupext.Dateutil() +mpl_packages['tornado'] = setupext.Tornado() +mpl_packages['pyparsing'] = setupext.Pyparsing() +mpl_packages['cxx'] = setupext.CXX() +mpl_packages['libagg'] = setupext.LibAgg() +mpl_packages['freetype'] = setupext.FreeType() +mpl_packages['ft2font'] = setupext.FT2Font(mpl_packages['freetype'], + mpl_packages['numpy'], + mpl_packages['cxx']) +mpl_packages['png'] = setupext.Png(mpl_packages['numpy'], + mpl_packages['cxx']) +mpl_packages['image'] = setupext.Image(mpl_packages['numpy'], + mpl_packages['libagg'], + mpl_packages['cxx']) +mpl_packages['ttconv'] = setupext.TTConv(mpl_packages['numpy'], + mpl_packages['cxx']) +mpl_packages['path'] = setupext.Path(mpl_packages['numpy'], + mpl_packages['libAgg'], + mpl_packages['cxx']) +mpl_packages['contour'] = setupext.Contour(mpl_packages['numpy']) +mpl_packages['delaunay'] = setupext.Delaunay(mpl_packages['numpy']) +mpl_packages['tri'] = setupext.Tri(mpl_packages['numpy']) + +mpl_packages['optional'] = Spacer('Optional subpackages') +mpl_packages['sample_data'] = setupext.SampleData() +mpl_packages['toolkits'] = setupext.Toolkits() +mpl_packages['tests'] = setupext.Tests() + +mpl_packages['optional backends'] = Spacer('Optional backend extensions') + +# These backends are listed in order of preference, the first +# being the most preferred. The first one that looks like it will +# work will be selected as the default backend. +mpl_packages['macosx'] = setupext.BackendMacOSX(mpl_packages['numpy'], + mpl_packages['libagg'], + mpl_packages['cxx']) +mpl_packages['qt4'] = setupext.BackendQt4() +mpl_packages['gtk3agg'] = setupext.BackendGtk3Agg() +mpl_packages['gtkcairo'] = setupext.BackendGtk3Cairo() +mpl_packages['gtkagg'] = setupext.BackendGtkAgg(mpl_packages['libagg'], + mpl_packages['cxx'], + mpl_packages['numpy']) +mpl_packages['tkagg'] = setupext.BackendTkAgg(mpl_packages['numpy'], + mpl_packages['libagg'], + mpl_packages['cxx']) +mpl_packages['wxagg'] = setupext.BackendWxAgg() +mpl_packages['gtkagg'] = setupext.BackendGtk(mpl_packages['numpy']) +mpl_packages['agg'] = setupext.BackendAgg(mpl_packages['numpy'], + mpl_packages['libagg'], + mpl_packages['freetype'], + mpl_packages['cxx']) +mpl_packages['cairo'] = setupext.BackendCairo() +mpl_packages['windowing'] = setupext.Windowing() + +mpl_packages['latex'] = Spacer('Optional LaTeX dependencies') +mpl_packages['dvipng'] = setupext.DviPng() +mpl_packages['ghostscript'] = setupext.Ghostscript() +mpl_packages['latex'] = setupext.LaTeX() +mpl_packages['pdftops'] = setupext.PdfToPs() classifiers = [ @@ -136,29 +162,30 @@ required_failed = [] good_packages = [] - for package in mpl_packages: - if isinstance(package, str): + for package in mpl_packages.items(): + if isinstance(package, Spacer): print_raw('') - print_raw(package.upper()) - else: - try: - result = package.check() - if result is not None: - message = 'yes [%s]' % result - print_status(package.name, message) - except setupext.CheckFailed as e: - msg = str(e).strip() - if len(msg): - print_status(package.name, 'no [%s]' % msg) - else: - print_status(package.name, 'no') - if not package.optional: - required_failed.append(package) + print_raw(package.text.upper()) + continue + + try: + result = package.check() + if result is not None: + message = 'yes [%s]' % result + print_status(package.name, message) + except setupext.CheckFailed as e: + msg = str(e).strip() + if len(msg): + print_status(package.name, 'no [%s]' % msg) else: - good_packages.append(package) - if isinstance(package, setupext.OptionalBackendPackage): - if default_backend is None: - default_backend = package.name + print_status(package.name, 'no') + if not package.optional: + required_failed.append(package) + else: + good_packages.append(package) + if isinstance(package, setupext.OptionalBackendPackage): + if default_backend is None: + default_backend = package.name print_raw('') diff --git a/setupext.py b/setupext.py index 62cd1d01b31d..678ade57f283 100644 --- a/setupext.py +++ b/setupext.py @@ -437,6 +437,9 @@ class CheckFailed(Exception): class SetupPackage(object): optional = False + def __init__(self, *dependencies): + self.dependencies = dependencies + def check(self): """ Checks whether the dependencies are met. Should raise a @@ -462,7 +465,6 @@ def get_namespace_packages(self): """ return [] - def get_py_modules(self): """ Get a list of top-level modules to add to the configuration. @@ -495,6 +497,10 @@ def get_install_requires(self): """ return [] + def add_dep_flags(self, ext): + for dep in self.dependencies: + dep.add_flags(ext) + def _check_for_pkg_config(self, package, include_file, min_version=None, version=None): """ @@ -955,9 +961,7 @@ def get_extension(self): 'src/mplutils.cpp' ] ext = make_extension('matplotlib.ft2font', sources) - FreeType().add_flags(ext) - Numpy().add_flags(ext) - CXX().add_flags(ext) + self.add_dep_flags(ext) return ext @@ -980,8 +984,7 @@ def get_extension(self): ext = make_extension('matplotlib._png', sources) pkg_config.setup_extension( ext, 'libpng', default_libraries=['png', 'z']) - Numpy().add_flags(ext) - CXX().add_flags(ext) + self.add_dep_flags(ext) return ext @@ -996,8 +999,7 @@ def get_extension(self): 'ttconv/ttutil.cpp' ] ext = make_extension('matplotlib.ttconv', sources) - Numpy().add_flags(ext) - CXX().add_flags(ext) + self.add_dep_flags(ext) return ext @@ -1012,9 +1014,7 @@ def get_extension(self): ] ext = make_extension('matplotlib._path', sources) - Numpy().add_flags(ext) - LibAgg().add_flags(ext) - CXX().add_flags(ext) + self.add_dep_flags(ext) return ext @@ -1026,9 +1026,7 @@ def get_extension(self): 'src/_image.cpp', 'src/mplutils.cpp' ] ext = make_extension('matplotlib._image', sources) - Numpy().add_flags(ext) - LibAgg().add_flags(ext) - CXX().add_flags(ext) + self.add_dep_flags(ext) return ext @@ -1040,7 +1038,7 @@ def get_extension(self): "src/cntr.c" ] ext = make_extension('matplotlib._cntr', sources) - Numpy().add_flags(ext) + self.add_dep_flags(ext) return ext @@ -1055,7 +1053,7 @@ def get_extension(self): "delaunay_utils.cpp", "natneighbors.cpp"] sources = [os.path.join('lib/matplotlib/delaunay', s) for s in sources] ext = make_extension('matplotlib._delaunay', sources) - Numpy().add_flags(ext) + self.add_dep_flags(ext) return ext @@ -1068,8 +1066,7 @@ def get_extension(self): "src/mplutils.cpp" ] ext = make_extension('matplotlib._tri', sources) - Numpy().add_flags(ext) - CXX().add_flags(ext) + self.add_dep_flags(ext) return ext @@ -1162,10 +1159,7 @@ def get_extension(self): "src/_backend_agg.cpp" ] ext = make_extension('matplotlib.backends._backend_agg', sources) - Numpy().add_flags(ext) - LibAgg().add_flags(ext) - FreeType().add_flags(ext) - CXX().add_flags(ext) + self.add_dep_flags(ext) return ext @@ -1213,9 +1207,7 @@ def get_extension(self): ext = make_extension('matplotlib.backends._tkagg', sources) self.add_flags(ext) - Numpy().add_flags(ext) - LibAgg().add_flags(ext) - CXX().add_flags(ext) + self.add_dep_flags(ext) return ext def query_tcltk(self): @@ -1503,7 +1495,7 @@ def get_extension(self): ] ext = make_extension('matplotlib.backends._backend_gdk', sources) self.add_flags(ext) - Numpy().add_flags(ext) + self.add_dep_flags(ext) return ext def add_flags(self, ext): @@ -1589,9 +1581,7 @@ def get_extension(self): ] ext = make_extension('matplotlib.backends._gtkagg', sources) self.add_flags(ext) - LibAgg().add_flags(ext) - CXX().add_flags(ext) - Numpy().add_flags(ext) + self.add_dep_flags(ext) return ext @@ -1766,9 +1756,7 @@ def get_extension(self): ] ext = make_extension('matplotlib.backends._macosx', sources) - Numpy().add_flags(ext) - LibAgg().add_flags(ext) - CXX().add_flags(ext) + self.add_dep_flags(ext) ext.extra_link_args.extend(['-framework', 'Cocoa']) return ext From d2d56d59ca4b73896017528be68a0e3d1c648528 Mon Sep 17 00:00:00 2001 From: Matt Terry Date: Fri, 30 Aug 2013 12:19:26 -0700 Subject: [PATCH 03/14] refactor pkg_config and ft_config --- setupext.py | 196 +++++++++++++++++++++++++++------------------------- 1 file changed, 100 insertions(+), 96 deletions(-) diff --git a/setupext.py b/setupext.py index 678ade57f283..a939fbe03811 100644 --- a/setupext.py +++ b/setupext.py @@ -329,6 +329,48 @@ def get_version(self, package): return output return None + def check_for_pkg_config(self, package, include_file, ext, + min_version=None, + version=None): + """ + A convenience function for writing checks for a + pkg_config-defined dependency. + + `package` is the pkg_config package name. + + `include_file` is a top-level include file we expect to find. + + `min_version` is the minimum version required. + + `version` will override the found version if this package + requires an alternate method for that. + """ + if version is None: + version = pkg_config.get_version(package) + + if version is None: + raise CheckFailed( + "pkg-config information for '%s' could not be found." % + package) + + if min_version == 'PATCH': + raise CheckFailed( + "Requires patches that have not been merged upstream.") + + if min_version: + if (not is_min_version(version, min_version)): + raise CheckFailed( + "Requires %s %s or later. Found %s." % + (package, min_version, version)) + + if ext is None: + ext = make_extension('test', []) + pkg_config.setup_extension(ext, package) + + check_include_file(ext.include_dirs, include_file, package) + + return 'version %s' % version + # The PkgConfig class should be used through this singleton pkg_config = PkgConfig() @@ -422,6 +464,47 @@ def get_version(self, package): return output return None + def check_for_ft_config(self, package, include_file, ext, + min_version=None, version=None): + """ + A convenience function for writing checks for a + pkg_config-defined dependency. + + `package` is the ft_config package name. + + `include_file` is a top-level include file we expect to find. + + `min_version` is the minimum version required. + + `version` will override the found version if this package + requires an alternate method for that. + """ + if version is None: + version = self.get_version(package) + + if version is None: + raise CheckFailed( + "pkg-config information for '%s' could not be found." % + package) + + if min_version == 'PATCH': + raise CheckFailed( + "Requires patches that have not been merged upstream.") + + if min_version: + if (not is_min_version(version, min_version)): + raise CheckFailed( + "Requires %s %s or later. Found %s." % + (package, min_version, version)) + + if ext is None: + ext = make_extension('test', []) + self.setup_extension(ext, package) + + check_include_file(ext.include_dirs, include_file, package) + + return 'version %s' % version + # The PkgConfig class should be used through this singleton ft_config = FTConfig() @@ -501,48 +584,6 @@ def add_dep_flags(self, ext): for dep in self.dependencies: dep.add_flags(ext) - def _check_for_pkg_config(self, package, include_file, min_version=None, - version=None): - """ - A convenience function for writing checks for a - pkg_config-defined dependency. - - `package` is the pkg_config package name. - - `include_file` is a top-level include file we expect to find. - - `min_version` is the minimum version required. - - `version` will override the found version if this package - requires an alternate method for that. - """ - if version is None: - version = pkg_config.get_version(package) - - if version is None: - raise CheckFailed( - "pkg-config information for '%s' could not be found." % - package) - - if min_version == 'PATCH': - raise CheckFailed( - "Requires patches that have not been merged upstream.") - - if min_version: - if (not is_min_version(version, min_version)): - raise CheckFailed( - "Requires %s %s or later. Found %s." % - (package, min_version, version)) - - ext = self.get_extension() - if ext is None: - ext = make_extension('test', []) - pkg_config.setup_extension(ext, package) - - check_include_file(ext.include_dirs, include_file, package) - - return 'version %s' % version - class OptionalPackage(SetupPackage): optional = True @@ -796,9 +837,11 @@ def check(self): sys.stdout = old_stdout try: - return self._check_for_pkg_config( - 'PyCXX', 'CXX/Extensions.hxx', min_version='6.2.4') - except CheckFailed as e: + return pkg_config.check_for_pkg_config('PyCXX', + 'CXX/Extensions.hxx', + self.get_ext(), + min_version='6.2.4') + except CheckFailed: # It's ok to just proceed here, since the `import CXX` # worked above, and PyCXX (at least upstream) ensures that # its header files are on the default distutils include @@ -841,8 +884,10 @@ class LibAgg(SetupPackage): def check(self): self.__class__.found_external = True try: - return self._check_for_pkg_config( - 'libagg', 'agg2/agg_basics.h', min_version='PATCH') + return pkg_config.check_for_pkg_config('libagg', + 'agg2/agg_basics.h', + self.get_ext(), + min_version='PATCH') except CheckFailed as e: self.__class__.found_external = False return str(e) + ' Using local copy.' @@ -876,58 +921,17 @@ def check(self): status, version = getstatusoutput("freetype-config --version") if status == 0: try: - return self._check_for_ft_config( - 'freetype2', 'ft2build.h', - min_version='2.4', version=version) + return ft_config.check_for_ft_config( + 'freetype2', 'ft2build.h', self.get_ext(), + min_version='2.4', version=version + ) except CheckFailed: pass - return self._check_for_pkg_config( - 'freetype2', 'ft2build.h', + return pkg_config.check_for_pkg_config( + 'freetype2', 'ft2build.h', self.get_ext(), min_version='2.4', version=None) - def _check_for_ft_config(self, package, include_file, min_version=None, - version=None): - """ - A convenience function for writing checks for a - pkg_config-defined dependency. - - `package` is the ft_config package name. - - `include_file` is a top-level include file we expect to find. - - `min_version` is the minimum version required. - - `version` will override the found version if this package - requires an alternate method for that. - """ - if version is None: - version = ft_config.get_version(package) - - if version is None: - raise CheckFailed( - "pkg-config information for '%s' could not be found." % - package) - - if min_version == 'PATCH': - raise CheckFailed( - "Requires patches that have not been merged upstream.") - - if min_version: - if (not is_min_version(version, min_version)): - raise CheckFailed( - "Requires %s %s or later. Found %s." % - (package, min_version, version)) - - ext = self.get_extension() - if ext is None: - ext = make_extension('test', []) - ft_config.setup_extension(ext, package) - - check_include_file(ext.include_dirs, include_file, package) - - return 'version %s' % version - def add_flags(self, ext): if ft_config.has_ftconfig: ft_config.setup_extension( @@ -970,8 +974,8 @@ class Png(SetupPackage): def check(self): try: - return self._check_for_pkg_config( - 'libpng', 'png.h', + return pkg_config.check_for_pkg_config( + 'libpng', 'png.h', self.get_ext(), min_version='1.2') except CheckFailed as e: self.__class__.found_external = False From 4daac477c773ec8ca80b6a72c5145c5f791ef504 Mon Sep 17 00:00:00 2001 From: Matt Terry Date: Tue, 3 Sep 2013 11:55:51 -0700 Subject: [PATCH 04/14] use self --- setupext.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setupext.py b/setupext.py index a939fbe03811..365859e11884 100644 --- a/setupext.py +++ b/setupext.py @@ -346,7 +346,7 @@ def check_for_pkg_config(self, package, include_file, ext, requires an alternate method for that. """ if version is None: - version = pkg_config.get_version(package) + version = self.get_version(package) if version is None: raise CheckFailed( @@ -365,7 +365,7 @@ def check_for_pkg_config(self, package, include_file, ext, if ext is None: ext = make_extension('test', []) - pkg_config.setup_extension(ext, package) + self.setup_extension(ext, package) check_include_file(ext.include_dirs, include_file, package) From ad7336a4dc4ed814bee77eeac0b89f2c1fba7487 Mon Sep 17 00:00:00 2001 From: Matt Terry Date: Tue, 3 Sep 2013 11:59:52 -0700 Subject: [PATCH 05/14] FreetypeConfig and PkgConfig share parent --- setupext.py | 250 ++++++++++++++++------------------------------------ 1 file changed, 74 insertions(+), 176 deletions(-) diff --git a/setupext.py b/setupext.py index 365859e11884..509a9595b68e 100644 --- a/setupext.py +++ b/setupext.py @@ -240,98 +240,72 @@ def make_extension(name, files, *args, **kwargs): return ext -class PkgConfig(object): +class Configurator(object): """ This is a class for communicating with pkg-config. """ - def __init__(self): + def __init__(self, config_command): """ Determines whether pkg-config exists on this machine. """ + self.config_command = config_command + if sys.platform == 'win32': - self.has_pkgconfig = False + self.has_config = False else: - self.set_pkgconfig_path() - status, output = getstatusoutput("pkg-config --help") - self.has_pkgconfig = (status == 0) - - def set_pkgconfig_path(self): - pkgconfig_path = sysconfig.get_config_var('LIBDIR') - if pkgconfig_path is None: - return + self.set_config_path() + status, output = getstatusoutput(self.config_command + ' --help') + self.has_config = (status == 0) - pkgconfig_path = os.path.join(pkgconfig_path, 'pkgconfig') - if not os.path.isdir(pkgconfig_path): - return - - try: - os.environ['PKG_CONFIG_PATH'] += ':' + pkgconfig_path - except KeyError: - os.environ['PKG_CONFIG_PATH'] = pkgconfig_path + def set_config_path(self): + """Use for extra setup""" + pass - def setup_extension(self, ext, package, default_include_dirs=[], - default_library_dirs=[], default_libraries=[], - alt_exec=None): + def setup_extension(self, ext, package, + default_include_dirs=[], + default_library_dirs=[], default_libraries=[]): """ Add parameters to the given `ext` for the given `package`. """ flag_map = { '-I': 'include_dirs', '-L': 'library_dirs', '-l': 'libraries'} - executable = alt_exec - if self.has_pkgconfig: - executable = 'pkg-config {0}'.format(package) - - use_defaults = True - - if executable is not None: - command = "{0} --libs --cflags ".format(executable) + if self.has_config: + command = "{cfg} {pkg} --libs --cflags".format( + cfg=self.config_command, pkg=package) try: - output = check_output(command, shell=True, + output = check_output(command, + shell=True, stderr=subprocess.STDOUT) except subprocess.CalledProcessError: pass else: output = output.decode(sys.getfilesystemencoding()) - use_defaults = False for token in output.split(): attr = flag_map.get(token[:2]) if attr is not None: getattr(ext, attr).append(token[2:]) - - if use_defaults: - basedirs = get_base_dirs() - for base in basedirs: - for include in default_include_dirs: - dir = os.path.join(base, include) - if os.path.exists(dir): - ext.include_dirs.append(dir) - for lib in default_library_dirs: - dir = os.path.join(base, lib) - if os.path.exists(dir): - ext.library_dirs.append(dir) - ext.libraries.extend(default_libraries) - return True - - return False + return + + # couldn't find library, fallback to looking in default paths + basedirs = get_base_dirs() + for base in basedirs: + for include in default_include_dirs: + d = os.path.join(base, include) + if os.path.exists(d): + ext.include_dirs.append(d) + for lib in default_library_dirs: + d = os.path.join(base, lib) + if os.path.exists(d): + ext.library_dirs.append(d) + ext.libraries.extend(default_libraries) def get_version(self, package): - """ - Get the version of the package from pkg-config. - """ - if not self.ft_config: - return None + raise NotImplementedError() - status, output = getstatusoutput( - "pkg-config %s --modversion" % (package)) - if status == 0: - return output - return None - - def check_for_pkg_config(self, package, include_file, ext, - min_version=None, - version=None): + def check_for_config(self, package, include_file, ext, + min_version=None, version=None): """ A convenience function for writing checks for a pkg_config-defined dependency. @@ -350,8 +324,8 @@ def check_for_pkg_config(self, package, include_file, ext, if version is None: raise CheckFailed( - "pkg-config information for '%s' could not be found." % - package) + "%s information for '%s' could not be found." % + (self.config_command, package)) if min_version == 'PATCH': raise CheckFailed( @@ -372,28 +346,12 @@ def check_for_pkg_config(self, package, include_file, ext, return 'version %s' % version -# The PkgConfig class should be used through this singleton -pkg_config = PkgConfig() - +class PkgConfig(Configurator): -class FTConfig(object): - """ - This is a class for communicating with freetype-config. - """ - def __init__(self): - """ - Determines whether freetype-config exists on this machine. - """ - if sys.platform == 'win32': - self.has_ftconfig = False - else: - self.set_pkgconfig_path() - status, output = getstatusoutput("freetype-config --help") - self.has_ftconfig = (status == 0) - - def set_pkgconfig_path(self): - pkgconfig_path = sysconfig.get_config_var('LIBDIR') - if pkgconfig_path is None: + def set_config_path(self): + # ask python if it has a pkg-config libdir + config_path = sysconfig.get_config_var('LIBDIR') + if config_path is None: return pkgconfig_path = os.path.join(pkgconfig_path, 'pkgconfig') @@ -405,58 +363,36 @@ def set_pkgconfig_path(self): except KeyError: os.environ['PKG_CONFIG_PATH'] = pkgconfig_path - def setup_extension(self, ext, package, default_include_dirs=[], - default_library_dirs=[], default_libraries=[]): + def get_version(self, package): """ - Add parameters to the given `ext` for the given `package`. + Get the version of the package from pkg-config. """ - flag_map = { - '-I': 'include_dirs', '-L': 'library_dirs', '-l': 'libraries'} + if not self.has_config: + return None - if package != 'freetype2': - raise RuntimeError("FTConfig only works for the freetype2 package") + status, output = getstatusoutput( + "pkg-config %s --modversion" % package) + if status == 0: + return output + return None - use_defaults = True - if self.has_ftconfig: - try: - output = check_output("freetype-config --libs --cflags", - shell=True, - stderr=subprocess.STDOUT) - except subprocess.CalledProcessError: - pass - else: - output = output.decode(sys.getfilesystemencoding()) - use_defaults = False - for token in output.split(): - attr = flag_map.get(token[:2]) - if attr is not None: - getattr(ext, attr).append(token[2:]) +class FreetypeConfig(Configurator): + """This is a class for communicating with freetype-config.""" - if use_defaults: - basedirs = get_base_dirs() - for base in basedirs: - for include in default_include_dirs: - dir = os.path.join(base, include) - if os.path.exists(dir): - ext.include_dirs.append(dir) - for lib in default_library_dirs: - dir = os.path.join(base, lib) - if os.path.exists(dir): - ext.library_dirs.append(dir) - ext.libraries.extend(default_libraries) - return True - - return False + def setup_extension(self, ext, package, **kw): + """Add parameters to the given `ext` for the given `package`.""" + if package != 'freetype2': + raise RuntimeError('package must be "freetype2"') + package = '' + return super(FreetypeConfig, self).setup_extension(ext, package, **kw) def get_version(self, package): - """ - Get the version from freetype-config. - """ + """Get the version from freetype-config.""" if package != 'freetype2': - raise RuntimeError("FTConfig only works for the freetype2 package") + raise RuntimeError('package must be "freetype2"') - if not self.ft_config: + if not self.has_config: return None status, output = getstatusoutput("freetype-config --ftversion") @@ -464,50 +400,12 @@ def get_version(self, package): return output return None - def check_for_ft_config(self, package, include_file, ext, - min_version=None, version=None): - """ - A convenience function for writing checks for a - pkg_config-defined dependency. - - `package` is the ft_config package name. - - `include_file` is a top-level include file we expect to find. - - `min_version` is the minimum version required. - - `version` will override the found version if this package - requires an alternate method for that. - """ - if version is None: - version = self.get_version(package) - - if version is None: - raise CheckFailed( - "pkg-config information for '%s' could not be found." % - package) - if min_version == 'PATCH': - raise CheckFailed( - "Requires patches that have not been merged upstream.") - if min_version: - if (not is_min_version(version, min_version)): - raise CheckFailed( - "Requires %s %s or later. Found %s." % - (package, min_version, version)) - - if ext is None: - ext = make_extension('test', []) - self.setup_extension(ext, package) - check_include_file(ext.include_dirs, include_file, package) - - return 'version %s' % version - - -# The PkgConfig class should be used through this singleton -ft_config = FTConfig() +# The PkgConfig/FreetypeConfig class should be used through singletons +pkg_config = PkgConfig('pkg-config') +ft_config = FreetypeConfig('freetype-config') class CheckFailed(Exception): @@ -884,10 +782,10 @@ class LibAgg(SetupPackage): def check(self): self.__class__.found_external = True try: - return pkg_config.check_for_pkg_config('libagg', - 'agg2/agg_basics.h', - self.get_ext(), - min_version='PATCH') + return pkg_config.check_for_config('libagg', + 'agg2/agg_basics.h', + self.get_ext(), + min_version='PATCH') except CheckFailed as e: self.__class__.found_external = False return str(e) + ' Using local copy.' @@ -921,19 +819,19 @@ def check(self): status, version = getstatusoutput("freetype-config --version") if status == 0: try: - return ft_config.check_for_ft_config( + return ft_config.check_for_config( 'freetype2', 'ft2build.h', self.get_ext(), min_version='2.4', version=version ) except CheckFailed: pass - return pkg_config.check_for_pkg_config( + return pkg_config.check_for_config( 'freetype2', 'ft2build.h', self.get_ext(), min_version='2.4', version=None) def add_flags(self, ext): - if ft_config.has_ftconfig: + if ft_config.has_config: ft_config.setup_extension( ext, 'freetype2', default_include_dirs=[ @@ -974,7 +872,7 @@ class Png(SetupPackage): def check(self): try: - return pkg_config.check_for_pkg_config( + return pkg_config.check_for_config( 'libpng', 'png.h', self.get_ext(), min_version='1.2') except CheckFailed as e: From 89c582dad57ace40f696e4a73ba049226bddc5b1 Mon Sep 17 00:00:00 2001 From: Matt Terry Date: Tue, 3 Sep 2013 12:00:42 -0700 Subject: [PATCH 06/14] add LibpngConfig --- setupext.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/setupext.py b/setupext.py index 509a9595b68e..406ec67e1755 100644 --- a/setupext.py +++ b/setupext.py @@ -401,11 +401,29 @@ def get_version(self, package): return None +class LibpngConfig(Configurator): + + def setup_extension(self, ext, package, **kw): + """Add parameters to the given `ext` for the given `package`.""" + if package != 'freetype2': + raise RuntimeError('package must be "freetype2"') + package = '' + return super(LibpngConfig, self).setup_extension(ext, package, **kw) + + def get_version(self, package): + if package != 'libpng': + raise RuntimeError('package must be libpng') + + status, output = getstatusoutput('libpng-config --version') + if status == 0: + return output + return None # The PkgConfig/FreetypeConfig class should be used through singletons pkg_config = PkgConfig('pkg-config') ft_config = FreetypeConfig('freetype-config') +png_config = LibpngConfig('libpng-config') class CheckFailed(Exception): From 24217e5e7f881a4a65886169dce76c84083d08c4 Mon Sep 17 00:00:00 2001 From: Matt Terry Date: Tue, 3 Sep 2013 12:02:39 -0700 Subject: [PATCH 07/14] prettify --- setupext.py | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/setupext.py b/setupext.py index 406ec67e1755..cbe69760017a 100644 --- a/setupext.py +++ b/setupext.py @@ -143,9 +143,9 @@ def get_base_dirs(): return options['basedirlist'] basedir_map = { - 'win32': ['win32_static',], + 'win32': ['win32_static'], 'darwin': ['/usr/local/', '/usr', '/usr/X11', '/opt/local'], - 'sunos5': [os.getenv('MPLIB_BASE') or '/usr/local',], + 'sunos5': [os.getenv('MPLIB_BASE') or '/usr/local'], 'gnu0': ['/usr'], 'aix5': ['/usr/local'], } @@ -588,8 +588,7 @@ def get_py_modules(self): def get_package_data(self): return { - 'matplotlib': - [ + 'matplotlib': [ 'mpl-data/fonts/afm/*.afm', 'mpl-data/fonts/pdfcorefonts/*.afm', 'mpl-data/fonts/pdfcorefonts/*.txt', @@ -610,8 +609,9 @@ def get_package_data(self): 'backends/web_backend/jquery/css/themes/base/*.*', 'backends/web_backend/jquery/css/themes/base/images/*', 'backends/web_backend/css/*.*', - 'backends/Matplotlib.nib/*' - ]} + 'backends/Matplotlib.nib/*', + ], + } class SampleData(OptionalPackage): @@ -707,8 +707,8 @@ def check(self): ext = make_extension('test', []) ext.include_dirs.append(numpy.get_include()) - if not has_include_file( - ext.include_dirs, os.path.join("numpy", "arrayobject.h")): + if not has_include_file(ext.include_dirs, + os.path.join("numpy", "arrayobject.h")): raise CheckFailed( "The C headers for numpy could not be found. You" "may need to install the development package.") @@ -768,12 +768,12 @@ def check(self): def add_flags(self, ext): if self.found_external and not 'sdist' in sys.argv: support_dir = os.path.normpath( - os.path.join( - sys.prefix, - 'share', - 'python%d.%d' % ( - sys.version_info[0], sys.version_info[1]), - 'CXX')) + os.path.join( + sys.prefix, + 'share', + 'python%d.%d' % (sys.version_info[0], sys.version_info[1]), + 'CXX') + ) if not os.path.exists(support_dir): # On Fedora 17, these files are installed in /usr/share/CXX support_dir = '/usr/src/CXX' @@ -1197,7 +1197,7 @@ def parse_tcl_config(self, tcl_lib_dir, tk_lib_dir): "/usr/lib/tcl" + str(Tkinter.TclVersion), "/usr/lib"] tk_poss = [tk_lib_dir, - os.path.normpath(os.path.join(tk_lib_dir, '..')), + os.path.normpath(os.path.join(tk_lib_dir, '..')), "/usr/lib/tk" + str(Tkinter.TkVersion), "/usr/lib"] for ptcl, ptk in zip(tcl_poss, tk_poss): @@ -1265,9 +1265,9 @@ def guess_tcl_config(self, tcl_lib_dir, tk_lib_dir, tk_ver): if not os.path.exists(tcl_inc): # this is a hack for suse linux, which is broken - if (sys.platform.startswith('linux') and - os.path.exists('/usr/include/tcl.h') and - os.path.exists('/usr/include/tk.h')): + if all([sys.platform.startswith('linux'), + os.path.exists('/usr/include/tcl.h'), + os.path.exists('/usr/include/tk.h')]): tcl_inc = '/usr/include' tk_inc = '/usr/include' @@ -1469,9 +1469,9 @@ def getoutput(s): (flag.startswith('-l') or flag.startswith('-L'))]) # visual studio doesn't need the math library - if (sys.platform == 'win32' and - win32_compiler == 'msvc' and - 'm' in ext.libraries): + if all([sys.platform == 'win32', + win32_compiler == 'msvc', + 'm' in ext.libraries]): ext.libraries.remove('m') elif sys.platform != 'win32': From a9e864f08ece35ca86fa9abe7a1c47f968f608de Mon Sep 17 00:00:00 2001 From: Matt Terry Date: Tue, 3 Sep 2013 12:03:03 -0700 Subject: [PATCH 08/14] function changed name --- setupext.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setupext.py b/setupext.py index cbe69760017a..aefab6a57dfd 100644 --- a/setupext.py +++ b/setupext.py @@ -753,10 +753,10 @@ def check(self): sys.stdout = old_stdout try: - return pkg_config.check_for_pkg_config('PyCXX', - 'CXX/Extensions.hxx', - self.get_ext(), - min_version='6.2.4') + return pkg_config.check_for_config('PyCXX', + 'CXX/Extensions.hxx', + self.get_ext(), + min_version='6.2.4') except CheckFailed: # It's ok to just proceed here, since the `import CXX` # worked above, and PyCXX (at least upstream) ensures that From fccafe9b1eeab58ca3ecabb27d6b6247b5325c7e Mon Sep 17 00:00:00 2001 From: Matt Terry Date: Tue, 3 Sep 2013 12:39:45 -0700 Subject: [PATCH 09/14] remove OrderedDict dependency --- setup.py | 129 +++++++++++++++++++++++++------------------------------ 1 file changed, 59 insertions(+), 70 deletions(-) diff --git a/setup.py b/setup.py index 5a1c8c2d31bf..02f0d8c07841 100644 --- a/setup.py +++ b/setup.py @@ -4,13 +4,13 @@ """ from __future__ import print_function, absolute_import -from collections import OrderedDict, namedtuple # This needs to be the very first thing to use distribute from distribute_setup import use_setuptools use_setuptools() import sys +from collections import namedtuple # distutils is breaking our sdists for files in symlinked dirs. # distutils will copy if os.link is not available, so this is a hack @@ -59,74 +59,63 @@ Spacer = namedtuple('Spacer', ['text']) -mpl_packages = OrderedDict() - -mpl_packages['building'] = Spacer('Building Matplotlib') -mpl_packages['matplotlib'] = setupext.Matplotlib() -mpl_packages['python'] = setupext.Python() -mpl_packages['platform'] = setupext.Platform() - -mpl_packages['required'] = Spacer('Required dependencies and extensions') -mpl_packages['numpy'] = setupext.Numpy() -mpl_packages['dateutil'] = setupext.Dateutil() -mpl_packages['tornado'] = setupext.Tornado() -mpl_packages['pyparsing'] = setupext.Pyparsing() -mpl_packages['cxx'] = setupext.CXX() -mpl_packages['libagg'] = setupext.LibAgg() -mpl_packages['freetype'] = setupext.FreeType() -mpl_packages['ft2font'] = setupext.FT2Font(mpl_packages['freetype'], - mpl_packages['numpy'], - mpl_packages['cxx']) -mpl_packages['png'] = setupext.Png(mpl_packages['numpy'], - mpl_packages['cxx']) -mpl_packages['image'] = setupext.Image(mpl_packages['numpy'], - mpl_packages['libagg'], - mpl_packages['cxx']) -mpl_packages['ttconv'] = setupext.TTConv(mpl_packages['numpy'], - mpl_packages['cxx']) -mpl_packages['path'] = setupext.Path(mpl_packages['numpy'], - mpl_packages['libAgg'], - mpl_packages['cxx']) -mpl_packages['contour'] = setupext.Contour(mpl_packages['numpy']) -mpl_packages['delaunay'] = setupext.Delaunay(mpl_packages['numpy']) -mpl_packages['tri'] = setupext.Tri(mpl_packages['numpy']) - -mpl_packages['optional'] = Spacer('Optional subpackages') -mpl_packages['sample_data'] = setupext.SampleData() -mpl_packages['toolkits'] = setupext.Toolkits() -mpl_packages['tests'] = setupext.Tests() - -mpl_packages['optional backends'] = Spacer('Optional backend extensions') - -# These backends are listed in order of preference, the first -# being the most preferred. The first one that looks like it will -# work will be selected as the default backend. -mpl_packages['macosx'] = setupext.BackendMacOSX(mpl_packages['numpy'], - mpl_packages['libagg'], - mpl_packages['cxx']) -mpl_packages['qt4'] = setupext.BackendQt4() -mpl_packages['gtk3agg'] = setupext.BackendGtk3Agg() -mpl_packages['gtkcairo'] = setupext.BackendGtk3Cairo() -mpl_packages['gtkagg'] = setupext.BackendGtkAgg(mpl_packages['libagg'], - mpl_packages['cxx'], - mpl_packages['numpy']) -mpl_packages['tkagg'] = setupext.BackendTkAgg(mpl_packages['numpy'], - mpl_packages['libagg'], - mpl_packages['cxx']) -mpl_packages['wxagg'] = setupext.BackendWxAgg() -mpl_packages['gtkagg'] = setupext.BackendGtk(mpl_packages['numpy']) -mpl_packages['agg'] = setupext.BackendAgg(mpl_packages['numpy'], - mpl_packages['libagg'], - mpl_packages['freetype'], - mpl_packages['cxx']) -mpl_packages['cairo'] = setupext.BackendCairo() -mpl_packages['windowing'] = setupext.Windowing() - -mpl_packages['latex'] = Spacer('Optional LaTeX dependencies') -mpl_packages['dvipng'] = setupext.DviPng() -mpl_packages['ghostscript'] = setupext.Ghostscript() -mpl_packages['latex'] = setupext.LaTeX() -mpl_packages['pdftops'] = setupext.PdfToPs() +# these packages are dependencies for other packages +# give them names so that we can reference them later +numpy_ext = setupext.Numpy() +cxx_ext = setupext.CXX() +libagg_ext = setupext.LibAgg() +freetype_ext = setupext.FreeType() + +mpl_packages = [ + Spacer('Building Matplotlib'), + setupext.Matplotlib(), + setupext.Python(), + setupext.Platform(), + + Spacer('Required dependencies and extensions'), + numpy_ext, + setupext.Dateutil(), + setupext.Tornado(), + setupext.Pyparsing(), + cxx_ext, + libagg_ext, + freetype_ext, + setupext.FT2Font(freetype_ext, numpy_ext, cxx_ext), + setupext.Png(numpy_ext, cxx_ext), + setupext.Image(numpy_ext, libagg_ext, cxx_ext), + setupext.TTConv(numpy_ext, cxx_ext), + setupext.Path(numpy_ext, libagg_ext, cxx_ext), + setupext.Contour(numpy_ext), + setupext.Delaunay(numpy_ext), + setupext.Tri(numpy_ext), + + Spacer('Optional subpackages'), + setupext.SampleData(), + setupext.Toolkits(), + setupext.Tests(), + + Spacer('Optional backend extensions'), + # These backends are listed in order of preference, the first + # being the most preferred. The first one that looks like it will + # work will be selected as the default backend. + setupext.BackendMacOSX(numpy_ext, libagg_ext, cxx_ext), + setupext.BackendQt4(), + setupext.BackendGtk3Agg(), + setupext.BackendGtk3Cairo(), + setupext.BackendGtkAgg(libagg_ext, cxx_ext, numpy_ext), + setupext.BackendTkAgg(numpy_ext, libagg_ext, cxx_ext), + setupext.BackendWxAgg(), + setupext.BackendGtk(numpy_ext), + setupext.BackendAgg(numpy_ext, libagg_ext, freetype_ext, cxx_ext), + setupext.BackendCairo(), + setupext.Windowing(), + + Spacer('Optional LaTeX dependencies'), + setupext.DviPng(), + setupext.Ghostscript(), + setupext.LaTeX(), + setupext.PdfToPs(), +] classifiers = [ @@ -162,7 +151,7 @@ required_failed = [] good_packages = [] - for package in mpl_packages.items(): + for package in mpl_packages: if isinstance(package, Spacer): print_raw('') print_raw(package.text.upper()) From e56c0ebaacbd10d28889bd1a53803e17876efd66 Mon Sep 17 00:00:00 2001 From: Matt Terry Date: Tue, 3 Sep 2013 12:52:00 -0700 Subject: [PATCH 10/14] better names --- setup.py | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/setup.py b/setup.py index 02f0d8c07841..3b44cb712b82 100644 --- a/setup.py +++ b/setup.py @@ -61,10 +61,10 @@ # these packages are dependencies for other packages # give them names so that we can reference them later -numpy_ext = setupext.Numpy() -cxx_ext = setupext.CXX() -libagg_ext = setupext.LibAgg() -freetype_ext = setupext.FreeType() +numpy_pkg = setupext.Numpy() +cxx_pkg = setupext.CXX() +libagg_pkg = setupext.LibAgg() +freetype_pkg = setupext.FreeType() mpl_packages = [ Spacer('Building Matplotlib'), @@ -73,21 +73,21 @@ setupext.Platform(), Spacer('Required dependencies and extensions'), - numpy_ext, + numpy_pkg, setupext.Dateutil(), setupext.Tornado(), setupext.Pyparsing(), - cxx_ext, - libagg_ext, - freetype_ext, - setupext.FT2Font(freetype_ext, numpy_ext, cxx_ext), - setupext.Png(numpy_ext, cxx_ext), - setupext.Image(numpy_ext, libagg_ext, cxx_ext), - setupext.TTConv(numpy_ext, cxx_ext), - setupext.Path(numpy_ext, libagg_ext, cxx_ext), - setupext.Contour(numpy_ext), - setupext.Delaunay(numpy_ext), - setupext.Tri(numpy_ext), + cxx_pkg, + libagg_pkg, + freetype_pkg, + setupext.FT2Font(freetype_pkg, numpy_pkg, cxx_pkg), + setupext.Png(numpy_pkg, cxx_pkg), + setupext.Image(numpy_pkg, libagg_pkg, cxx_pkg), + setupext.TTConv(numpy_pkg, cxx_pkg), + setupext.Path(numpy_pkg, libagg_pkg, cxx_pkg), + setupext.Contour(numpy_pkg), + setupext.Delaunay(numpy_pkg), + setupext.Tri(numpy_pkg), Spacer('Optional subpackages'), setupext.SampleData(), @@ -98,15 +98,15 @@ # These backends are listed in order of preference, the first # being the most preferred. The first one that looks like it will # work will be selected as the default backend. - setupext.BackendMacOSX(numpy_ext, libagg_ext, cxx_ext), + setupext.BackendMacOSX(numpy_pkg, libagg_pkg, cxx_pkg), setupext.BackendQt4(), setupext.BackendGtk3Agg(), setupext.BackendGtk3Cairo(), - setupext.BackendGtkAgg(libagg_ext, cxx_ext, numpy_ext), - setupext.BackendTkAgg(numpy_ext, libagg_ext, cxx_ext), + setupext.BackendGtkAgg(libagg_pkg, cxx_pkg, numpy_pkg), + setupext.BackendTkAgg(numpy_pkg, libagg_pkg, cxx_pkg), setupext.BackendWxAgg(), - setupext.BackendGtk(numpy_ext), - setupext.BackendAgg(numpy_ext, libagg_ext, freetype_ext, cxx_ext), + setupext.BackendGtk(numpy_pkg), + setupext.BackendAgg(numpy_pkg, libagg_pkg, freetype_pkg, cxx_pkg), setupext.BackendCairo(), setupext.Windowing(), From b1fc8ffe0d898861f8dc9b9502f35f3edf45f99f Mon Sep 17 00:00:00 2001 From: Matt Terry Date: Tue, 3 Sep 2013 12:57:15 -0700 Subject: [PATCH 11/14] tweak SetupPackage API --- setup.py | 29 ++++++++++++++++------------- setupext.py | 4 ++-- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/setup.py b/setup.py index 3b44cb712b82..772048cb57ea 100644 --- a/setup.py +++ b/setup.py @@ -80,14 +80,14 @@ cxx_pkg, libagg_pkg, freetype_pkg, - setupext.FT2Font(freetype_pkg, numpy_pkg, cxx_pkg), - setupext.Png(numpy_pkg, cxx_pkg), - setupext.Image(numpy_pkg, libagg_pkg, cxx_pkg), - setupext.TTConv(numpy_pkg, cxx_pkg), - setupext.Path(numpy_pkg, libagg_pkg, cxx_pkg), - setupext.Contour(numpy_pkg), - setupext.Delaunay(numpy_pkg), - setupext.Tri(numpy_pkg), + setupext.FT2Font(dependencies=[freetype_pkg, numpy_pkg, cxx_pkg]), + setupext.Png(dependencies=[numpy_pkg, cxx_pkg]), + setupext.Image(dependencies=[numpy_pkg, libagg_pkg, cxx_pkg]), + setupext.TTConv(dependencies=[numpy_pkg, cxx_pkg]), + setupext.Path(dependencies=[numpy_pkg, libagg_pkg, cxx_pkg]), + setupext.Contour(dependencies=[numpy_pkg]), + setupext.Delaunay(dependencies=[numpy_pkg]), + setupext.Tri(dependencies=[numpy_pkg]), Spacer('Optional subpackages'), setupext.SampleData(), @@ -98,15 +98,18 @@ # These backends are listed in order of preference, the first # being the most preferred. The first one that looks like it will # work will be selected as the default backend. - setupext.BackendMacOSX(numpy_pkg, libagg_pkg, cxx_pkg), + setupext.BackendMacOSX(dependencies=[numpy_pkg, libagg_pkg, cxx_pkg]), setupext.BackendQt4(), setupext.BackendGtk3Agg(), setupext.BackendGtk3Cairo(), - setupext.BackendGtkAgg(libagg_pkg, cxx_pkg, numpy_pkg), - setupext.BackendTkAgg(numpy_pkg, libagg_pkg, cxx_pkg), + setupext.BackendGtkAgg(dependencies=[libagg_pkg, cxx_pkg, numpy_pkg]), + setupext.BackendTkAgg(dependencies=[numpy_pkg, libagg_pkg, cxx_pkg]), setupext.BackendWxAgg(), - setupext.BackendGtk(numpy_pkg), - setupext.BackendAgg(numpy_pkg, libagg_pkg, freetype_pkg, cxx_pkg), + setupext.BackendGtk(dependencies=[numpy_pkg]), + setupext.BackendAgg(dependencies=[numpy_pkg, + libagg_pkg, + freetype_pkg, + cxx_pkg]), setupext.BackendCairo(), setupext.Windowing(), diff --git a/setupext.py b/setupext.py index aefab6a57dfd..cbe2edecaaba 100644 --- a/setupext.py +++ b/setupext.py @@ -436,8 +436,8 @@ class CheckFailed(Exception): class SetupPackage(object): optional = False - def __init__(self, *dependencies): - self.dependencies = dependencies + def __init__(self, dependencies=None): + self.dependencies = dependencies if dependencies is not None else [] def check(self): """ From a8fbfc7e7810df2ac6ae407ec5c7907812b392e1 Mon Sep 17 00:00:00 2001 From: Matt Terry Date: Tue, 3 Sep 2013 15:19:40 -0700 Subject: [PATCH 12/14] get_extension spelled out --- setupext.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setupext.py b/setupext.py index cbe2edecaaba..c64a9420786d 100644 --- a/setupext.py +++ b/setupext.py @@ -755,7 +755,7 @@ def check(self): try: return pkg_config.check_for_config('PyCXX', 'CXX/Extensions.hxx', - self.get_ext(), + self.get_extension(), min_version='6.2.4') except CheckFailed: # It's ok to just proceed here, since the `import CXX` @@ -802,7 +802,7 @@ def check(self): try: return pkg_config.check_for_config('libagg', 'agg2/agg_basics.h', - self.get_ext(), + self.get_extension(), min_version='PATCH') except CheckFailed as e: self.__class__.found_external = False @@ -838,14 +838,14 @@ def check(self): if status == 0: try: return ft_config.check_for_config( - 'freetype2', 'ft2build.h', self.get_ext(), + 'freetype2', 'ft2build.h', self.get_extension(), min_version='2.4', version=version ) except CheckFailed: pass return pkg_config.check_for_config( - 'freetype2', 'ft2build.h', self.get_ext(), + 'freetype2', 'ft2build.h', self.get_extension(), min_version='2.4', version=None) def add_flags(self, ext): @@ -891,7 +891,7 @@ class Png(SetupPackage): def check(self): try: return pkg_config.check_for_config( - 'libpng', 'png.h', self.get_ext(), + 'libpng', 'png.h', self.get_extension(), min_version='1.2') except CheckFailed as e: self.__class__.found_external = False From 9451b9f64632feb1f697d219b0c50468d20df965 Mon Sep 17 00:00:00 2001 From: Matt Terry Date: Tue, 3 Sep 2013 15:24:09 -0700 Subject: [PATCH 13/14] don't use config_path before it exists --- setupext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setupext.py b/setupext.py index c64a9420786d..20b7ff89ead7 100644 --- a/setupext.py +++ b/setupext.py @@ -354,7 +354,7 @@ def set_config_path(self): if config_path is None: return - pkgconfig_path = os.path.join(pkgconfig_path, 'pkgconfig') + pkgconfig_path = os.path.join(config_path, 'pkgconfig') if not os.path.isdir(pkgconfig_path): return From 43e49abc255c163fc5f1a3dadb4a8482f5426edb Mon Sep 17 00:00:00 2001 From: Matt Terry Date: Tue, 3 Sep 2013 15:25:15 -0700 Subject: [PATCH 14/14] BackendTkAgg needs to call parent __init__ --- setupext.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setupext.py b/setupext.py index 20b7ff89ead7..b10013fcfdcc 100644 --- a/setupext.py +++ b/setupext.py @@ -1086,8 +1086,9 @@ def get_extension(self): class BackendTkAgg(OptionalBackendPackage): name = "tkagg" - def __init__(self): + def __init__(self, **kw): self.tcl_tk_cache = None + OptionalBackendPackage.__init__(self, **kw) def check(self): if self.get_config() is False: