Skip to content

Commit 044a5e5

Browse files
committed
BLD: Use Meson to build extensions
1 parent 6665b26 commit 044a5e5

File tree

20 files changed

+1982
-12
lines changed

20 files changed

+1982
-12
lines changed

.circleci/config.yml

+2-5
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,9 @@ commands:
117117
python -m pip install --user -ve .
118118
fi
119119
- save_cache:
120-
key: build-deps-1
120+
key: build-deps-2
121121
paths:
122-
# FreeType 2.6.1 tarball.
123-
- ~/.cache/matplotlib/0a3c7dfbda6da1e8fce29232e8e96d987ababbbf71ebc8c75659e4132c367014
124-
# Qhull 2020.2 tarball.
125-
- ~/.cache/matplotlib/b5c2d7eb833278881b952c8a52d20179eab87766b00b865000469a45c1838b7e
122+
- subprojects/packagecache
126123

127124
doc-build:
128125
steps:

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ pip-wheel-metadata/*
4444
mplsetup.cfg
4545
# generated by setuptools_scm
4646
lib/matplotlib/_version.py
47+
# build subproject files
48+
subprojects/*/
49+
!subprojects/packagefiles/
4750

4851
# OS generated files #
4952
######################

extern/agg24-svn/meson.build

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# We need a patched Agg not available elsewhere, so always use the vendored
2+
# version.
3+
4+
agg_incdir = include_directories('include')
5+
6+
agg_lib = static_library('agg',
7+
'src/agg_bezier_arc.cpp',
8+
'src/agg_curves.cpp',
9+
'src/agg_image_filters.cpp',
10+
'src/agg_trans_affine.cpp',
11+
'src/agg_vcgen_contour.cpp',
12+
'src/agg_vcgen_dash.cpp',
13+
'src/agg_vcgen_stroke.cpp',
14+
'src/agg_vpgen_segmentator.cpp',
15+
include_directories : agg_incdir,
16+
gnu_symbol_visibility: 'inlineshidden',
17+
)
18+
19+
agg_dep = declare_dependency(
20+
include_directories: agg_incdir,
21+
link_with: agg_lib,
22+
)

extern/meson.build

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Bundled code.
2+
subdir('agg24-svn')
3+
subdir('ttconv')
4+
5+
# External code.
6+
7+
# FreeType 2.3 has libtool version 9.11.3 as can be checked from the tarball.
8+
# For FreeType>=2.4, there is a conversion table in docs/VERSIONS.txt in the
9+
# FreeType source tree.
10+
if get_option('system-freetype')
11+
freetype_dep = dependency('freetype2', version: '>=9.11.3')
12+
else
13+
# This is the version of FreeType to use when building a local version. It
14+
# must match the value in `lib/matplotlib.__init__.py`. Also update the docs
15+
# in `docs/devel/dependencies.rst`. Bump the cache key in
16+
# `.circleci/config.yml` when changing requirements.
17+
TESTING_VERSION_OF_FREETYPE = '2.6.1'
18+
if host_machine.system() == 'windows' and host_machine.cpu_family() == 'aarch64'
19+
# Older versions of freetype are not supported for win/arm64
20+
# Matplotlib tests will not pass
21+
LOCAL_FREETYPE_VERSION = '2.11.1'
22+
else
23+
LOCAL_FREETYPE_VERSION = TESTING_VERSION_OF_FREETYPE
24+
endif
25+
26+
freetype_proj = subproject(
27+
f'freetype-@LOCAL_FREETYPE_VERSION@',
28+
default_options: ['default_library=static'])
29+
freetype_dep = freetype_proj.get_variable('freetype_dep')
30+
endif
31+
32+
if get_option('system-qhull')
33+
qhull_dep = dependency('qhull_r', version: '>=8.0.2', required: false)
34+
if not qhull_dep.found()
35+
cc.check_header('libqhull_r/qhull_ra.h', required: true)
36+
qhull_dep = cc.find_library('qhull_r')
37+
endif
38+
else
39+
qhull_proj = subproject('qhull')
40+
qhull_dep = qhull_proj.get_variable('qhull_dep')
41+
endif

