Skip to content

Commit 41a7797

Browse files
committed
add scipy support
1 parent e62d33c commit 41a7797

8 files changed

Lines changed: 204 additions & 50 deletions

File tree

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from pythonforandroid.recipe import Recipe
2+
from pythonforandroid.logger import shprint
3+
from pythonforandroid.util import current_directory, ensure_dir
4+
from multiprocessing import cpu_count
5+
from os.path import join
6+
import sh
7+
8+
9+
class This(Recipe):
10+
11+
name = 'lapack'
12+
version = 'v3.9.0'
13+
url = 'https://github.com/Reference-LAPACK/lapack/archive/{version}.tar.gz'
14+
libdir = 'build/install/lib'
15+
built_libraries = {'libblas.so': libdir, 'liblapack.so': libdir, 'libcblas.so' :libdir}
16+
need_stl_shared = True
17+
18+
def get_recipe_env(self, arch):
19+
env = super().get_recipe_env(arch)
20+
sysroot = f"{self.ctx.ndk_dir}/platforms/{env['NDK_API']}/{arch.platform_dir}"
21+
FC =f"{env['TOOLCHAIN_PREFIX']}-gfortran"
22+
env['FC'] = f'{FC} --sysroot={sysroot}'
23+
if sh.which(FC) is None:
24+
raise Exception(f"{FC} not found. See https://github.com/mzakharo/android-gfortran")
25+
return env
26+
27+
def build_arch(self, arch):
28+
source_dir = self.get_build_dir(arch.arch)
29+
build_target = join(source_dir, 'build')
30+
install_target = join(build_target, 'install')
31+
32+
ensure_dir(build_target)
33+
with current_directory(build_target):
34+
env = self.get_recipe_env(arch)
35+
shprint(sh.rm, '-rf', 'CMakeFiles/', 'CMakeCache.txt', _env=env)
36+
shprint(sh.cmake, source_dir,
37+
'-DCMAKE_SYSTEM_NAME=Android',
38+
'-DCMAKE_POSITION_INDEPENDENT_CODE=1',
39+
'-DCMAKE_ANDROID_ARCH_ABI={arch}'.format(arch=arch.arch),
40+
'-DCMAKE_ANDROID_NDK=' + self.ctx.ndk_dir,
41+
'-DCMAKE_BUILD_TYPE=Release',
42+
'-DCMAKE_INSTALL_PREFIX={}'.format(install_target),
43+
'-DANDROID_ABI={arch}'.format(arch=arch.arch),
44+
'-DANDROID_ARM_NEON=ON',
45+
'-DENABLE_NEON=ON',
46+
'-DCBLAS=ON',
47+
'-DBUILD_SHARED_LIBS=ON',
48+
_env=env)
49+
shprint(sh.make, '-j' + str(cpu_count()), _env=env)
50+
shprint(sh.make, 'install', _env=env)
51+
52+
53+
recipe = This()

pythonforandroid/recipes/numpy/__init__.py

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,59 @@
1-
from pythonforandroid.recipe import CompiledComponentsPythonRecipe
1+
from pythonforandroid.recipe import CompiledComponentsPythonRecipe, sh, info, current_directory, shprint
22
from multiprocessing import cpu_count
3-
from os.path import join
4-
3+
from os.path import join, exists
4+
import glob
55

66
class NumpyRecipe(CompiledComponentsPythonRecipe):
77

88
version = '1.18.1'
99
url = 'https://pypi.python.org/packages/source/n/numpy/numpy-{version}.zip'
1010
site_packages_name = 'numpy'
1111
depends = ['setuptools', 'cython']
12+
install_in_hostpython = True
13+
call_hostpython_via_targetpython = False
1214

1315
patches = [
16+
join('patches', 'hostnumpy-xlocale.patch'),
17+
join('patches', 'remove-default-paths.patch'),
1418
join('patches', 'add_libm_explicitly_to_build.patch'),
15-
join('patches', 'do_not_use_system_libs.patch'),
16-
join('patches', 'remove_unittest_call.patch'),
19+
join('patches', 'compiler_cxx_fix.patch'),
1720
]
1821

