Skip to content

Commit e3123f4

Browse files
opacamAndreMiras
authored andcommitted
Rework for Pillow/pil recipes & update jpeg and png (kivy#1573)
* Force to build only static library for freetype/harfbuzz, format source code and fix imports We force to only build the static library to avoid that Pillow/pil gets linked with the shared library, plus we cannot use those libraries in his shared form because we will have conflicts with the ones distributed by android os...so no need to build those libraries unless properly versioned as we do with openssl libs * Update png version * Update jpeg and move to mainline Also add a patch that may allow us to build the libraries in his shared form...in case we need them * Rework Pillow - Fix compatibility for new jpeg - add freetype/harfbuzz support - move libraries from LDFLAGS to LIBS - format source code * Rework pil - Fix compatibility for new jpeg - add freetype/harfbuzz support - move libraries from LDFLAGS to LIBS - make it work with python2 and python2legacy * Add cmake reminder to quickstart.rst The recent rework of the jpeg recipe has introduced a new build dependency for us, so we add it to the section `Installing Dependencies` to no forgot about it. * Fix hardcoded url for png We set the last commit published for a version because the author of the github's repo never released/tagged it, despite He performed the necessary changes in master branch and notify about it in the README file...so this way we don't hardcode the url. Note: we should try to move the png repo to mainline because of the issue mentioned above and the fact that the last commit of the repo is more than one year old
1 parent ce0a651 commit e3123f4

File tree

9 files changed

+215
-109
lines changed

9 files changed

+215
-109
lines changed

doc/source/quickstart.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ p4a has several dependencies that must be installed:
6363
- ccache (optional)
6464
- autoconf (for ffpyplayer_codecs recipe)
6565
- libtool (for ffpyplayer_codecs recipe)
66+
- cmake (required for some native code recipes like jpeg's recipe)
6667

6768
On recent versions of Ubuntu and its derivatives you may be able to
6869
install most of these with::

pythonforandroid/recipes/Pillow/__init__.py

Lines changed: 32 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,58 @@
11
from pythonforandroid.recipe import CompiledComponentsPythonRecipe
2-
from pythonforandroid.toolchain import shprint
3-
from os.path import join, dirname
4-
import sh
2+
from os.path import join
53

64

75
class PillowRecipe(CompiledComponentsPythonRecipe):
86

97
version = '5.2.0'
108
url = 'https://github.com/python-pillow/Pillow/archive/{version}.tar.gz'
119
site_packages_name = 'Pillow'
12-
depends = [
13-
'png',
14-
'jpeg',
15-
'freetype',
16-
'setuptools'
17-
]
18-
patches = [
19-
join('patches', 'fix-docstring.patch'),
20-
join('patches', 'fix-setup.patch')
21-
]
10+
depends = ['png', 'jpeg', 'freetype', 'setuptools']
11+
patches = [join('patches', 'fix-docstring.patch'),
12+
join('patches', 'fix-setup.patch')]
2213

2314
call_hostpython_via_targetpython = False
2415

25-
def get_recipe_env(self, arch=None):
26-
env = super(PillowRecipe, self).get_recipe_env(arch)
27-
py_ver = self.ctx.python_recipe.version[0:3]
16+
def get_recipe_env(self, arch=None, with_flags_in_cc=True):
17+
env = super(PillowRecipe, self).get_recipe_env(arch, with_flags_in_cc)
2818

29-
ndk_dir = self.ctx.ndk_platform
30-
ndk_lib_dir = join(ndk_dir, 'usr', 'lib')
31-
ndk_include_dir = (
32-
join(self.ctx.ndk_dir, 'sysroot', 'usr', 'include')
33-
if py_ver == '2.7' else join(ndk_dir, 'usr', 'include'))
19+
env['ANDROID_ROOT'] = join(self.ctx.ndk_platform, 'usr')
20+
ndk_lib_dir = join(self.ctx.ndk_platform, 'usr', 'lib')
21+
ndk_include_dir = join(self.ctx.ndk_dir, 'sysroot', 'usr', 'include')
3422

3523
png = self.get_recipe('png', self.ctx)
3624
png_lib_dir = png.get_lib_dir(arch)
3725
png_jni_dir = png.get_jni_dir(arch)
3826

3927
jpeg = self.get_recipe('jpeg', self.ctx)
40-
jpeg_lib_dir = jpeg.get_lib_dir(arch)
41-
jpeg_jni_dir = jpeg.get_jni_dir(arch)
28+
jpeg_inc_dir = jpeg_lib_dir = jpeg.get_build_dir(arch.arch)
4229

43-
env['JPEG_ROOT'] = '{}|{}'.format(jpeg_lib_dir, jpeg_jni_dir)
30+
freetype = self.get_recipe('freetype', self.ctx)
31+
free_lib_dir = join(freetype.get_build_dir(arch.arch), 'objs', '.libs')
32+
free_inc_dir = join(freetype.get_build_dir(arch.arch), 'include')
33+
34+
# harfbuzz is a direct dependency of freetype and we need the proper
35+
# flags to successfully build the Pillow recipe, so we add them here.
36+
harfbuzz = self.get_recipe('harfbuzz', self.ctx)
37+
harf_lib_dir = join(harfbuzz.get_build_dir(arch.arch), 'src', '.libs')
38+
harf_inc_dir = harfbuzz.get_build_dir(arch.arch)
39+
40+
env['JPEG_ROOT'] = '{}|{}'.format(jpeg_lib_dir, jpeg_inc_dir)
41+
env['FREETYPE_ROOT'] = '{}|{}'.format(free_lib_dir, free_inc_dir)
4442
env['ZLIB_ROOT'] = '{}|{}'.format(ndk_lib_dir, ndk_include_dir)
4543

46-
cflags = ' -nostdinc'
47-
cflags += ' -I{} -L{}'.format(png_jni_dir, png_lib_dir)
48-
cflags += ' -I{} -L{}'.format(jpeg_jni_dir, jpeg_lib_dir)
49-
cflags += ' -I{} -L{}'.format(ndk_include_dir, ndk_lib_dir)
50-
51-
gcc_lib = shprint(
52-
sh.gcc, '-print-libgcc-file-name').stdout.decode('utf-8').split('\n')[0]
53-
gcc_include = join(dirname(gcc_lib), 'include')
54-
cflags += ' -I{}'.format(gcc_include)
55-
56-
if self.ctx.ndk == 'crystax':
57-
py_inc_dir = join(
58-
self.ctx.ndk_dir, 'sources', 'python', py_ver, 'include', 'python')
59-
py_lib_dir = join(
60-
self.ctx.ndk_dir, 'sources', 'python', py_ver, 'libs', arch.arch)
61-
cflags += ' -I{}'.format(py_inc_dir)
62-
env['LDFLAGS'] += ' -L{} -lpython{}m'.format(py_lib_dir, py_ver)
63-
64-
env['LDFLAGS'] += ' {} -L{}'.format(env['CFLAGS'], self.ctx.libs_dir)
44+
cflags = ' -I{}'.format(png_jni_dir)
45+
cflags += ' -I{} -I{}'.format(harf_inc_dir, join(harf_inc_dir, 'src'))
46+
cflags += ' -I{}'.format(free_inc_dir)
47+
cflags += ' -I{}'.format(jpeg_inc_dir)
48+
cflags += ' -I{}'.format(ndk_include_dir)
49+
50+
env['LIBS'] = ' -lpng -lfreetype -lharfbuzz -ljpeg -lturbojpeg'
51+
52+
env['LDFLAGS'] += ' -L{} -L{} -L{} -L{}'.format(
53+
png_lib_dir, harf_lib_dir, jpeg_lib_dir, ndk_lib_dir)
6554
if cflags not in env['CFLAGS']:
6655
env['CFLAGS'] += cflags
67-
env['LDSHARED'] = '{} {}'.format(
68-
env['CC'],
69-
'-pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions')
7056
return env
7157

7258

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
1-
2-
from pythonforandroid.toolchain import Recipe, current_directory, shprint
1+
from pythonforandroid.toolchain import Recipe
2+
from pythonforandroid.util import current_directory
3+
from pythonforandroid.logger import shprint
34
from os.path import exists, join, realpath
45
import sh
56

67

78
class FreetypeRecipe(Recipe):
89

910
version = '2.5.5'
10-
url = 'http://download.savannah.gnu.org/releases/freetype/freetype-{version}.tar.gz'
11+
url = 'http://download.savannah.gnu.org/releases/freetype/freetype-{version}.tar.gz' # noqa
1112

1213
depends = ['harfbuzz']
1314

1415
def should_build(self, arch):
15-
if exists(join(self.get_build_dir(arch.arch), 'objs', '.libs', 'libfreetype.so')):
16+
if exists(join(self.get_build_dir(arch.arch),
17+
'objs', '.libs', 'libfreetype.a')):
1618
return False
1719
return True
1820

@@ -22,17 +24,21 @@ def build_arch(self, arch):
2224
harfbuzz_recipe = Recipe.get_recipe('harfbuzz', self.ctx)
2325
env['LDFLAGS'] = ' '.join(
2426
[env['LDFLAGS'],
25-
'-L{}'.format(join(harfbuzz_recipe.get_build_dir(arch.arch), 'src', '.libs'))])
27+
'-L{}'.format(join(harfbuzz_recipe.get_build_dir(arch.arch),
28+
'src', '.libs'))])
2629