extern/ttconv/meson.build

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
ttconv_lib = static_library('ttconv',
2+
'pprdrv_tt2.cpp',
3+
'pprdrv_tt.cpp',
4+
'ttutil.cpp',
5+
'pprdrv.h',
6+
'truetype.h',
7+
dependencies: [py3_dep],
8+
gnu_symbol_visibility: 'inlineshidden',
9+
)
10+
11+
ttconv_dep = declare_dependency(
12+
include_directories: include_directories('.'),
13+
link_with: ttconv_lib,
14+
)

meson.build

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
project(
2+
'matplotlib',
3+
'c', 'cpp',
4+
version: '3.9.0.dev0',
5+
# qt_editor backend is MIT
6+
# ResizeObserver at end of lib/matplotlib/backends/web_backend/js/mpl.js is CC0
7+
# Carlogo, STIX and Computer Modern is OFL
8+
# DejaVu is Bitstream Vera and Public Domain
9+
license: 'PSF-2.0 AND MIT AND CC0-1.0 AND OFL-1.1 AND Bitstream-Vera AND Public-Domain',
10+
default_options: [
11+
'b_lto=true',
12+
'cpp_std=c++11',
13+
'auto_features=disabled', # Force FreeType to avoid extra dependencies.
14+
],
15+
)
16+
17+
cc = meson.get_compiler('c')
18+
cpp = meson.get_compiler('cpp')
19+
20+
# https://mesonbuild.com/Python-module.html
21+
py_mod = import('python')
22+
py3 = py_mod.find_installation()
23+
py3_dep = py3.dependency()
24+
25+
pybind11_dep = dependency('pybind11', version: '>=2.6')
26+
27+
subdir('extern')
28+
subdir('src')

meson_options.txt

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# By default, Matplotlib downloads and builds its own copies of FreeType and of
2+
# Qhull. You may set the following to True to instead link against a system
3+
# FreeType/Qhull. As an exception, Matplotlib defaults to the system version
4+
# of FreeType on AIX.
5+
option('system-freetype', type: 'boolean', value: false,
6+
description: 'Build against system version of FreeType')
7+
option('system-qhull', type: 'boolean', value: false,
8+
description: 'Build against system version of Qhull')
9+
10+
# Some of Matplotlib's components are optional: the MacOSX backend (installed
11+
# by default on MacOSX; requires the Cocoa headers included with XCode), and
12+
# the test data (i.e., the baseline image files; not installed by default). You
13+
# can control whether they are installed by uncommenting the following lines.
14+
# Note that the MacOSX backend is never built on Linux or Windows, regardless
15+
# of the config value.
16+
option('macosx', type: 'boolean', value: true,
17+
description: 'Enable MacOSX backend (requires Cocoa)')

src/_c_internal_utils.c

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
#ifdef _WIN32
2+
#define WIN32_LEAN_AND_MEAN
3+
// Windows 10, for latest HiDPI API support.
4+
#define WINVER 0x0A00
5+
#define _WIN32_WINNT 0x0A00
6+
#endif
17
#define PY_SSIZE_T_CLEAN
28
#include <Python.h>
39
#ifdef __linux__

src/_tkagg.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@
99
// rewritten, we have removed the PIL licensing information. If you want PIL,
1010
// you can get it at https://python-pillow.org/
1111

12+
#ifdef _WIN32
13+
#define WIN32_LEAN_AND_MEAN
14+
// Windows 8.1
15+
#define WINVER 0x0603
16+
#define _WIN32_WINNT 0x0603
17+
#endif
18+
1219
#define PY_SSIZE_T_CLEAN
1320
#include <Python.h>
1421

src/_ttconv.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#include "mplutils.h"
99

1010
#include <pybind11/pybind11.h>
11-
#include "ttconv/pprdrv.h"
11+
#include "pprdrv.h"
1212
#include <vector>
1313

1414
namespace py = pybind11;

src/meson.build

