Skip to content

Commit

Permalink
BLD: Use Meson to build extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
QuLogic committed Oct 3, 2023
1 parent 6665b26 commit 044a5e5
Show file tree
Hide file tree
Showing 20 changed files with 1,982 additions and 12 deletions.
7 changes: 2 additions & 5 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,9 @@ commands:
python -m pip install --user -ve .
fi
- save_cache:
key: build-deps-1
key: build-deps-2
paths:
# FreeType 2.6.1 tarball.
- ~/.cache/matplotlib/0a3c7dfbda6da1e8fce29232e8e96d987ababbbf71ebc8c75659e4132c367014
# Qhull 2020.2 tarball.
- ~/.cache/matplotlib/b5c2d7eb833278881b952c8a52d20179eab87766b00b865000469a45c1838b7e
- subprojects/packagecache

doc-build:
steps:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ pip-wheel-metadata/*
mplsetup.cfg
# generated by setuptools_scm
lib/matplotlib/_version.py
# build subproject files
subprojects/*/
!subprojects/packagefiles/

# OS generated files #
######################
Expand Down
22 changes: 22 additions & 0 deletions extern/agg24-svn/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# We need a patched Agg not available elsewhere, so always use the vendored
# version.

agg_incdir = include_directories('include')

agg_lib = static_library('agg',
'src/agg_bezier_arc.cpp',
'src/agg_curves.cpp',
'src/agg_image_filters.cpp',
'src/agg_trans_affine.cpp',
'src/agg_vcgen_contour.cpp',
'src/agg_vcgen_dash.cpp',
'src/agg_vcgen_stroke.cpp',
'src/agg_vpgen_segmentator.cpp',
include_directories : agg_incdir,
gnu_symbol_visibility: 'inlineshidden',
)

agg_dep = declare_dependency(
include_directories: agg_incdir,
link_with: agg_lib,
)
41 changes: 41 additions & 0 deletions extern/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Bundled code.
subdir('agg24-svn')
subdir('ttconv')

# External code.

# 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.
if get_option('system-freetype')
freetype_dep = dependency('freetype2', version: '>=9.11.3')
else
# This is the version of FreeType to use when building a local version. It
# must match the value in `lib/matplotlib.__init__.py`. Also update the docs
# in `docs/devel/dependencies.rst`. Bump the cache key in
# `.circleci/config.yml` when changing requirements.
TESTING_VERSION_OF_FREETYPE = '2.6.1'
if host_machine.system() == 'windows' and host_machine.cpu_family() == 'aarch64'
# Older versions of freetype are not supported for win/arm64
# Matplotlib tests will not pass
LOCAL_FREETYPE_VERSION = '2.11.1'
else
LOCAL_FREETYPE_VERSION = TESTING_VERSION_OF_FREETYPE
endif

freetype_proj = subproject(
f'freetype-@LOCAL_FREETYPE_VERSION@',
default_options: ['default_library=static'])
freetype_dep = freetype_proj.get_variable('freetype_dep')
endif

if get_option('system-qhull')
qhull_dep = dependency('qhull_r', version: '>=8.0.2', required: false)
if not qhull_dep.found()
cc.check_header('libqhull_r/qhull_ra.h', required: true)
qhull_dep = cc.find_library('qhull_r')
endif
else
qhull_proj = subproject('qhull')
qhull_dep = qhull_proj.get_variable('qhull_dep')
endif
14 changes: 14 additions & 0 deletions extern/ttconv/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
ttconv_lib = static_library('ttconv',
'pprdrv_tt2.cpp',
'pprdrv_tt.cpp',
'ttutil.cpp',
'pprdrv.h',
'truetype.h',
dependencies: [py3_dep],
gnu_symbol_visibility: 'inlineshidden',
)

ttconv_dep = declare_dependency(
include_directories: include_directories('.'),
link_with: ttconv_lib,
)
28 changes: 28 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
project(
'matplotlib',
'c', 'cpp',
version: '3.9.0.dev0',
# qt_editor backend is MIT
# ResizeObserver at end of lib/matplotlib/backends/web_backend/js/mpl.js is CC0
# Carlogo, STIX and Computer Modern is OFL
# DejaVu is Bitstream Vera and Public Domain
license: 'PSF-2.0 AND MIT AND CC0-1.0 AND OFL-1.1 AND Bitstream-Vera AND Public-Domain',
default_options: [
'b_lto=true',
'cpp_std=c++11',
'auto_features=disabled', # Force FreeType to avoid extra dependencies.
],
)

cc = meson.get_compiler('c')
cpp = meson.get_compiler('cpp')