2730
with current_directory(self.get_build_dir(arch.arch)):
2831
configure = sh.Command('./configure')
29-
shprint(configure, '--host=arm-linux-androideabi',
32+
shprint(configure,
33+
'--host=arm-linux-androideabi',
3034
'--prefix={}'.format(realpath('.')),
31-
'--without-zlib', '--with-png=no', '--enable-shared',
35+
'--without-zlib',
36+
'--with-png=no',
37+
'--disable-shared',
3238
_env=env)
3339
shprint(sh.make, '-j5', _env=env)
3440

35-
shprint(sh.cp, 'objs/.libs/libfreetype.so', self.ctx.libs_dir)
41+
shprint(sh.cp, 'objs/.libs/libfreetype.a', self.ctx.libs_dir)
3642

3743

3844
recipe = FreetypeRecipe()
Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
2-
from pythonforandroid.toolchain import Recipe, current_directory, shprint
1+
from pythonforandroid.toolchain import Recipe
2+
from pythonforandroid.util import current_directory
3+
from pythonforandroid.logger import shprint
34
from os.path import exists, join
45
import sh
56

67

78
class HarfbuzzRecipe(Recipe):
89
version = '0.9.40'
9-
url = 'http://www.freedesktop.org/software/harfbuzz/release/harfbuzz-{version}.tar.bz2'
10+
url = 'http://www.freedesktop.org/software/harfbuzz/release/harfbuzz-{version}.tar.bz2' # noqa
1011

1112
def should_build(self, arch):
12-
if exists(join(self.get_build_dir(arch.arch), 'src', '.libs', 'libharfbuzz.so')):
13+
if exists(join(self.get_build_dir(arch.arch),
14+
'src', '.libs', 'libharfbuzz.a')):
1315
return False
1416
return True
1517

@@ -22,11 +24,16 @@ def build_arch(self, arch):
2224
with current_directory(self.get_build_dir(arch.arch)):
2325
configure = sh.Command('./configure')
2426
shprint(configure, '--without-icu', '--host=arm-linux=androideabi',
25-
'--prefix={}'.format(join(self.ctx.build_dir, 'python-install')),
26-
'--without-freetype', '--without-glib', _env=env)
27+
'--prefix={}'.format(
28+
join(self.ctx.build_dir, 'python-install')),
29+
'--without-freetype',
30+
'--without-glib',
31+
'--disable-shared',
32+
_env=env)
2733
shprint(sh.make, '-j5', _env=env)
2834

