diff --git a/.appveyor.yml b/.appveyor.yml
index b60e1f6133cb..cbc7e687af8d 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -84,7 +84,6 @@ install:
# and for the wheels
- del %LIBRARY_LIB%\png.lib
- del %LIBRARY_LIB%\z.lib
- - set MPLBASEDIRLIST=%CONDA_PREFIX%\Library\;.
# enables the local freetype build
- set MPLLOCALFREETYPE=1
# Show the installed packages + versions
@@ -92,6 +91,7 @@ install:
test_script:
# Now build the thing..
+ - set LINK=/LIBPATH:%cd%\lib
- pip install -ve .
# these should show no z, png, or freetype dll...
- set "DUMPBIN=%VS140COMNTOOLS%\..\..\VC\bin\dumpbin.exe"
diff --git a/INSTALL.rst b/INSTALL.rst
index 704e76193fef..ec0c74930812 100644
--- a/INSTALL.rst
+++ b/INSTALL.rst
@@ -174,10 +174,35 @@ etc., you can install the following:
.. note::
- Matplotlib depends on non-Python libraries. `pkg-config
- `_ can be used
- to find required non-Python libraries and thus make the install go more
- smoothly if the libraries and headers are not in the expected locations.
+ Matplotlib depends on non-Python libraries.
+
+ On Linux and OSX, pkg-config_ can be used to find required non-Python
+ libraries and thus make the install go more smoothly if the libraries and
+ headers are not in the expected locations.
+
+ .. _pkg-config: https://www.freedesktop.org/wiki/Software/pkg-config/
+
+ If not using pkg-config (in particular on Windows), you may need to set the
+ include path (to the FreeType, libpng, and zlib headers) and link path (to
+ the FreeType, libpng, and zlib libraries) explicitly, if they are not in
+ standard locations. This can be done using standard environment variables
+ -- on Linux and OSX:
+
+ .. code-block:: sh
+
+ export CFLAGS='-I/directory/containing/ft2build.h ...'
+ export LDFLAGS='-L/directory/containing/libfreetype.so ...'
+
+ and on Windows:
+
+ .. code-block:: bat
+
+ set CL=/IC:\directory\containing\ft2build.h ...
+ set LINK=/LIBPATH:C:\directory\containing\freetype.lib ...
+
+ where ``...`` means "also give, in the same format, the directories
+ containing ``png.h`` and ``zlib.h`` for the include path, and for
+ ``libpng.so``/``png.lib`` and ``libz.so``/``z.lib`` for the link path."
.. note::
diff --git a/build_alllocal.cmd b/build_alllocal.cmd
index 4a3aba3a0275..535042e08a66 100644
--- a/build_alllocal.cmd
+++ b/build_alllocal.cmd
@@ -23,9 +23,5 @@ mkdir lib || cmd /c "exit /b 0"
copy %LIBRARY_LIB%\zlibstatic.lib lib\z.lib
copy %LIBRARY_LIB%\libpng_static.lib lib\png.lib
-:: Make the header files and the rest of the static libs available during the build
-:: CONDA_PREFIX is a env variable which is set to the currently active environment path
-set MPLBASEDIRLIST=%CONDA_PREFIX%\Library\;.
-
:: build the target
python setup.py %TARGET%
diff --git a/doc/api/next_api_changes/2018-12-29-AL.rst b/doc/api/next_api_changes/2018-12-29-AL.rst
new file mode 100644
index 000000000000..949f5c214a4e
--- /dev/null
+++ b/doc/api/next_api_changes/2018-12-29-AL.rst
@@ -0,0 +1,10 @@
+Changes to search paths for FreeType and libpng
+```````````````````````````````````````````````
+
+The ``MPLBASEDIRLIST`` environment variables and ``basedirlist`` entry in
+``setup.cfg`` have no effect anymore. Instead, if building in situations where
+FreeType or libpng are not in the compiler or linker's default path, set the
+standard environment variables ``CFLAGS``/``LDFLAGS`` on Linux or OSX, or
+``CL``/``LINK`` on Windows, to indicate the relevant paths.
+
+See details in :file:`INSTALL.rst`.
diff --git a/setup.cfg.template b/setup.cfg.template
index 3b17cb94761d..b7b1be0a425e 100644
--- a/setup.cfg.template
+++ b/setup.cfg.template
@@ -3,11 +3,6 @@
[egg_info]
-[directories]
-# Uncomment to override the default basedir in setupext.py.
-# This can be a single directory or a comma-delimited list of directories.
-#basedirlist = /usr
-
[test]
# If you plan to develop Matplotlib and run or add to the test suite,
# set this to True. It will download and build a specific version of
diff --git a/setupext.py b/setupext.py
index 5ff2c9dc165e..ecdf769e3423 100644
--- a/setupext.py
+++ b/setupext.py
@@ -11,6 +11,7 @@
import pathlib
import platform
import setuptools
+import shlex
import shutil
import subprocess
import sys
@@ -176,7 +177,6 @@ def write_cache(local_fn, data):
options = {
'display_status': True,
'backend': None,
- 'basedirlist': None
}
@@ -191,11 +191,6 @@ def write_cache(local_fn, data):
if config.has_option('rc_options', 'backend'):
options['backend'] = config.get("rc_options", "backend")
- if config.has_option('directories', 'basedirlist'):
- options['basedirlist'] = [
- x.strip() for x in
- config.get("directories", "basedirlist").split(',')]
-
if config.has_option('test', 'local_freetype'):
options['local_freetype'] = config.getboolean("test", "local_freetype")
else:
@@ -205,74 +200,6 @@ def write_cache(local_fn, data):
options['local_freetype'] = lft or options.get('local_freetype', False)
-def has_include_file(include_dirs, filename):
- """
- Returns `True` if *filename* can be found in one of the
- directories in *include_dirs*.
- """
- if sys.platform == 'win32':
- include_dirs = [*include_dirs, # Don't modify it in-place.
- *os.environ.get('INCLUDE', '.').split(os.pathsep)]
- return any(pathlib.Path(dir, filename).exists() for dir in include_dirs)
-
-
-def check_include_file(include_dirs, filename, package):
- """
- Raises an exception if the given include file can not be found.
- """
- if not has_include_file(include_dirs, filename):
- raise CheckFailed(
- "The C/C++ header for %s (%s) could not be found. You "
- "may need to install the development package." %
- (package, filename))
-
-
-def get_base_dirs():
- """
- Returns a list of standard base directories on this platform.
- """
- if options['basedirlist']:
- return options['basedirlist']
-
- if os.environ.get('MPLBASEDIRLIST'):
- return os.environ.get('MPLBASEDIRLIST').split(os.pathsep)
-
- win_bases = ['win32_static']
- # on conda windows, we also add the \Library,
- # as conda installs libs/includes there
- # env var names mess: https://github.com/conda/conda/issues/2312
- conda_env_path = os.getenv('CONDA_PREFIX') # conda >= 4.1
- if not conda_env_path:
- conda_env_path = os.getenv('CONDA_DEFAULT_ENV') # conda < 4.1
- if conda_env_path and os.path.isdir(conda_env_path):
- win_bases.append(os.path.join(conda_env_path, "Library"))
-
- basedir_map = {
- 'win32': win_bases,
- 'darwin': ['/usr/local/', '/usr', '/usr/X11',
- '/opt/X11', '/opt/local'],
- 'sunos5': [os.getenv('MPLIB_BASE') or '/usr/local', ],
- 'gnu0': ['/usr'],
- 'aix5': ['/usr/local'],
- }
- return basedir_map.get(sys.platform, ['/usr/local', '/usr'])
-
-
-def get_include_dirs():
- """
- Returns a list of standard include directories on this platform.
- """
- include_dirs = [os.path.join(d, 'include') for d in get_base_dirs()]
- if sys.platform != 'win32':
- # gcc includes these dirs automatically, so also look for headers in
- # these dirs
- include_dirs.extend(
- os.environ.get('CPATH', '').split(os.pathsep))
- include_dirs.extend(
- os.environ.get('CPLUS_INCLUDE_PATH', '').split(os.pathsep))
- return include_dirs
-
-
def is_min_version(found, minversion):
"""
Returns whether *found* is a version at least as high as *minversion*.
@@ -306,32 +233,6 @@ def print_line(*args, **kwargs):
print_status = print_message = print_raw = print_line
-def make_extension(name, files, *args, **kwargs):
- """
- Make a new extension. Automatically sets include_dirs and
- library_dirs to the base directories appropriate for this
- platform.
-
- `name` is the name of the extension.
-
- `files` is a list of source files.
-
- Any additional arguments are passed to the
- `distutils.core.Extension` constructor.
- """
- ext = Extension(name, files, *args, **kwargs)
- for dir in get_base_dirs():
- include_dir = os.path.join(dir, 'include')
- if os.path.exists(include_dir):
- ext.include_dirs.append(include_dir)
- for lib in ('lib', 'lib64'):
- lib_dir = os.path.join(dir, lib)
- if os.path.exists(lib_dir):
- ext.library_dirs.append(lib_dir)
- ext.include_dirs.append('.')
- return ext
-
-
def get_buffer_hash(fd):
BLOCKSIZE = 1 << 16
hasher = hashlib.sha256()
@@ -343,20 +244,17 @@ def get_buffer_hash(fd):
class PkgConfig(object):
- """
- This is a class for communicating with pkg-config.
- """
+ """This is a class for communicating with pkg-config."""
+
def __init__(self):
- """
- Determines whether pkg-config exists on this machine.
- """
- if sys.platform == 'win32':
- self.has_pkgconfig = False
- else:
- self.pkg_config = os.environ.get('PKG_CONFIG', 'pkg-config')
- self.set_pkgconfig_path()
- self.has_pkgconfig = shutil.which(self.pkg_config) is not None
- if not self.has_pkgconfig:
+ """Determines whether pkg-config exists on this machine."""
+ self.pkg_config = None
+ if sys.platform != 'win32':
+ pkg_config = os.environ.get('PKG_CONFIG', 'pkg-config')
+ if shutil.which(pkg_config) is not None:
+ self.pkg_config = pkg_config
+ self.set_pkgconfig_path()
+ else:
print("IMPORTANT WARNING:\n"
" pkg-config is not installed.\n"
" matplotlib may not be able to find some of its dependencies")
@@ -375,65 +273,49 @@ 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=[],
- alt_exec=None):
- """
- 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 = (self.pkg_config + ' {0}').format(package)
-
- use_defaults = True
+ def setup_extension(
+ self, ext, package,
+ atleast_version=None, alt_exec=None, default_libraries=()):
+ """Add parameters to the given *ext* for the given *package*."""
- if executable is not None:
- command = "{0} --libs --cflags ".format(executable)
+ # First, try to get the flags from pkg-config.
+ cmd = ([self.pkg_config, package] if self.pkg_config else alt_exec)
+ if cmd is not None:
try:
- output = subprocess.check_output(
- command, shell=True, stderr=subprocess.STDOUT)
- except subprocess.CalledProcessError:
+ if self.pkg_config and atleast_version:
+ subprocess.check_call(
+ [*cmd, f"--atleast-version={atleast_version}"])
+ # Use sys.getfilesystemencoding() to allow round-tripping
+ # when passed back to later subprocess calls; do not use
+ # locale.getpreferredencoding() which universal_newlines=True
+ # would do.
+ cflags = shlex.split(
+ os.fsdecode(subprocess.check_output([*cmd, "--cflags"])))
+ libs = shlex.split(
+ os.fsdecode(subprocess.check_output([*cmd, "--libs"])))
+ except (OSError, 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).insert(0, 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 of the package from pkg-config.
- """
- if not self.has_pkgconfig:
- return None
+ ext.extra_compile_args.extend(cflags)
+ ext.extra_link_args.extend(libs)
+ return
- status, output = subprocess.getstatusoutput(
- self.pkg_config + " %s --modversion" % (package))
- if status == 0:
- return output
- return None
+ # If that fails, fall back on the defaults.
+
+ # conda Windows header and library paths.
+ # https://github.com/conda/conda/issues/2312 re: getting the env dir.
+ if sys.platform == 'win32':
+ conda_env_path = (os.getenv('CONDA_PREFIX') # conda >= 4.1
+ or os.getenv('CONDA_DEFAULT_ENV')) # conda < 4.1
+ if conda_env_path and os.path.isdir(conda_env_path):
+ ext.include_dirs.append(os.fspath(
+ pathlib.Path(conda_env_path, "Library/include")))
+ ext.library_dirs.append(os.fspath(
+ pathlib.Path(conda_env_path, "Library/lib")))
+
+ # Default linked libs.
+ ext.libraries.extend(default_libraries)
# The PkgConfig class should be used through this singleton
@@ -523,47 +405,6 @@ def get_setup_requires(self):
"""
return []
- 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. Set version='unknown'
- if the version is not known but you still want to disabled
- pkg_config version check.
- """
- 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 and version != 'unknown':
- 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 + get_include_dirs(), include_file, package)
-
- return 'version %s' % version
-
def do_custom_build(self):
"""
If a package needs to do extra custom things, such as building a
@@ -868,13 +709,12 @@ def add_flags(self, ext):
ext.define_macros.append(('FREETYPE_BUILD_TYPE', 'local'))
else:
pkg_config.setup_extension(
+ # FreeType 2.3 has libtool version 9.11.3 as can be checked
+ # from the tarball. For FreeType>=2.4, there is a conversion
+ # table in docs/VERSIONS.txt in the FreeType source tree.
ext, 'freetype2',
- default_include_dirs=[
- 'include/freetype2', 'freetype2',
- 'lib/freetype2/include',
- 'lib/freetype2/include/freetype2'],
- default_library_dirs=[
- 'freetype2/lib'],
+ atleast_version='9.11.3',
+ alt_exec=['freetype-config'],
default_libraries=['freetype', 'z'])
ext.define_macros.append(('FREETYPE_BUILD_TYPE', 'system'))
@@ -991,7 +831,7 @@ def get_extension(self):
'src/mplutils.cpp',
'src/py_converters.cpp',
]
- ext = make_extension('matplotlib.ft2font', sources)
+ ext = Extension('matplotlib.ft2font', sources)
FreeType().add_flags(ext)
Numpy().add_flags(ext)
LibAgg().add_flags(ext, add_sources=False)
@@ -1015,10 +855,12 @@ def get_extension(self):
'src/_png.cpp',
'src/mplutils.cpp',
]
- ext = make_extension('matplotlib._png', sources)
+ ext = Extension('matplotlib._png', sources)
pkg_config.setup_extension(
- ext, 'libpng', default_libraries=['png', 'z'],
- alt_exec='libpng-config --ldflags')
+ ext, 'libpng',
+ atleast_version='1.2',
+ alt_exec=['libpng-config', '--ldflags'],
+ default_libraries=['png', 'z'])
Numpy().add_flags(ext)
return ext
@@ -1046,7 +888,7 @@ def get_extension(self):
'extern/ttconv/pprdrv_tt2.cpp',
'extern/ttconv/ttutil.cpp'
]
- ext = make_extension('matplotlib.ttconv', sources)
+ ext = Extension('matplotlib.ttconv', sources)
Numpy().add_flags(ext)
ext.include_dirs.insert(0, 'extern')
return ext
@@ -1061,7 +903,7 @@ def get_extension(self):
'src/_path_wrapper.cpp'
]
- ext = make_extension('matplotlib._path', sources)
+ ext = Extension('matplotlib._path', sources)
Numpy().add_flags(ext)
LibAgg().add_flags(ext)
return ext
@@ -1077,7 +919,7 @@ def get_extension(self):
'src/_image_wrapper.cpp',
'src/py_converters.cpp'
]
- ext = make_extension('matplotlib._image', sources)
+ ext = Extension('matplotlib._image', sources)
Numpy().add_flags(ext)
LibAgg().add_flags(ext)
@@ -1093,7 +935,7 @@ def get_extension(self):
"src/_contour_wrapper.cpp",
'src/py_converters.cpp',
]
- ext = make_extension('matplotlib._contour', sources)
+ ext = Extension('matplotlib._contour', sources)
Numpy().add_flags(ext)
LibAgg().add_flags(ext, add_sources=False)
return ext
@@ -1104,8 +946,8 @@ class QhullWrap(SetupPackage):
def get_extension(self):
sources = ['src/qhull_wrap.c']
- ext = make_extension('matplotlib._qhull', sources,
- define_macros=[('MPL_DEVNULL', os.devnull)])
+ ext = Extension('matplotlib._qhull', sources,
+ define_macros=[('MPL_DEVNULL', os.devnull)])
Numpy().add_flags(ext)
Qhull().add_flags(ext)
return ext
@@ -1116,11 +958,11 @@ class Tri(SetupPackage):
def get_extension(self):
sources = [
- "lib/matplotlib/tri/_tri.cpp",
- "lib/matplotlib/tri/_tri_wrapper.cpp",
+ "src/tri/_tri.cpp",
+ "src/tri/_tri_wrapper.cpp",
"src/mplutils.cpp"
]
- ext = make_extension('matplotlib._tri', sources)
+ ext = Extension('matplotlib._tri', sources)
Numpy().add_flags(ext)
return ext
@@ -1136,7 +978,7 @@ def get_extension(self):
"src/_backend_agg.cpp",
"src/_backend_agg_wrapper.cpp"
]
- ext = make_extension('matplotlib.backends._backend_agg', sources)
+ ext = Extension('matplotlib.backends._backend_agg', sources)
Numpy().add_flags(ext)
LibAgg().add_flags(ext)
FreeType().add_flags(ext)
@@ -1156,7 +998,7 @@ def get_extension(self):
'src/py_converters.cpp',
]
- ext = make_extension('matplotlib.backends._tkagg', sources)
+ ext = Extension('matplotlib.backends._tkagg', sources)
self.add_flags(ext)
Numpy().add_flags(ext)
LibAgg().add_flags(ext, add_sources=False)
@@ -1187,7 +1029,7 @@ def get_extension(self):
'src/_macosx.m'
]
- ext = make_extension('matplotlib.backends._macosx', sources)
+ ext = Extension('matplotlib.backends._macosx', sources)
ext.extra_link_args.extend(['-framework', 'Cocoa'])
if platform.python_implementation().lower() == 'pypy':
ext.extra_compile_args.append('-DPYPY=1')
diff --git a/src/_contour.cpp b/src/_contour.cpp
index d870fb2d151a..ac655d73de27 100644
--- a/src/_contour.cpp
+++ b/src/_contour.cpp
@@ -6,8 +6,8 @@
// to the appropriate make_extension call in setupext.py, and then rebuilding.
#define NO_IMPORT_ARRAY
-#include "src/mplutils.h"
-#include "src/_contour.h"
+#include "mplutils.h"
+#include "_contour.h"
#include
diff --git a/src/_contour.h b/src/_contour.h
index fc7b2f106df4..6232b3abd2a7 100644
--- a/src/_contour.h
+++ b/src/_contour.h
@@ -142,7 +142,7 @@
#ifndef MPL_CONTOUR_H
#define MPL_CONTOUR_H
-#include "src/numpy_cpp.h"
+#include "numpy_cpp.h"
#include
#include
#include
diff --git a/src/_contour_wrapper.cpp b/src/_contour_wrapper.cpp
index 8aa64fcdf068..6464a3748daf 100644
--- a/src/_contour_wrapper.cpp
+++ b/src/_contour_wrapper.cpp
@@ -1,7 +1,7 @@
-#include "src/_contour.h"
-#include "src/mplutils.h"
-#include "src/py_converters.h"
-#include "src/py_exceptions.h"
+#include "_contour.h"
+#include "mplutils.h"
+#include "py_converters.h"
+#include "py_exceptions.h"
/* QuadContourGenerator */
diff --git a/lib/matplotlib/tri/_tri.cpp b/src/tri/_tri.cpp
similarity index 100%
rename from lib/matplotlib/tri/_tri.cpp
rename to src/tri/_tri.cpp
diff --git a/lib/matplotlib/tri/_tri.h b/src/tri/_tri.h
similarity index 99%
rename from lib/matplotlib/tri/_tri.h
rename to src/tri/_tri.h
index 7243e195f9a8..13aad01fb668 100644
--- a/lib/matplotlib/tri/_tri.h
+++ b/src/tri/_tri.h
@@ -63,7 +63,7 @@
#ifndef MPL_TRI_H
#define MPL_TRI_H
-#include "src/numpy_cpp.h"
+#include "../numpy_cpp.h"
#include
#include
diff --git a/lib/matplotlib/tri/_tri_wrapper.cpp b/src/tri/_tri_wrapper.cpp
similarity index 99%
rename from lib/matplotlib/tri/_tri_wrapper.cpp
rename to src/tri/_tri_wrapper.cpp
index 38ce2e55d36d..81fe1d40ba92 100644
--- a/lib/matplotlib/tri/_tri_wrapper.cpp
+++ b/src/tri/_tri_wrapper.cpp
@@ -1,6 +1,6 @@
#include "_tri.h"
-#include "src/mplutils.h"
-#include "src/py_exceptions.h"
+#include "../mplutils.h"
+#include "../py_exceptions.h"
/* Triangulation */