# https://mesonbuild.com/Python-module.html
py_mod = import('python')
py3 = py_mod.find_installation()
py3_dep = py3.dependency()

pybind11_dep = dependency('pybind11', version: '>=2.6')

subdir('extern')
subdir('src')
17 changes: 17 additions & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# By default, Matplotlib downloads and builds its own copies of FreeType and of
# Qhull. You may set the following to True to instead link against a system
# FreeType/Qhull. As an exception, Matplotlib defaults to the system version
# of FreeType on AIX.
option('system-freetype', type: 'boolean', value: false,
description: 'Build against system version of FreeType')
option('system-qhull', type: 'boolean', value: false,
description: 'Build against system version of Qhull')

# Some of Matplotlib's components are optional: the MacOSX backend (installed
# by default on MacOSX; requires the Cocoa headers included with XCode), and
# the test data (i.e., the baseline image files; not installed by default). You
# can control whether they are installed by uncommenting the following lines.
# Note that the MacOSX backend is never built on Linux or Windows, regardless
# of the config value.
option('macosx', type: 'boolean', value: true,
description: 'Enable MacOSX backend (requires Cocoa)')
6 changes: 6 additions & 0 deletions src/_c_internal_utils.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
// Windows 10, for latest HiDPI API support.
#define WINVER 0x0A00
#define _WIN32_WINNT 0x0A00
#endif
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#ifdef __linux__
Expand Down
7 changes: 7 additions & 0 deletions src/_tkagg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
// rewritten, we have removed the PIL licensing information. If you want PIL,
// you can get it at https://python-pillow.org/

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
// Windows 8.1
#define WINVER 0x0603
#define _WIN32_WINNT 0x0603
#endif

#define PY_SSIZE_T_CLEAN
#include <Python.h>

Expand Down
2 changes: 1 addition & 1 deletion src/_ttconv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include "mplutils.h"

#include <pybind11/pybind11.h>
#include "ttconv/pprdrv.h"
#include "pprdrv.h"
#include <vector>

namespace py = pybind11;
Expand Down
191 changes: 191 additions & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
# NumPy include directory - needed in all submodules
# The try-except is needed because when things are split across drives on Windows, there
# is no relative path and an exception gets raised. There may be other such cases, so add
# a catch-all and switch to an absolute path. Relative paths are needed when for example
# a virtualenv is placed inside the source tree; Meson rejects absolute paths to places
# inside the source tree.
# For cross-compilation it is often not possible to run the Python interpreter in order
# to retrieve numpy's include directory. It can be specified in the cross file instead:
#
# [properties]
# numpy-include-dir = /abspath/to/host-pythons/site-packages/numpy/core/include
#
# This uses the path as is, and avoids running the interpreter.
incdir_numpy = meson.get_external_property('numpy-include-dir', 'not-given')
if incdir_numpy == 'not-given'
incdir_numpy = run_command(py3,
[
'-c',
'''import os
import numpy as np
try:
incdir = os.path.relpath(np.get_include())
except Exception:
incdir = np.get_include()
print(incdir)'''
],
check: true
).stdout().strip()
endif
numpy_dep = declare_dependency(
compile_args: [
'-DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION',
# Allow NumPy's printf format specifiers in C++.
'-D__STDC_FORMAT_MACROS=1',
],
include_directories: include_directories(incdir_numpy),
dependencies: py3_dep,
)

# For cross-compilation it is often not possible to run the Python interpreter in order
# to retrieve the platform-specific /dev/null. It can be specified in the cross file
# instead:
#
# [properties]
# devnull = /dev/null
#
# This uses the value as is, and avoids running the interpreter.
devnull = meson.get_external_property('devnull', 'not-given')
if devnull == 'not-given'
devnull = run_command(py3, '-c', 'import os; print(os.devnull)',
capture: true, check: true).stdout().strip()
endif

# Will only exist on Linux with older glibc.
dl = cc.find_library('dl', required: false)

# With Meson >= 1.2.0, use cpp_winlibs instead of manually searching.
if ['cygwin', 'windows'].contains(host_machine.system())
comctl32 = cc.find_library('comctl32')
ole32 = cc.find_library('ole32')
psapi = cc.find_library('psapi')
shell32 = cc.find_library('shell32')
user32 = cc.find_library('user32')
else
comctl32 = []
ole32 = []
psapi = []
shell32 = []
user32 = []
endif

