1
1
2
+ from pythonforandroid .logger import info_notify
2
3
from pythonforandroid .recipe import CppCompiledComponentsPythonRecipe
4
+ from pythonforandroid .util import ensure_dir
3
5
4
6
from os .path import join
5
7
6
8
7
9
class MatplotlibRecipe (CppCompiledComponentsPythonRecipe ):
8
10
9
- version = '3.0 .3'
11
+ version = '3.1 .3'
10
12
url = 'https://github.com/matplotlib/matplotlib/archive/v{version}.zip'
11
13
12
14
depends = ['numpy' , 'png' , 'setuptools' , 'freetype' , 'kiwisolver' ]
15
+ conflicts = ['python2' ]
13
16
14
17
python_depends = ['pyparsing' , 'cycler' , 'python-dateutil' ]
15
18
16
19
# We need to patch to:
17
- # - make mpl build against the same numpy version as the numpy recipe
18
- # (this could be done better by setting the target version dynamically)
19
- # - prevent mpl trying to build TkAgg, which wouldn't work on Android anyway but has build issues
20
+ # - make mpl install work without importing numpy
21
+ # - make mpl use shared libraries for freetype and png
22
+ # - make mpl link to png16, to match p4a library name for png
23
+ # - prevent mpl trying to build TkAgg, which wouldn't work
24
+ # on Android anyway but has build issues
20
25
patches = ['mpl_android_fixes.patch' ]
21
26
22
27
call_hostpython_via_targetpython = False
23
28
29
+ def generate_libraries_pc_files (self , arch ):
30
+ """
31
+ Create *.pc files for libraries that `matplotib` depends on.
32
+
33
+ Because, for unix platforms, the mpl install script uses `pkg-config`
34
+ to detect libraries installed in non standard locations (our case...
35
+ well...we don't even install the libraries...so we must trick a little
36
+ the mlp install).
37
+ """
38
+ pkg_config_path = self .get_recipe_env (arch )['PKG_CONFIG_PATH' ]
39
+ ensure_dir (pkg_config_path )
40
+
41
+ lib_to_pc_file = {
42
+ # `pkg-config` search for version freetype2.pc, our current
43
+ # version for freetype, but we have our recipe named without
44
+ # the version...so we add it in here for our pc file
45
+ 'freetype' : 'freetype2.pc' ,
46
+ 'png' : 'png.pc' ,
47
+ }
48
+
49
+ for lib_name in {'freetype' , 'png' }:
50
+ pc_template_file = join (
51
+ self .get_recipe_dir (),
52
+ f'lib{ lib_name } .pc.template'
53
+ )
54
+ # read template file into buffer
55
+ with open (pc_template_file ) as template_file :
56
+ text_buffer = template_file .read ()
57
+ # set the library absolute path and library version
58
+ lib_recipe = self .get_recipe (lib_name , self .ctx )
59
+ text_buffer = text_buffer .replace (
60
+ 'path_to_built' , lib_recipe .get_build_dir (arch .arch ),
61
+ )
62
+ text_buffer = text_buffer .replace (
63
+ 'library_version' , lib_recipe .version ,
64
+ )
65
+
66
+ # write the library pc file into our defined dir `PKG_CONFIG_PATH`
67
+ pc_dest_file = join (pkg_config_path , lib_to_pc_file [lib_name ])
68
+ with open (pc_dest_file , 'w' ) as pc_file :
69
+ pc_file .write (text_buffer )
70
+
71
+ def download_web_backend_dependencies (self , arch ):
72
+ """
73
+ During building, host needs to download the jquery-ui package (in order
74
+ to make it work the mpl web backend). This operation seems to fail
75
+ in our CI tests, so we download this package at the expected location
76
+ by the mpl install script which is defined by the environ variable
77
+ `XDG_CACHE_HOME` (we modify that one in our `get_recipe_env` so it will
78
+ be the same regardless of the host platform).
79
+ """
80
+
81
+ env = self .get_recipe_env (arch )
82
+
83
+ info_notify ('Downloading jquery-ui for matplatlib web backend' )
84
+ # We use the same jquery-ui version than mpl's setup.py script,
85
+ # inside function `_download_jquery_to`
86
+ jquery_sha = (
87
+ 'f8233674366ab36b2c34c577ec77a3d70cac75d2e387d8587f3836345c0f624d'
88
+ )
89
+ url = f'https://jqueryui.com/resources/download/jquery-ui-1.12.1.zip'
90
+ target_file = join (env ['XDG_CACHE_HOME' ], 'matplotlib' , jquery_sha )
91
+
92
+ info_notify (f'Will download into { env ["XDG_CACHE_HOME" ]} ' )
93
+ ensure_dir (join (env ['XDG_CACHE_HOME' ], 'matplotlib' ))
94
+ self .download_file (url , target_file )
95
+
24
96
def prebuild_arch (self , arch ):
25
97
with open (join (self .get_recipe_dir (), 'setup.cfg.template' )) as fileh :
26
98
setup_cfg = fileh .read ()
@@ -29,5 +101,64 @@ def prebuild_arch(self, arch):
29
101
fileh .write (setup_cfg .format (
30
102
ndk_sysroot_usr = join (self .ctx .ndk_dir , 'sysroot' , 'usr' )))
31
103
104
+ self .generate_libraries_pc_files (arch )
105
+ self .download_web_backend_dependencies (arch )
106
+
107
+ def get_recipe_env (self , arch = None , with_flags_in_cc = True ):
108
+ env = super ().get_recipe_env (arch , with_flags_in_cc )
109
+ if self .need_stl_shared :
110
+ # matplotlib compile flags does not honor the standard flags:
111
+ # `CPPFLAGS` and `LDLIBS`, so we put in `CFLAGS` and `LDFLAGS` to
112
+ # correctly link with the `c++_shared` library
113
+ env ['CFLAGS' ] += ' -I{}' .format (self .stl_include_dir )
114
+ env ['CFLAGS' ] += ' -frtti -fexceptions'
115
+
116
+ env ['LDFLAGS' ] += ' -L{}' .format (self .get_stl_lib_dir (arch ))
117
+ env ['LDFLAGS' ] += ' -l{}' .format (self .stl_lib_name )
118
+
119
+ # we modify `XDG_CACHE_HOME` to download `jquery-ui` into that folder,
120
+ # or mpl install will fail when trying to download/install it, but if
121
+ # we have the proper package already downloaded, it will use the cached
122
+ # package to successfully finish the installation.
123
+ # Note: this may not be necessary for some local systems, but it is
124
+ # for our CI providers: `gh-actions` and travis, which will
125
+ # fail trying to download the `jquery-ui` package
126
+ env ['XDG_CACHE_HOME' ] = join (self .get_build_dir (arch ), 'p4a_files' )
127
+ # we make use of the same directory than `XDG_CACHE_HOME`, for our
128
+ # custom library pc files, so we have all the install files that we
129
+ # generate at the same place
130
+ env ['PKG_CONFIG_PATH' ] = env ['XDG_CACHE_HOME' ]
131
+
132
+ # We set a new environ variable `NUMPY_INCLUDES` to be able to tell
133
+ # the matplotlib script where to find our numpy without importing it
134
+ # (which will fail, because numpy isn't installed in our hostpython)
135
+ env ['NUMPY_INCLUDES' ] = join (
136
+ self .ctx .get_site_packages_dir (),
137
+ 'numpy' , 'core' , 'include' ,
138
+ )
139
+
140
+ # creating proper *.pc files for our libraries does not seem enough to
141
+ # success with our build (without depending on system development
142
+ # libraries), but if we tell the compiler where to find our libraries
143
+ # and includes, then the install success :)
144
+ png = self .get_recipe ('png' , self .ctx )
145
+ env ['CFLAGS' ] += f' -I{ png .get_build_dir (arch )} '
146
+ env ['LDFLAGS' ] += f' -L{ join (png .get_build_dir (arch .arch ), ".libs" )} '
147
+
148
+ freetype = self .get_recipe ('freetype' , self .ctx )
149
+ free_lib_dir = join (freetype .get_build_dir (arch .arch ), 'objs' , '.libs' )
150
+ free_inc_dir = join (freetype .get_build_dir (arch .arch ), 'include' )
151
+ env ['CFLAGS' ] += f' -I{ free_inc_dir } '
152
+ env ['LDFLAGS' ] += f' -L{ free_lib_dir } '
153
+
154
+ # `freetype` could be built with `harfbuzz` support,
155
+ # so we also include the necessary flags...just to be sure
156
+ if 'harfbuzz' in self .ctx .recipe_build_order :
157
+ harfbuzz = self .get_recipe ('harfbuzz' , self .ctx )
158
+ harf_build = harfbuzz .get_build_dir (arch .arch )
159
+ env ['CFLAGS' ] += f' -I{ harf_build } -I{ join (harf_build , "src" )} '
160
+ env ['LDFLAGS' ] += f' -L{ join (harf_build , "src" , ".libs" )} '
161
+ return env
162
+
32
163
33
164
recipe = MatplotlibRecipe ()
0 commit comments