Skip to content

Commit 9e39fbe

Browse files
opacaminclement
authored andcommitted
[WIP][LIBS - PART IV] Rework of shapely and libgeos (#1967)
* [recipe-stl] Make libgeos a library recipe * [recipe-stl] Fix shapely for reworked libgeos
1 parent 129601c commit 9e39fbe

File tree

3 files changed

+112
-55
lines changed

3 files changed

+112
-55
lines changed
Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,52 @@
1-
from pythonforandroid.toolchain import Recipe, shprint, shutil, current_directory
2-
from os.path import exists, join
3-
import sh
1+
from pythonforandroid.util import current_directory, ensure_dir
2+
from pythonforandroid.toolchain import shprint
3+
from pythonforandroid.recipe import Recipe
44
from multiprocessing import cpu_count
5+
from os.path import join
6+
import sh
57

68

79
class LibgeosRecipe(Recipe):
8-
version = '3.5'
9-
# url = 'http://download.osgeo.org/geos/geos-{version}.tar.bz2'
10-
url = 'https://github.com/libgeos/libgeos/archive/svn-{version}.zip'
10+
version = '3.7.1'
11+
url = 'https://github.com/libgeos/libgeos/archive/{version}.zip'
1112
depends = []
12-
13-
def should_build(self, arch):
14-
super(LibgeosRecipe, self).should_build(arch)
15-
return not exists(join(self.ctx.get_libs_dir(arch.arch), 'libgeos_c.so'))
13+
built_libraries = {
14+
'libgeos.so': 'install_target/lib',
15+
'libgeos_c.so': 'install_target/lib'
16+
}
17+
need_stl_shared = True
1618

1719
def build_arch(self, arch):
18-
super(LibgeosRecipe, self).build_arch(arch)
19-
env = self.get_recipe_env(arch)
20-
21-
with current_directory(self.get_build_dir(arch.arch)):
22-
dst_dir = join(self.get_build_dir(arch.arch), 'dist')
23-
bash = sh.Command('bash')
24-
print("If this fails make sure you have autoconf and libtool installed")
25-
shprint(bash, 'autogen.sh') # Requires autoconf and libtool
26-
shprint(bash, 'configure', '--host=arm-linux-androideabi', '--enable-shared', '--prefix={}'.format(dst_dir), _env=env)
27-
shprint(sh.make, '-j', str(cpu_count()), _env=env)
20+
source_dir = self.get_build_dir(arch.arch)
21+
build_target = join(source_dir, 'build_target')
22+
install_target = join(source_dir, 'install_target')
23+
24+
ensure_dir(build_target)
25+
with current_directory(build_target):
26+
env = self.get_recipe_env(arch)
27+
shprint(sh.cmake, source_dir,
28+
'-DANDROID_ABI={}'.format(arch.arch),
29+
'-DANDROID_NATIVE_API_LEVEL={}'.format(self.ctx.ndk_api),
30+
'-DANDROID_STL=' + self.stl_lib_name,
31+
32+
'-DCMAKE_TOOLCHAIN_FILE={}'.format(
33+
join(self.ctx.ndk_dir, 'build', 'cmake',
34+
'android.toolchain.cmake')),
35+
'-DCMAKE_INSTALL_PREFIX={}'.format(install_target),
36+
'-DCMAKE_BUILD_TYPE=Release',
37+
38+
'-DGEOS_ENABLE_TESTS=OFF',
39+
40+
'-DBUILD_SHARED_LIBS=1',
41+
42+
_env=env)
43+
shprint(sh.make, '-j' + str(cpu_count()), _env=env)
44+
45+
# We make the install because this way we will have all the
46+
# includes in one place (mostly we are interested in `geos_c.h`,
47+
# which is not in the include folder, so this way we make easier to
48+
# link with this library...case of shapely's recipe)
2849
shprint(sh.make, 'install', _env=env)
29-
shutil.copyfile('{}/lib/libgeos_c.so'.format(dst_dir), join(self.ctx.get_libs_dir(arch.arch), 'libgeos_c.so'))
30-
31-
def get_recipe_env(self, arch):
32-
env = super(LibgeosRecipe, self).get_recipe_env(arch)
33-
env['CXXFLAGS'] += ' -I{}/sources/cxx-stl/gnu-libstdc++/4.8/include'.format(self.ctx.ndk_dir)
34-
env['CXXFLAGS'] += ' -I{}/sources/cxx-stl/gnu-libstdc++/4.8/libs/{}/include'.format(
35-
self.ctx.ndk_dir, arch)
36-
env['CXXFLAGS'] += ' -L{}/sources/cxx-stl/gnu-libstdc++/4.8/libs/{}'.format(
37-
self.ctx.ndk_dir, arch)
38-
env['CXXFLAGS'] += ' -lgnustl_shared'
39-
env['LDFLAGS'] += ' -L{}/sources/cxx-stl/gnu-libstdc++/4.8/libs/{}'.format(
40-
self.ctx.ndk_dir, arch)
41-
return env
4250

4351

4452
recipe = LibgeosRecipe()

pythonforandroid/recipes/shapely/__init__.py

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,38 @@
1-
from pythonforandroid.recipe import Recipe, CythonRecipe
1+
from pythonforandroid.recipe import CythonRecipe
2+
from os.path import join
23

34

45
class ShapelyRecipe(CythonRecipe):
5-
version = '1.5'
6-
url = 'https://github.com/Toblerity/Shapely/archive/master.zip'
6+
version = '1.7a1'
7+
url = 'https://github.com/Toblerity/Shapely/archive/{version}.tar.gz'
78
depends = ['setuptools', 'libgeos']
9+
10+
# Actually, this recipe seems to compile/install fine for python2, but it
11+
# fails at runtime when importing module with:
12+
# `[Errno 2] No such file or directory`
13+
conflicts = ['python2']
14+
815
call_hostpython_via_targetpython = False
916

10-
patches = ['setup.patch'] # Patch to force setup to fail when C extention fails to build
17+
# Patch to avoid libgeos check (because it fails), insert environment
18+
# variables for our libgeos build (includes, lib paths...) and force
19+
# the cython's compilation to raise an error in case that it fails
20+
patches = ['setup.patch']
21+
22+
# Don't Force Cython
23+
# setup_extra_args = ['sdist']
24+
25+
def get_recipe_env(self, arch=None, with_flags_in_cc=True):
26+
env = super(ShapelyRecipe, self).get_recipe_env(arch)
1127

12-
# setup_extra_args = ['sdist'] # DontForce Cython
28+
libgeos_install = join(self.get_recipe(
29+
'libgeos', self.ctx).get_build_dir(arch.arch), 'install_target')
30+
# All this `GEOS_X` variables should be string types, separated
31+
# by commas in case that we need to pass more than one value
32+
env['GEOS_INCLUDE_DIRS'] = join(libgeos_install, 'include')
33+
env['GEOS_LIBRARY_DIRS'] = join(libgeos_install, 'lib')
34+
env['GEOS_LIBRARIES'] = 'geos_c,geos'
1335

14-
def get_recipe_env(self, arch, with_flags_in_cc=True):
15-
""" Add libgeos headers to path """
16-
env = super(ShapelyRecipe, self).get_recipe_env(arch, with_flags_in_cc)
17-
libgeos_dir = Recipe.get_recipe('libgeos', self.ctx).get_build_dir(arch.arch)
18-
env['CFLAGS'] += " -I{}/dist/include".format(libgeos_dir)
1936
return env
2037

2138

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,44 @@
1-
*** shapely/setup.py 2016-06-29 11:29:49.000000000 -0400
2-
--- b/setup.py 2016-07-09 01:51:37.759670990 -0400
3-
***************
4-
*** 359,364 ****
5-
--- 359,365 ----
6-
construct_build_ext(existing_build_ext)
7-
setup(ext_modules=ext_modules, **setup_args)
8-
except BuildFailed as ex:
9-
+ raise # Force python only build to fail
10-
BUILD_EXT_WARNING = "The C extension could not be compiled, " \
11-
"speedups are not enabled."
12-
log.warn(ex)
1+
This patch does three things:
2+
- disable the libgeos check, because, even setting the proper env variables,
3+
it fails to load our libgeos library, so we skip that because it's not
4+
mandatory for the cythonizing.
5+
- sets some environment variables into the setup.py file, so we can pass
6+
our libgeos information (includes, lib path and libraries)
7+
- force to raise an error when cython file to compile (our current build
8+
system relies on this failure to do the proper `cythonizing`, if we don't
9+
raise the error, we will end up with the package installed without the
10+
speed optimizations.
11+
--- Shapely-1.7a1/setup.py.orig 2018-07-29 22:53:13.000000000 +0200
12+
+++ Shapely-1.7a1/setup.py 2019-02-24 14:26:19.178610660 +0100
13+
@@ -82,8 +82,8 @@ if not (py_version == (2, 7) or py_versi
14+
15+
# Get geos_version from GEOS dynamic library, which depends on
16+
# GEOS_LIBRARY_PATH and/or GEOS_CONFIG environment variables
17+
-from shapely._buildcfg import geos_version_string, geos_version, \
18+
- geos_config, get_geos_config
19+
+# from shapely._buildcfg import geos_version_string, geos_version, \
20+
+# geos_config, get_geos_config
21+
22+
logging.basicConfig()
23+
log = logging.getLogger(__file__)
24+
@@ -248,9 +248,9 @@ if sys.platform == 'win32':
25+
setup_args['package_data']['shapely'].append('shapely/DLLs/*.dll')
26+
27+
# Prepare build opts and args for the speedups extension module.
28+
-include_dirs = []
29+
-library_dirs = []
30+
-libraries = []
31+
+include_dirs = os.environ.get('GEOS_INCLUDE_DIRS', '').split(',')
32+
+library_dirs = os.environ.get('GEOS_LIBRARY_DIRS', '').split(',')
33+
+libraries = os.environ.get('GEOS_LIBRARIES', '').split(',')
34+
extra_link_args = []
35+
36+
# If NO_GEOS_CONFIG is set in the environment, geos-config will not
37+
@@ -375,6 +375,7 @@ try:
38+
construct_build_ext(existing_build_ext)
39+
setup(ext_modules=ext_modules, **setup_args)
40+
except BuildFailed as ex:
41+
+ raise # Force python only build to fail
42+
BUILD_EXT_WARNING = "The C extension could not be compiled, " \
43+
"speedups are not enabled."
44+
log.warn(ex)

0 commit comments

Comments
 (0)