Skip to content

Commit

Permalink
Updates matplotlib, fixes an issue related to shared libc++
Browse files Browse the repository at this point in the history
  • Loading branch information
misl6 committed Jul 30, 2022
1 parent c77e07d commit f96f6de
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 179 deletions.
14 changes: 0 additions & 14 deletions pythonforandroid/recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,20 +492,6 @@ def get_recipe_env(self, arch=None, with_flags_in_cc=True):
if arch is None:
arch = self.filtered_archs[0]
env = arch.get_env(with_flags_in_cc=with_flags_in_cc)

if self.need_stl_shared:
env['CPPFLAGS'] = env.get('CPPFLAGS', '')
env['CPPFLAGS'] += ' -I{}'.format(self.ctx.ndk.libcxx_include_dir)

env['CXXFLAGS'] = env['CFLAGS'] + ' -frtti -fexceptions'

if with_flags_in_cc:
env['CXX'] += ' -frtti -fexceptions'

env['LDFLAGS'] += ' -L{}'.format(arch.ndk_lib_dir)
env['LIBS'] = env.get('LIBS', '') + " -l{}".format(
self.stl_lib_name
)
return env

def prebuild_arch(self, arch):
Expand Down
2 changes: 1 addition & 1 deletion pythonforandroid/recipes/cppy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class CppyRecipe(PythonRecipe):

# Pin to commit: `Nucleic migration and project documentation`,
# because the official releases are too old, at time of writing
version = '4e0b956'
version = '1.1.0'
url = 'https://github.com/nucleic/cppy/archive/{version}.zip'
call_hostpython_via_targetpython = False
# to be detected by the matplotlib install script
Expand Down
15 changes: 1 addition & 14 deletions pythonforandroid/recipes/kiwisolver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,9 @@ class KiwiSolverRecipe(CppCompiledComponentsPythonRecipe):
# changes that we want to include are merged to master branch
# Note: the commit we want to include is
# `Cppy use update and c++11 compatibility` (4858730)
version = '0846189'
version = '1.3.2'
url = 'https://github.com/nucleic/kiwi/archive/{version}.zip'
depends = ['cppy']

def get_recipe_env(self, arch=None, with_flags_in_cc=True):
env = super().get_recipe_env(arch, with_flags_in_cc)
if self.need_stl_shared:
# kiwisolver compile flags does not honor the standard flags:
# `CPPFLAGS` and `LDLIBS`, so we put in `CFLAGS` and `LDFLAGS` to
# correctly link with the `c++_shared` library
env['CFLAGS'] += f' -I{self.ctx.ndk.libcxx_include_dir}'
env['CFLAGS'] += ' -frtti -fexceptions'

env['LDFLAGS'] += f' -L{arch.ndk_lib_dir}'
env['LDFLAGS'] += f' -l{self.stl_lib_name}'
return env


recipe = KiwiSolverRecipe()
56 changes: 6 additions & 50 deletions pythonforandroid/recipes/matplotlib/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@

from pythonforandroid.logger import info_notify
from pythonforandroid.recipe import CppCompiledComponentsPythonRecipe
from pythonforandroid.util import ensure_dir

Expand All @@ -8,22 +6,20 @@

class MatplotlibRecipe(CppCompiledComponentsPythonRecipe):

version = '3.1.3'
version = '3.5.2'
url = 'https://github.com/matplotlib/matplotlib/archive/v{version}.zip'

depends = ['numpy', 'png', 'setuptools', 'freetype', 'kiwisolver']
depends = ['kiwisolver', 'numpy', 'pillow', 'setuptools', 'freetype']

python_depends = ['pyparsing', 'cycler', 'python-dateutil']
python_depends = ['cycler', 'fonttools', 'packaging', 'pyparsing', 'python-dateutil']

# We need to patch to:
# - make mpl install work without importing numpy
# - make mpl use shared libraries for freetype and png
# - make mpl link to png16, to match p4a library name for png
# - prevent mpl trying to build TkAgg, which wouldn't work
# on Android anyway but has build issues
patches = ['mpl_android_fixes.patch']

call_hostpython_via_targetpython = False
# patches = ['mpl_android_fixes.patch']

