Skip to content

Commit 923ce72

Browse files
committed
Simplify version checks for freetype and libpng.
Currently, setupext.py replicates a lot of work done by the compiler to check whether header files are present, and whether freetype and libpng have sufficiently recent versions. Instead, we can just add a small stub source file at the top of the extension sources which just tries to include the header and checks the version macros. If the header is not found, compilation will immediately abort with `foo.h: No such file or directory`; if the version is too old, we can emit an appropriate error message (`#pragma message` is supported by all major compilers and allows expanding of macros in the error message).
1 parent 9e7650e commit 923ce72

File tree

3 files changed

+28
-73
lines changed

3 files changed

+28
-73
lines changed

setupext.py

+10-73
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,13 @@ def add_flags(self, ext, add_sources=True):
814814
for x in agg_sources)
815815

816816

817+
# For FreeType2 and libpng, we add a separate checkdep_foo.c source to at the
818+
# top of the extension sources. This file is compiled first and immediately
819+
# aborts the compilation either with "foo.h: No such file or directory" if the
820+
# header is not found, or an appropriate error message if the header indicates
821+
# a too-old version.
822+
823+
817824
class FreeType(SetupPackage):
818825
name = "freetype"
819826
pkg_names = {
@@ -825,59 +832,8 @@ class FreeType(SetupPackage):
825832
"windows_url": "http://gnuwin32.sourceforge.net/packages/freetype.htm"
826833
}
827834

828-
def check(self):
829-
if options.get('local_freetype'):
830-
return "Using local version for testing"
831-
832-
if sys.platform == 'win32':
833-
try:
834-
check_include_file(get_include_dirs(), 'ft2build.h', 'freetype')
835-
except CheckFailed:
836-
check_include_file(get_include_dirs(), os.path.join('freetype2', 'ft2build.h'), 'freetype')
837-
return 'Using unknown version found on system.'
838-
839-
status, output = subprocess.getstatusoutput(
840-
"freetype-config --ftversion")
841-
if status == 0:
842-
version = output
843-
else:
844-
version = None
845-
846-
# Early versions of freetype grep badly inside freetype-config,
847-
# so catch those cases. (tested with 2.5.3).
848-
if version is None or 'No such file or directory\ngrep:' in version:
849-
version = self.version_from_header()
850-
851-
# pkg_config returns the libtool version rather than the
852-
# freetype version so we need to explicitly pass the version
853-
# to _check_for_pkg_config
854-
return self._check_for_pkg_config(
855-
'freetype2', 'ft2build.h',
856-
min_version='2.3', version=version)
857-
858-
def version_from_header(self):
859-
version = 'unknown'
860-
ext = self.get_extension()
861-
if ext is None:
862-
return version
863-
# Return the first version found in the include dirs.
864-
for include_dir in ext.include_dirs:
865-
header_fname = os.path.join(include_dir, 'freetype.h')
866-
if os.path.exists(header_fname):
867-
major, minor, patch = 0, 0, 0
868-
with open(header_fname, 'r') as fh:
869-
for line in fh:
870-
if line.startswith('#define FREETYPE_'):
871-
value = line.rsplit(' ', 1)[1].strip()
872-
if 'MAJOR' in line:
873-
major = value
874-
elif 'MINOR' in line:
875-
minor = value
876-
else:
877-
patch = value
878-
return '.'.join([major, minor, patch])
879-
880835
def add_flags(self, ext):
836+
ext.sources.insert(0, 'src/checkdep_freetype2.c')
881837
if options.get('local_freetype'):
882838
src_path = os.path.join(
883839
'build', 'freetype-{0}'.format(LOCAL_FREETYPE_VERSION))
@@ -1058,30 +1014,11 @@ class Png(SetupPackage):
10581014
"windows_url": "http://gnuwin32.sourceforge.net/packages/libpng.htm"
10591015
}
10601016

1061-
def check(self):
1062-
if sys.platform == 'win32':
1063-
check_include_file(get_include_dirs(), 'png.h', 'png')
1064-
return 'Using unknown version found on system.'
1065-
1066-
status, output = subprocess.getstatusoutput("libpng-config --version")
1067-
if status == 0:
1068-
version = output
1069-
else:
1070-
version = None
1071-
1072-
try:
1073-
return self._check_for_pkg_config(
1074-
'libpng', 'png.h',
1075-
min_version='1.2', version=version)
1076-
except CheckFailed as e:
1077-
if has_include_file(get_include_dirs(), 'png.h'):
1078-
return str(e) + ' Using unknown version found on system.'
1079-
raise
1080-
10811017
def get_extension(self):
10821018
sources = [
1019+
'src/checkdep_libpng.c',
10831020
'src/_png.cpp',
1084-
'src/mplutils.cpp'
1021+
'src/mplutils.cpp',
10851022
]
10861023
ext = make_extension('matplotlib._png', sources)
10871024
pkg_config.setup_extension(

src/checkdep_freetype2.c

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <ft2build.h>
2+
#include FT_FREETYPE_H
3+
4+
#define XSTR(x) STR(x)
5+
#define STR(x) #x
6+
7+
#pragma message("Compiling with FreeType version " \
8+
XSTR(FREETYPE_MAJOR) "." XSTR(FREETYPE_MINOR) "." XSTR(FREETYPE_PATCH) ".")
9+
#if FREETYPE_MAJOR << 16 + FREETYPE_MINOR << 8 + FREETYPE_PATCH < 0x020300
10+
#error "FreeType version 2.3 or higher is required." \
11+
"Consider setting the MPLLOCALFREETYPE environment variable to 1."
12+
#error
13+
#endif

src/checkdep_libpng.c

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include <png.h>
2+
#pragma message("Compiling with libpng version " PNG_LIBPNG_VER_STRING ".")
3+
#if PNG_LIBPNG_VER < 10200
4+
#error "libpng version 1.2 or higher is required."
5+
#endif

0 commit comments

Comments
 (0)