Skip to content

Commit 5691837

Browse files
committed
[libraries] Rework of freetype/harfbuzz recipes
To fix cyclic dependency between freetype and harfbuzz and to produce shared libraries, because we use those libraries in multiple recipes and building those libraries as shared libraries can reduce a little the apk size in some circumstances (when we build multiple recipes that depends on those libraries)
1 parent 00bd9d5 commit 5691837

File tree

2 files changed

+159
-43
lines changed

2 files changed

+159
-43
lines changed
Lines changed: 101 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,120 @@
11
from pythonforandroid.toolchain import Recipe
2+
from pythonforandroid.logger import shprint, info
23
from pythonforandroid.util import current_directory
3-
from pythonforandroid.logger import shprint
4-
from os.path import exists, join, realpath
4+
from os.path import exists, join
5+
from multiprocessing import cpu_count
56
import sh
67

78

89
class FreetypeRecipe(Recipe):
10+
"""The freetype library it's special, because has cyclic dependencies with
11+
harfbuzz library, so freetype can be build with harfbuzz support, and
12+
harfbuzz can be build with freetype support. This complicates the build of
13+
both recipes because in order to get the full set we need to compile those
14+
recipes several times:
15+
- build freetype without harfbuzz
16+
- build harfbuzz with freetype
17+
- build freetype with harfbuzz support
18+
19+
.. note::
20+
To build freetype with harfbuzz support you must add `harfbuzz` to your
21+
requirements, otherwise freetype will be build without harfbuzz
22+
23+
.. seealso::
24+
https://sourceforge.net/projects/freetype/files/freetype2/2.5.3/
25+
"""
926

1027
version = '2.5.5'
1128
url = 'http://download.savannah.gnu.org/releases/freetype/freetype-{version}.tar.gz' # noqa
1229

13-
depends = ['harfbuzz']
14-
1530
def should_build(self, arch):
16-
if exists(join(self.get_build_dir(arch.arch),
17-
'objs', '.libs', 'libfreetype.a')):
18-
return False
19-
return True
31+
return not exists(
32+
join(
33+
self.get_build_dir(arch.arch),
34+
'objs',
35+
'.libs',
36+
'libfreetype.so',
37+
)
38+
)
39+
40+
def get_recipe_env(self, arch=None, with_harfbuzz=False):
41+
env = super(FreetypeRecipe, self).get_recipe_env(arch)
42+
if with_harfbuzz:
43+
harfbuzz_build = self.get_recipe(
44+
'harfbuzz', self.ctx
45+
).get_build_dir(arch.arch)
46+
freetype_install = join(self.get_build_dir(arch.arch), 'install')
47+
env['CFLAGS'] = ' '.join(
48+
[env['CFLAGS'], '-DFT_CONFIG_OPTION_USE_HARFBUZZ']
49+
)
2050

21-
def build_arch(self, arch):
22-
env = self.get_recipe_env(arch)
51+
env['HARFBUZZ_CFLAGS'] = '-I{harfbuzz} -I{harfbuzz}/src'.format(
52+
harfbuzz=harfbuzz_build
53+
)
54+
env['HARFBUZZ_LIBS'] = (
55+
'-L{freetype}/lib -lfreetype '
56+
'-L{harfbuzz}/src/.libs -lharfbuzz'.format(
57+
freetype=freetype_install, harfbuzz=harfbuzz_build
58+
)
59+
)
60+
return env
2361

24-
harfbuzz_recipe = Recipe.get_recipe('harfbuzz', self.ctx)
25-
env['LDFLAGS'] = ' '.join(
26-
[env['LDFLAGS'],
27-
'-L{}'.format(join(harfbuzz_recipe.get_build_dir(arch.arch),
28-
'src', '.libs'))])
62+
def build_arch(self, arch, with_harfbuzz=False):
63+
env = self.get_recipe_env(arch, with_harfbuzz=with_harfbuzz)
2964

65+
harfbuzz_in_recipes = 'harfbuzz' in self.ctx.recipe_build_order
66+
prefix_path = self.get_build_dir(arch.arch)
67+
if harfbuzz_in_recipes and not with_harfbuzz:
68+
# This is the first time we build freetype and we modify `prefix`,
69+
# because we will install the compiled library so later we can
70+
# build harfbuzz (with freetype support) using this freetype
71+
# installation
72+
prefix_path = join(prefix_path, 'install')
73+
74+
# Configure freetype library
75+
config_args = {
76+
'--host={}'.format(arch.command_prefix),
77+
'--prefix={}'.format(prefix_path),
78+
'--without-zlib',
79+
'--with-png=no',
80+
}
81+
if not harfbuzz_in_recipes:
82+
info('Build freetype (without harfbuzz)')
83+
config_args = config_args.union(
84+
{'--disable-static', '--enable-shared', '--with-harfbuzz=no'}
85+
)
86+
elif not with_harfbuzz:
87+
info('Build freetype for First time (without harfbuzz)')
88+
# This time we will build our freetype library as static because we
89+
# want that the harfbuzz library to have the necessary freetype
90+
# symbols/functions, so we avoid to have two freetype shared
91+
# libraries which will be confusing and harder to link with them
92+
config_args = config_args.union(
93+
{'--disable-shared', '--with-harfbuzz=no'}
94+
)
95+
else:
96+
info('Build freetype for Second time (with harfbuzz)')
97+
config_args = config_args.union(
98+
{'--disable-static', '--enable-shared', '--with-harfbuzz=yes'}
99+
)
100+
info('Configure args are:\n\t-{}'.format('\n\t-'.join(config_args)))
101+
102+
# Build freetype library
30103
with current_directory(self.get_build_dir(arch.arch)):
31104
configure = sh.Command('./configure')
32-
shprint(configure,
33-
'--host=arm-linux-androideabi',
34-
'--prefix={}'.format(realpath('.')),
35-
'--without-zlib',
36-
'--with-png=no',
37-
'--disable-shared',
38-
_env=env)
39-
shprint(sh.make, '-j5', _env=env)
40-
41-
shprint(sh.cp, 'objs/.libs/libfreetype.a', self.ctx.libs_dir)
105+
shprint(configure, *config_args, _env=env)
106+
shprint(sh.make, '-j', str(cpu_count()), _env=env)
107+
108+
if not with_harfbuzz and harfbuzz_in_recipes:
109+
info('Installing freetype (first time build without harfbuzz)')
110+
# First build, install the compiled lib, and clean build env
111+
shprint(sh.make, 'install', _env=env)
112+
shprint(sh.make, 'distclean', _env=env)
113+
else:
114+
# Second build (or the first if harfbuzz not enabled), now we
115+
# copy definitive libs to libs collection. Be sure to link your
116+
# recipes to the definitive library, located at: objs/.libs
117+
self.install_libs(arch, 'objs/.libs/libfreetype.so')
42118