29-
shprint(sh.cp, '-L', join('src', '.libs', 'libharfbuzz.so'), self.ctx.libs_dir)
35+
shprint(sh.cp, '-L', join('src', '.libs', 'libharfbuzz.a'),
36+
self.ctx.libs_dir)
3037

3138

3239
recipe = HarfbuzzRecipe()
Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,78 @@
1-
from pythonforandroid.recipe import NDKRecipe
1+
from pythonforandroid.recipe import Recipe
22
from pythonforandroid.logger import shprint
33
from pythonforandroid.util import current_directory
44
from os.path import join, exists
5+
from os import environ, uname
6+
from glob import glob
57
import sh
68

79

8-
class JpegRecipe(NDKRecipe):
10+
class JpegRecipe(Recipe):
11+
'''
12+
.. versionchanged:: 0.6.0
13+
rewrote recipe to be build with clang and updated libraries to latest
14+
version of the official git repo.
15+
'''
916
name = 'jpeg'
10-
version = 'linaro-android'
11-
url = 'git+https://git.linaro.org/people/tomgall/libjpeg-turbo/libjpeg-turbo'
17+
version = '2.0.1'
18+
url = 'https://github.com/libjpeg-turbo/libjpeg-turbo/archive/{version}.tar.gz' # noqa
19+
# we will require this below patch to build the shared library
20+
# patches = ['remove-version.patch']
1221

13-
patches = ['build-static.patch']
22+
def should_build(self, arch):
23+
return not exists(join(self.get_build_dir(arch.arch),
24+
'libturbojpeg.a'))
1425

15-
generated_libraries = ['libjpeg.a']
26+
def build_arch(self, arch):
27+
super(JpegRecipe, self).build_arch(arch)
28+
build_dir = self.get_build_dir(arch.arch)
1629