+191
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
# NumPy include directory - needed in all submodules
2+
# The try-except is needed because when things are split across drives on Windows, there
3+
# is no relative path and an exception gets raised. There may be other such cases, so add
4+
# a catch-all and switch to an absolute path. Relative paths are needed when for example
5+
# a virtualenv is placed inside the source tree; Meson rejects absolute paths to places
6+
# inside the source tree.
7+
# For cross-compilation it is often not possible to run the Python interpreter in order
8+
# to retrieve numpy's include directory. It can be specified in the cross file instead:
9+
#
10+
# [properties]
11+
# numpy-include-dir = /abspath/to/host-pythons/site-packages/numpy/core/include
12+
#
13+
# This uses the path as is, and avoids running the interpreter.
14+
incdir_numpy = meson.get_external_property('numpy-include-dir', 'not-given')
15+
if incdir_numpy == 'not-given'
16+
incdir_numpy = run_command(py3,
17+
[
18+
'-c',
19+
'''import os
20+
import numpy as np
21+
try:
22+
incdir = os.path.relpath(np.get_include())
23+
except Exception:
24+
incdir = np.get_include()
25+
print(incdir)'''
26+
],
27+
check: true
28+
).stdout().strip()
29+
endif
30+
numpy_dep = declare_dependency(
31+
compile_args: [
32+
'-DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION',
33+
# Allow NumPy's printf format specifiers in C++.
34+
'-D__STDC_FORMAT_MACROS=1',
35+
],
36+
include_directories: include_directories(incdir_numpy),
37+
dependencies: py3_dep,
38+
)
39+
40+
# For cross-compilation it is often not possible to run the Python interpreter in order
41+
# to retrieve the platform-specific /dev/null. It can be specified in the cross file
42+
# instead:
43+
#
44+
# [properties]
45+
# devnull = /dev/null
46+
#
47+
# This uses the value as is, and avoids running the interpreter.
48+
devnull = meson.get_external_property('devnull', 'not-given')
49+
if devnull == 'not-given'
50+
devnull = run_command(py3, '-c', 'import os; print(os.devnull)',
51+
capture: true, check: true).stdout().strip()
52+
endif
53+
54+
# Will only exist on Linux with older glibc.
55+
dl = cc.find_library('dl', required: false)
56+
57+
# With Meson >= 1.2.0, use cpp_winlibs instead of manually searching.
58+
if ['cygwin', 'windows'].contains(host_machine.system())
59+
comctl32 = cc.find_library('comctl32')
60+
ole32 = cc.find_library('ole32')
61+
psapi = cc.find_library('psapi')
62+
shell32 = cc.find_library('shell32')
63+
user32 = cc.find_library('user32')
64+
else
65+
comctl32 = []
66+
ole32 = []
67+
psapi = []
68+
shell32 = []
69+
user32 = []
70+
endif
71+
72+
extension_data = {
73+
'_backend_agg': {
74+
'subdir': 'matplotlib/backends',
75+
'sources': files(
76+
'py_converters.cpp',
77+
'_backend_agg.cpp',
78+
'_backend_agg_wrapper.cpp',
79+
),
80+
'dependencies': [agg_dep, numpy_dep, freetype_dep],
81+
},
82+
'_c_internal_utils': {
83+
'subdir': 'matplotlib',
84+
'sources': files(
85+
'_c_internal_utils.c',
86+
),
87+
'dependencies': [py3_dep, dl, ole32, shell32, user32],
88+
},
89+
'ft2font': {
90+
'subdir': 'matplotlib',
91+
'sources': files(
92+
'ft2font.cpp',
93+
'ft2font_wrapper.cpp',
94+
'py_converters.cpp',
95+
),
96+
'dependencies': [
97+
freetype_dep, numpy_dep, agg_dep.partial_dependency(includes: true),
98+
],
99+
},
100+
'_image': {
101+
'subdir': 'matplotlib',
102+
'sources': files(
103+
'_image_wrapper.cpp',
104+
'py_converters_11.cpp',
105+
),
106+
'dependencies': [
107+
pybind11_dep,
108+
# Only need source code files agg_image_filters.cpp and agg_trans_affine.cpp
109+
agg_dep,
110+
],
111+
},
112+
'_path': {
113+
'subdir': 'matplotlib',
114+
'sources': files(
115+
'py_converters.cpp',
116+
'_path_wrapper.cpp',
117+
),
118+
'dependencies': [numpy_dep, agg_dep],
119+
},
120+
'_qhull': {
121+
'subdir': 'matplotlib',
122+
'sources': files(
123+
'_qhull_wrapper.cpp',
124+
),
125+
'dependencies': [numpy_dep, qhull_dep],
126+
'c_args': [f'-DMPL_DEVNULL=@devnull@'],
127+
'cpp_args': [f'-DMPL_DEVNULL=@devnull@'],
128+
},
129+
'_tkagg': {
130+
'subdir': 'matplotlib/backends',
131+
'sources': files(
132+
'_tkagg.cpp',
133+
),
134+
'include_directories': include_directories('.'),
135+
# The dl/psapi libraries are needed for finding Tcl/Tk at run time.
136+
'dependencies': [
137+
numpy_dep, agg_dep.partial_dependency(includes: true), dl, comctl32, psapi,
138+
],
139+
},
140+
'_tri': {
141+
'subdir': 'matplotlib',
142+
'sources': files(
143+
'tri/_tri.cpp',
144+
'tri/_tri_wrapper.cpp',
145+
),
146+
'dependencies': [pybind11_dep],
147+
},
148+
'_ttconv': {
149+
'subdir': 'matplotlib',
150+
'sources': files(
151+
'_ttconv.cpp',
152+
),
153+
'dependencies': [ttconv_dep, pybind11_dep],
154+
},
155+
}
156+
157+
cpp_special_arguments = []
158+
if cpp.get_id() == 'msvc' and get_option('buildtype') != 'plain'
159+
# Disable FH4 Exception Handling implementation so that we don't require
160+
# VCRUNTIME140_1.dll. For more details, see:
161+
# https://devblogs.microsoft.com/cppblog/making-cpp-exception-handling-smaller-x64/
162+
# https://github.com/joerick/cibuildwheel/issues/423#issuecomment-677763904
163+
cpp_special_arguments += ['/d2FH4-']
164+
endif
165+
166+
foreach ext, kwargs : extension_data
167+
# Ensure that PY_ARRAY_UNIQUE_SYMBOL is uniquely defined for each extension.
168+
unique_array_api = '-DPY_ARRAY_UNIQUE_SYMBOL=MPL_@0@_ARRAY_API'.format(ext.replace('.', '_'))
169+
additions = {
170+
'c_args': [unique_array_api] + kwargs.get('c_args', []),
171+
'cpp_args': cpp_special_arguments + [unique_array_api] + kwargs.get('cpp_args', []),
172+
}
173+
py3.extension_module(
174+
ext,
175+
install: true,
176+
kwargs: kwargs + additions)
177+
endforeach
178+
179+
if get_option('macosx') and host_machine.system() == 'darwin'
180+
add_languages('objc', native: false)
181+
py3.extension_module(
182+
'_macosx',
183+
subdir: 'matplotlib/backends',
184+
sources: files(
185+
'_macosx.m',
186+
),
187+
dependencies: dependency('appleframeworks', modules: 'Cocoa'),
188+
override_options: ['werror=true'],
189+
install: true,
190+
)
191+
endif