19-
call_hostpython_via_targetpython = False
22+
#add clean --force
23+
def _build_compiled_components(self, arch):
24+
info('Building compiled components in {}'.format(self.name))
25+
26+
env = self.get_recipe_env(arch)
27+
with current_directory(self.get_build_dir(arch.arch)):
28+
hostpython = sh.Command(self.real_hostpython_location)
29+
if self.install_in_hostpython:
30+
shprint(hostpython, 'setup.py', 'clean', '--all', '--force', _env=env)
31+
hostpython = sh.Command(self.hostpython_location)
32+
shprint(hostpython, 'setup.py', self.build_cmd, '-v',
33+
_env=env, *self.setup_extra_args)
34+
build_dir = glob.glob('build/lib.*')[0]
35+
shprint(sh.find, build_dir, '-name', '"*.o"', '-exec',
36+
env['STRIP'], '{}', ';', _env=env)
37+
38+
#add clean --force
39+
def _rebuild_compiled_components(self, arch, env):
40+
info('Rebuilding compiled components in {}'.format(self.name))
41+
42+
hostpython = sh.Command(self.real_hostpython_location)
43+
shprint(hostpython, 'setup.py', 'clean', '--all', '--force', _env=env)
44+
shprint(hostpython, 'setup.py', self.build_cmd, '-v', _env=env,
45+
*self.setup_extra_args)
46+
2047

2148
def build_compiled_components(self, arch):
2249
self.setup_extra_args = ['-j', str(cpu_count())]
23-
super().build_compiled_components(arch)
50+
self._build_compiled_components(arch)
2451
self.setup_extra_args = []
2552

53+
2654
def rebuild_compiled_components(self, arch, env):
2755
self.setup_extra_args = ['-j', str(cpu_count())]
28-
super().rebuild_compiled_components(arch, env)
56+
self._rebuild_compiled_components(arch, env)
2957
self.setup_extra_args = []
3058

3159

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
diff --git a/numpy/distutils/ccompiler.py b/numpy/distutils/ccompiler.py
2+
index 6438790..a5f1527 100644
3+
--- a/numpy/distutils/ccompiler.py
4+
+++ b/numpy/distutils/ccompiler.py
5+
@@ -686,13 +686,13 @@ def CCompiler_cxx_compiler(self):
6+
return self
7+
8+
cxx = copy(self)
9+
- cxx.compiler_so = [cxx.compiler_cxx[0]] + cxx.compiler_so[1:]
10+
+ cxx.compiler_so = cxx.compiler_cxx + cxx.compiler_so[1:]
11+
if sys.platform.startswith('aix') and 'ld_so_aix' in cxx.linker_so[0]:
12+
# AIX needs the ld_so_aix script included with Python
13+
cxx.linker_so = [cxx.linker_so[0], cxx.compiler_cxx[0]] \
14+
+ cxx.linker_so[2:]
15+
else:
16+
- cxx.linker_so = [cxx.compiler_cxx[0]] + cxx.linker_so[1:]
17+
+ cxx.linker_so = cxx.compiler_cxx + cxx.linker_so[1:]
18+
return cxx
19+
20+
replace_method(CCompiler, 'cxx_compiler', CCompiler_cxx_compiler)

pythonforandroid/recipes/numpy/patches/do_not_use_system_libs.patch

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
diff --git a/numpy/core/src/common/numpyos.c b/numpy/core/src/common/numpyos.c
2+
index d60b1ca..8972144 100644
3+
--- a/numpy/core/src/common/numpyos.c
4+
+++ b/numpy/core/src/common/numpyos.c
5+
@@ -20,7 +20,7 @@
6+
* the defines from xlocale.h are included in locale.h on some systems;
7+
* see gh-8367
8+
*/
9+
- #include <xlocale.h>
10+
+ #include <locale.h>
11+
#endif
12+
#endif
13+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
diff --git a/numpy/distutils/system_info.py b/numpy/distutils/system_info.py
2+
index fc7018a..7b514bc 100644
3+
--- a/numpy/distutils/system_info.py
4+
+++ b/numpy/distutils/system_info.py
5+
@@ -340,10 +340,10 @@ if os.path.join(sys.prefix, 'lib') not in default_lib_dirs:
6+
default_include_dirs.append(os.path.join(sys.prefix, 'include'))
7+
default_src_dirs.append(os.path.join(sys.prefix, 'src'))
8+
9+
-default_lib_dirs = [_m for _m in default_lib_dirs if os.path.isdir(_m)]
10+
-default_runtime_dirs = [_m for _m in default_runtime_dirs if os.path.isdir(_m)]
11+
-default_include_dirs = [_m for _m in default_include_dirs if os.path.isdir(_m)]
12+
-default_src_dirs = [_m for _m in default_src_dirs if os.path.isdir(_m)]
13+
+default_lib_dirs = [] #[_m for _m in default_lib_dirs if os.path.isdir(_m)]
14+
+default_runtime_dirs =[] # [_m for _m in default_runtime_dirs if os.path.isdir(_m)]
15+
+default_include_dirs =[] # [_m for _m in default_include_dirs if os.path.isdir(_m)]
16+
+default_src_dirs =[] # [_m for _m in default_src_dirs if os.path.isdir(_m)]
17+
18+
so_ext = get_shared_lib_extension()
19+
20+
@@ -814,7 +814,7 @@ class system_info(object):
21+
path = self.get_paths(self.section, key)
22+
if path == ['']:
23+
path = []
24+
- return path
25+
+ return []
26+
27+
def get_include_dirs(self, key='include_dirs'):
28+
return self.get_paths(self.section, key)