43119

44120
recipe = FreetypeRecipe()
Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,79 @@
11
from pythonforandroid.toolchain import Recipe
22
from pythonforandroid.util import current_directory
33
from pythonforandroid.logger import shprint
4+
from multiprocessing import cpu_count
45
from os.path import exists, join
56
import sh
67

78

89
class HarfbuzzRecipe(Recipe):
10+
"""The harfbuzz library it's special, because has cyclic dependencies with
11+
freetype library, so freetype can be build with harfbuzz support, and
12+
harfbuzz can be build with freetype support. This complicates the build of
13+
both recipes because in order to get the full set we need to compile those
14+
recipes several times:
15+
- build freetype without harfbuzz
16+
- build harfbuzz with freetype
17+
- build freetype with harfbuzz support
18+
19+
.. seealso::
20+
https://sourceforge.net/projects/freetype/files/freetype2/2.5.3/
21+
"""
22+
923
version = '0.9.40'
1024
url = 'http://www.freedesktop.org/software/harfbuzz/release/harfbuzz-{version}.tar.bz2' # noqa
25+
opt_depends = ['freetype']
1126

1227
def should_build(self, arch):
13-
if exists(join(self.get_build_dir(arch.arch),
14-
'src', '.libs', 'libharfbuzz.a')):
15-
return False
16-
return True
28+
return not exists(
29+
join(
30+
self.get_build_dir(arch.arch), 'src', '.libs', 'libharfbuzz.so'
31+
)
32+
)
33+
34+
def get_recipe_env(self, arch=None):
35+
env = super(HarfbuzzRecipe, self).get_recipe_env(arch)
36+
if 'freetype' in self.ctx.recipe_build_order:
37+
freetype = self.get_recipe('freetype', self.ctx)
38+
freetype_install = join(
39+
freetype.get_build_dir(arch.arch), 'install'
40+
)
41+
# Explicitly tell harfbuzz's configure script that we want to
42+
# use our freetype library or it won't be correctly detected
43+
env['FREETYPE_CFLAGS'] = '-I{}/include/freetype2'.format(
44+
freetype_install
45+
)
46+
env['FREETYPE_LIBS'] = ' '.join(
47+
['-L{}/lib'.format(freetype_install), '-lfreetype']
48+
)
49+
return env
1750

1851
def build_arch(self, arch):
1952

2053
env = self.get_recipe_env(arch)
21-
env['LDFLAGS'] = env['LDFLAGS'] + ' -L{}'.format(
22-
self.ctx.get_libs_dir(arch.arch) +
23-
'-L{}'.format(self.ctx.libs_dir))
54+
2455
with current_directory(self.get_build_dir(arch.arch)):
2556
configure = sh.Command('./configure')
26-
shprint(configure, '--without-icu', '--host=arm-linux=androideabi',
27-
'--prefix={}'.format(
28-
join(self.ctx.build_dir, 'python-install')),
29-
'--without-freetype',
30-
'--without-glib',
31-
'--disable-shared',
32-
_env=env)
33-
shprint(sh.make, '-j5', _env=env)
34-
35-
shprint(sh.cp, '-L', join('src', '.libs', 'libharfbuzz.a'),
36-
self.ctx.libs_dir)
57+
shprint(
58+
configure,
59+
'--without-icu',
60+
'--host={}'.format(arch.command_prefix),
61+
'--prefix={}'.format(self.get_build_dir(arch.arch)),
62+
'--with-freetype={}'.format(
63+
'yes'
64+
if 'freetype' in self.ctx.recipe_build_order
65+
else 'no'
66+
),
67+
'--without-glib',
68+
_env=env,
69+
)
70+
shprint(sh.make, '-j', str(cpu_count()), _env=env)
71+
self.install_libs(arch, join('src', '.libs', 'libharfbuzz.so'))
72+
73+
if 'freetype' in self.ctx.recipe_build_order:
74+
# Rebuild freetype with harfbuzz support
75+
freetype = self.get_recipe('freetype', self.ctx)
76+
freetype.build_arch(arch, with_harfbuzz=True)
3777

3878

3979
recipe = HarfbuzzRecipe()

0 commit comments

Comments
 (0)