def generate_libraries_pc_files(self, arch):
"""
Expand All @@ -42,10 +38,9 @@ def generate_libraries_pc_files(self, arch):
# version for freetype, but we have our recipe named without
# the version...so we add it in here for our pc file
'freetype': 'freetype2.pc',
'png': 'png.pc',
}

for lib_name in {'freetype', 'png'}:
for lib_name in {'freetype'}:
pc_template_file = join(
self.get_recipe_dir(),
f'lib{lib_name}.pc.template'
Expand All @@ -67,53 +62,18 @@ def generate_libraries_pc_files(self, arch):
with open(pc_dest_file, 'w') as pc_file:
pc_file.write(text_buffer)

def download_web_backend_dependencies(self, arch):
"""
During building, host needs to download the jquery-ui package (in order
to make it work the mpl web backend). This operation seems to fail
in our CI tests, so we download this package at the expected location
by the mpl install script which is defined by the environ variable
`XDG_CACHE_HOME` (we modify that one in our `get_recipe_env` so it will
be the same regardless of the host platform).
"""

env = self.get_recipe_env(arch)

info_notify('Downloading jquery-ui for matplatlib web backend')
# We use the same jquery-ui version than mpl's setup.py script,
# inside function `_download_jquery_to`
jquery_sha = (
'f8233674366ab36b2c34c577ec77a3d70cac75d2e387d8587f3836345c0f624d'
)
url = "https://jqueryui.com/resources/download/jquery-ui-1.12.1.zip"
target_file = join(env['XDG_CACHE_HOME'], 'matplotlib', jquery_sha)

info_notify(f'Will download into {env["XDG_CACHE_HOME"]}')
ensure_dir(join(env['XDG_CACHE_HOME'], 'matplotlib'))
self.download_file(url, target_file)

def prebuild_arch(self, arch):
with open(join(self.get_recipe_dir(), 'setup.cfg.template')) as fileh:
setup_cfg = fileh.read()

with open(join(self.get_build_dir(arch), 'setup.cfg'), 'w') as fileh:
with open(join(self.get_build_dir(arch), 'mplsetup.cfg'), 'w') as fileh:
fileh.write(setup_cfg.format(
ndk_sysroot_usr=join(self.ctx.ndk.sysroot, 'usr')))

self.generate_libraries_pc_files(arch)
self.download_web_backend_dependencies(arch)

def get_recipe_env(self, arch=None, with_flags_in_cc=True):
env = super().get_recipe_env(arch, with_flags_in_cc)
if self.need_stl_shared:
# matplotlib compile flags does not honor the standard flags:
# `CPPFLAGS` and `LDLIBS`, so we put in `CFLAGS` and `LDFLAGS` to
# correctly link with the `c++_shared` library
env['CFLAGS'] += ' -I{}'.format(self.ctx.ndk.libcxx_include_dir)
env['CFLAGS'] += ' -frtti -fexceptions'

env['LDFLAGS'] += ' -L{}'.format(arch.ndk_lib_dir)
env['LDFLAGS'] += ' -l{}'.format(self.stl_lib_name)

# we modify `XDG_CACHE_HOME` to download `jquery-ui` into that folder,
# or mpl install will fail when trying to download/install it, but if
Expand All @@ -140,10 +100,6 @@ def get_recipe_env(self, arch=None, with_flags_in_cc=True):
# success with our build (without depending on system development
# libraries), but if we tell the compiler where to find our libraries
# and includes, then the install success :)
png = self.get_recipe('png', self.ctx)
env['CFLAGS'] += f' -I{png.get_build_dir(arch)}'
env['LDFLAGS'] += f' -L{join(png.get_build_dir(arch.arch), ".libs")}'

freetype = self.get_recipe('freetype', self.ctx)
free_lib_dir = join(freetype.get_build_dir(arch.arch), 'objs', '.libs')
free_inc_dir = join(freetype.get_build_dir(arch.arch), 'include')
Expand Down
107 changes: 26 additions & 81 deletions pythonforandroid/recipes/matplotlib/setup.cfg.template
Original file line number Diff line number Diff line change
@@ -1,93 +1,38 @@
# Rename this file to setup.cfg to modify Matplotlib's
# build options.

[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 = {ndk_sysroot_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
# FreeType, and then use that to build the ft2font extension. This
# ensures that test images are exactly reproducible.
# local_freetype = True

[status]
# To suppress display of the dependencies and their versions
# at the top of the build log, uncomment the following line:
#suppress = True
# Rename this file to mplsetup.cfg to modify Matplotlib's build options.

[libs]
# By default, Matplotlib builds with LTO, which may be slow if you re-compile
# often, and don't need the space saving/speedup.
enable_lto = False
# 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.
system_freetype = True
#system_qhull = False

[packages]
# There are a number of subpackages of Matplotlib that are considered
# optional. All except tests are installed by default, but that can
# be changed here.
#
tests = False
sample_data = False
#toolkits = True
# Tests for the toolkits are only automatically installed
# if the tests and toolkits packages are also getting installed.
toolkits_tests = False
# There are a number of data subpackages from Matplotlib that are
# considered optional. All except 'tests' data (meaning the baseline
# image files) are installed by default, but that can be changed here.
#tests = False

[gui_support]
# Matplotlib supports multiple GUI toolkits, including
# GTK3, MacOSX, Qt4, Qt5, Tk, and WX. Support for many of
# these toolkits requires AGG, the Anti-Grain Geometry library,
# which is provided by Matplotlib and built by default.
#
# Some backends are written in pure Python, and others require
# extension code to be compiled. By default, Matplotlib checks for
# these GUI toolkits during installation and, if present, compiles the
# required extensions to support the toolkit.
#
# - Tk support requires Tk development headers and Tkinter.
# - Mac OSX backend requires the Cocoa headers included with XCode.
# - Windowing is MS-Windows specific, and requires the "windows.h"
# header.
# Matplotlib supports multiple GUI toolkits, known as backends.
# The MacOSX backend requires the Cocoa headers included with XCode.
# You can select whether to build it by uncommenting the following line.
# It is never built on Linux or Windows, regardless of the config value.
#
# The other GUI toolkits do not require any extension code, and can be
# used as long as the libraries are installed on your system --
# therefore they are installed unconditionally.
#
# You can uncomment any the following lines to change this
# behavior. Acceptable values are:
#
# True: build the extension. Exits with a warning if the
# required dependencies are not available
# False: do not build the extension
# auto: build if the required dependencies are available,
# otherwise skip silently. This is the default
# behavior
#
agg = True
cairo = False
gtk3agg = False
gtk3cairo = False
macosx = False
pyside = False
qt4agg = False
tkagg = False
windowing = False
wxagg = False

[rc_options]
# User-configurable options
#
# Default backend, one of: Agg, Cairo, GTK3Agg, GTK3Cairo, MacOSX, Pdf, Ps,
# Qt4Agg, Qt5Agg, SVG, TkAgg, WX, WXAgg.
# Default backend, one of: Agg, Cairo, GTK3Agg, GTK3Cairo, GTK4Agg, GTK4Cairo,
# MacOSX, Pdf, Ps, QtAgg, QtCairo, SVG, TkAgg, WX, WXAgg.
#
# The Agg, Ps, Pdf and SVG backends do not require external dependencies. Do
# not choose MacOSX, or TkAgg if you have disabled the relevant extension
# modules. Agg will be used by default.
#
backend = Agg
#

[package_data]
# Package additional files found in the lib/matplotlib directories.
# The Agg, Ps, Pdf and SVG backends do not require external dependencies. Do
# not choose MacOSX if you have disabled the relevant extension modules. The
# default is determined by fallback.
#
# On Windows, package DLL files.
#dlls = True
#backend = Agg
19 changes: 0 additions & 19 deletions tests/test_recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,25 +279,6 @@ def test_get_recipe_env_with(
)
self.assertIsInstance(env, dict)

# check `CPPFLAGS`
expected_cppflags = {
'-I{libcxx_include}'.format(libcxx_include=self.ctx.ndk.libcxx_include_dir)
}
self.assertIn('CPPFLAGS', env)
for flags in expected_cppflags:
self.assertIn(flags, env['CPPFLAGS'])

# check `LIBS`
self.assertIn('LDFLAGS', env)
self.assertIn('-L' + arch.ndk_lib_dir, env['LDFLAGS'])
self.assertIn('LIBS', env)
self.assertIn('-lc++_shared', env['LIBS'])

# check `CXXFLAGS` and `CXX`
for flag in {'CXXFLAGS', 'CXX'}:
self.assertIn(flag, env)
self.assertIn('-frtti -fexceptions', env[flag])

@mock.patch('pythonforandroid.recipe.Recipe.install_libs')
@mock.patch('pythonforandroid.recipe.isfile')
@mock.patch('pythonforandroid.build.ensure_dir')
Expand Down

0 comments on commit f96f6de

Please sign in to comment.