pythonforandroid/recipes/numpy/patches/remove_unittest_call.patch

Lines changed: 0 additions & 30 deletions
This file was deleted.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from pythonforandroid.recipe import CompiledComponentsPythonRecipe, Recipe
2+
from multiprocessing import cpu_count
3+
from os.path import join
4+
import sh
5+
6+
7+
class ThisRecipe(CompiledComponentsPythonRecipe):
8+
9+
version = '1.5.4'
10+
url = f'https://github.com/scipy/scipy/releases/download/v{version}/scipy-{version}.zip'
11+
site_packages_name = 'scipy'
12+
depends = ['setuptools', 'cython', 'numpy', 'lapack']
13+
call_hostpython_via_targetpython = False
14+
15+
def build_compiled_components(self, arch):
16+
self.setup_extra_args = ['-j', str(cpu_count())]
17+
super().build_compiled_components(arch)
18+
self.setup_extra_args = []
19+
20+
def rebuild_compiled_components(self, arch, env):
21+
self.setup_extra_args = ['-j', str(cpu_count())]
22+
super().rebuild_compiled_components(arch, env)
23+
self.setup_extra_args = []
24+
25+
def get_recipe_env(self, arch):
26+
env = super().get_recipe_env(arch)
27+
28+
#hard-coded parameters
29+
GCC_VER = '4.9'
30+
HOST = 'linux-x86_64'
31+
LIB = 'lib64'
32+
33+
if sh.which('ccache') is not None:
34+
raise Exception("'ccache' is not supported by numpy C++ distutils, please uninstall 'ccache'")
35+
36+
#generated paths/variables
37+
prefix = env['TOOLCHAIN_PREFIX']
38+
lapack_dir = join(Recipe.get_recipe('lapack', self.ctx).get_build_dir(arch.arch), 'build', 'install')
39+
sysroot = f"{self.ctx.ndk_dir}/platforms/{env['NDK_API']}/{arch.platform_dir}"
40+
sysroot_include = f'{self.ctx.ndk_dir}/toolchains/llvm/prebuilt/{HOST}/sysroot/usr/include'
41+
libgfortran = f'{self.ctx.ndk_dir}/toolchains/{prefix}-{GCC_VER}/prebuilt/{HOST}/{prefix}/{LIB}'
42+
numpylib = self.ctx.get_python_install_dir() + '/numpy/core/lib'
43+
LDSHARED_opts = env['LDSHARED'].split('clang')[1]
44+
45+
env['LAPACK'] = f'{lapack_dir}/lib'
46+
env['BLAS'] = env['LAPACK']
47+
env['F90'] = f'{prefix}-gfortran'
48+
env['CXX'] += f' -Wl,-l{self.stl_lib_name} -Wl,-L{self.get_stl_lib_dir(arch)}'
49+
env['CPPFLAGS'] += f' --sysroot={sysroot} -I{sysroot_include}/c++/v1 -I{sysroot_include}'
50+
env['LDSHARED'] = 'clang'
51+
env['LDFLAGS'] += f' {LDSHARED_opts} --sysroot={sysroot} -L{libgfortran} -L{numpylib}'
52+
return env
53+
54+
recipe = ThisRecipe()

0 commit comments

Comments
 (0)