src/tri/_tri.cpp

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
/* This file contains liberal use of asserts to assist code development and
2-
* debugging. Standard matplotlib builds disable asserts so they cause no
3-
* performance reduction. To enable the asserts, you need to undefine the
4-
* NDEBUG macro, which is achieved by adding the following
5-
* undef_macros=['NDEBUG']
6-
* to the appropriate make_extension call in setupext.py, and then rebuilding.
1+
/* This file contains liberal use of asserts to assist code development and debugging.
2+
* Standard Matplotlib builds disable asserts so they cause no performance reduction. To
3+
* enable the asserts, you need to undefine the NDEBUG macro, which is achieved by
4+
* passing ``b_ndebug=false`` to the Meson configuration.
75
*/
86
#include "../mplutils.h"
97
#include "_tri.h"

subprojects/freetype-2.11.1.wrap

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[wrap-file]
2+
source_url = https://download.savannah.gnu.org/releases/freetype/freetype-2.11.1.tar.xz
3+
source_filename = freetype-2.11.1.tar.xz
4+
source_hash = 3333ae7cfda88429c97a7ae63b7d01ab398076c3b67182e960e5684050f2c5c8
5+
6+
[provide]
7+
freetype-2.11.1 = freetype_dep

0 commit comments

Comments
 (0)