extension_data = {
'_backend_agg': {
'subdir': 'matplotlib/backends',
'sources': files(
'py_converters.cpp',
'_backend_agg.cpp',
'_backend_agg_wrapper.cpp',
),
'dependencies': [agg_dep, numpy_dep, freetype_dep],
},
'_c_internal_utils': {
'subdir': 'matplotlib',
'sources': files(
'_c_internal_utils.c',
),
'dependencies': [py3_dep, dl, ole32, shell32, user32],
},
'ft2font': {
'subdir': 'matplotlib',
'sources': files(
'ft2font.cpp',
'ft2font_wrapper.cpp',
'py_converters.cpp',
),
'dependencies': [
freetype_dep, numpy_dep, agg_dep.partial_dependency(includes: true),
],
},
'_image': {
'subdir': 'matplotlib',
'sources': files(
'_image_wrapper.cpp',
'py_converters_11.cpp',
),
'dependencies': [
pybind11_dep,
# Only need source code files agg_image_filters.cpp and agg_trans_affine.cpp
agg_dep,
],
},
'_path': {
'subdir': 'matplotlib',
'sources': files(
'py_converters.cpp',
'_path_wrapper.cpp',
),
'dependencies': [numpy_dep, agg_dep],
},
'_qhull': {
'subdir': 'matplotlib',
'sources': files(
'_qhull_wrapper.cpp',
),
'dependencies': [numpy_dep, qhull_dep],
'c_args': [f'-DMPL_DEVNULL=@devnull@'],
'cpp_args': [f'-DMPL_DEVNULL=@devnull@'],
},
'_tkagg': {
'subdir': 'matplotlib/backends',
'sources': files(
'_tkagg.cpp',
),
'include_directories': include_directories('.'),
# The dl/psapi libraries are needed for finding Tcl/Tk at run time.
'dependencies': [
numpy_dep, agg_dep.partial_dependency(includes: true), dl, comctl32, psapi,
],
},
'_tri': {
'subdir': 'matplotlib',
'sources': files(
'tri/_tri.cpp',
'tri/_tri_wrapper.cpp',
),
'dependencies': [pybind11_dep],
},
'_ttconv': {
'subdir': 'matplotlib',
'sources': files(
'_ttconv.cpp',
),
'dependencies': [ttconv_dep, pybind11_dep],
},
}

cpp_special_arguments = []
if cpp.get_id() == 'msvc' and get_option('buildtype') != 'plain'
# Disable FH4 Exception Handling implementation so that we don't require
# VCRUNTIME140_1.dll. For more details, see:
# https://devblogs.microsoft.com/cppblog/making-cpp-exception-handling-smaller-x64/
# https://github.com/joerick/cibuildwheel/issues/423#issuecomment-677763904
cpp_special_arguments += ['/d2FH4-']
endif

foreach ext, kwargs : extension_data
# Ensure that PY_ARRAY_UNIQUE_SYMBOL is uniquely defined for each extension.
unique_array_api = '-DPY_ARRAY_UNIQUE_SYMBOL=MPL_@0@_ARRAY_API'.format(ext.replace('.', '_'))
additions = {
'c_args': [unique_array_api] + kwargs.get('c_args', []),
'cpp_args': cpp_special_arguments + [unique_array_api] + kwargs.get('cpp_args', []),
}
py3.extension_module(
ext,
install: true,
kwargs: kwargs + additions)
endforeach

if get_option('macosx') and host_machine.system() == 'darwin'
add_languages('objc', native: false)
py3.extension_module(
'_macosx',
subdir: 'matplotlib/backends',
sources: files(
'_macosx.m',
),
dependencies: dependency('appleframeworks', modules: 'Cocoa'),
override_options: ['werror=true'],
install: true,
)
endif
10 changes: 4 additions & 6 deletions src/tri/_tri.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
/* This file contains liberal use of asserts to assist code development and
* debugging. Standard matplotlib builds disable asserts so they cause no
* performance reduction. To enable the asserts, you need to undefine the
* NDEBUG macro, which is achieved by adding the following
* undef_macros=['NDEBUG']
* to the appropriate make_extension call in setupext.py, and then rebuilding.
/* This file contains liberal use of asserts to assist code development and debugging.
* Standard Matplotlib builds disable asserts so they cause no performance reduction. To
* enable the asserts, you need to undefine the NDEBUG macro, which is achieved by
* passing ``b_ndebug=false`` to the Meson configuration.
*/
#include "../mplutils.h"
#include "_tri.h"
Expand Down
7 changes: 7 additions & 0 deletions subprojects/freetype-2.11.1.wrap
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[wrap-file]
source_url = https://download.savannah.gnu.org/releases/freetype/freetype-2.11.1.tar.xz
source_filename = freetype-2.11.1.tar.xz
source_hash = 3333ae7cfda88429c97a7ae63b7d01ab398076c3b67182e960e5684050f2c5c8

[provide]
freetype-2.11.1 = freetype_dep
Loading

0 comments on commit 044a5e5

Please sign in to comment.