17-
def prebuild_arch(self, arch):
18-
super(JpegRecipe, self).prebuild_arch(arch)
30+
# TODO: Fix simd/neon
31+
with current_directory(build_dir):
32+
env = self.get_recipe_env(arch)
33+
toolchain_file = join(self.ctx.ndk_dir,
34+
'build/cmake/android.toolchain.cmake')
1935

20-
build_dir = self.get_build_dir(arch.arch)
21-
app_mk = join(build_dir, 'Application.mk')
22-
if not exists(app_mk):
23-
shprint(sh.cp, join(self.get_recipe_dir(), 'Application.mk'), app_mk)
24-
jni_ln = join(build_dir, 'jni')
25-
if not exists(jni_ln):
26-
shprint(sh.ln, '-s', build_dir, jni_ln)
36+
shprint(sh.rm, '-f', 'CMakeCache.txt', 'CMakeFiles/')
37+
shprint(sh.cmake, '-G', 'Unix Makefiles',
38+
'-DCMAKE_SYSTEM_NAME=Android',
39+
'-DCMAKE_SYSTEM_PROCESSOR={cpu}'.format(cpu='arm'),
40+
'-DCMAKE_POSITION_INDEPENDENT_CODE=1',
41+
'-DCMAKE_ANDROID_ARCH_ABI={arch}'.format(arch=arch.arch),
42+
'-DCMAKE_ANDROID_NDK=' + self.ctx.ndk_dir,
43+
'-DCMAKE_C_COMPILER={toolchain}/bin/clang'.format(
44+
toolchain=env['TOOLCHAIN']),
45+
'-DCMAKE_CXX_COMPILER={toolchain}/bin/clang++'.format(
46+
toolchain=env['TOOLCHAIN']),
47+
'-DCMAKE_BUILD_TYPE=Release',
48+
'-DCMAKE_INSTALL_PREFIX=./install',
49+
'-DCMAKE_TOOLCHAIN_FILE=' + toolchain_file,
2750

28-
def build_arch(self, arch):
29-
super(JpegRecipe, self).build_arch(arch)
30-
with current_directory(self.get_lib_dir(arch)):
31-
shprint(sh.mv, 'libjpeg.a', 'libjpeg-orig.a')
32-
shprint(sh.ar, '-rcT', 'libjpeg.a', 'libjpeg-orig.a', 'libsimd.a')
51+
'-DANDROID_ABI={arch}'.format(arch=arch.arch),
52+
'-DANDROID_ARM_NEON=ON',
53+
'-DENABLE_NEON=ON',
54+
# '-DREQUIRE_SIMD=1',
55+
56+
# Force disable shared, with the static ones is enough
57+
'-DENABLE_SHARED=0',
58+
'-DENABLE_STATIC=1',
59+
_env=env)
60+
shprint(sh.make, _env=env)
61+
62+
# copy static libs to libs collection
63+
for lib in glob(join(build_dir, '*.a')):
64+
shprint(sh.cp, '-L', lib, self.ctx.libs_dir)
65+
66+
def get_recipe_env(self, arch=None, with_flags_in_cc=False, clang=True):
67+
env = environ.copy()
68+
69+
build_platform = '{system}-{machine}'.format(
70+
system=uname()[0], machine=uname()[-1]).lower()
71+
env['TOOLCHAIN'] = join(self.ctx.ndk_dir, 'toolchains/llvm/'
72+
'prebuilt/{build_platform}'.format(
73+
build_platform=build_platform))
74+
75+
return env
3376

3477

3578
recipe = JpegRecipe()
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--- jpeg/CMakeLists.txt.orig 2018-11-12 20:20:28.000000000 +0100
2+
+++ jpeg/CMakeLists.txt 2018-12-14 12:43:45.338704504 +0100
3+
@@ -573,6 +573,9 @@
4+
add_library(turbojpeg SHARED ${TURBOJPEG_SOURCES})
5+
set_property(TARGET turbojpeg PROPERTY COMPILE_FLAGS
6+
"-DBMP_SUPPORTED -DPPM_SUPPORTED")
7+
+ set_property(TARGET jpeg PROPERTY NO_SONAME 1)
8+
+ set_property(TARGET turbojpeg PROPERTY NO_SONAME 1)
9+
+ set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "")
10+
if(WIN32)
11+
set_target_properties(turbojpeg PROPERTIES DEFINE_SYMBOL DLLDEFINE)
12+
endif()

0 commit comments

Comments
 (0)