Skip to content

Commit 99be9b2

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 (whe we build multiple recipes that depends on those libraries) Note: Add `libfreetype6-dev` to docker dependencies or we will be unable to build freetype in travis tests
1 parent 00bd9d5 commit 99be9b2

File tree

4 files changed

+165
-42
lines changed

4 files changed

+165
-42
lines changed

Dockerfile.py2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ RUN dpkg --add-architecture i386 \
112112
# specific recipes dependencies (e.g. libffi requires autoreconf binary)
113113
RUN ${RETRY} apt -y install -qq --no-install-recommends \
114114
libffi-dev autoconf automake cmake gettext libltdl-dev libtool pkg-config \
115+
libfreetype6-dev \
115116
&& apt -y autoremove \
116117
&& apt -y clean
117118

Dockerfile.py3

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ RUN dpkg --add-architecture i386 \
113113
# specific recipes dependencies (e.g. libffi requires autoreconf binary)
114114
RUN ${RETRY} apt -y install -qq --no-install-recommends \
115115
libffi-dev autoconf automake cmake gettext libltdl-dev libtool pkg-config \
116+
libfreetype6-dev \
116117
&& apt -y autoremove \
117118
&& apt -y clean
118119

Lines changed: 96 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,116 @@
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+
)
2039

21-
def build_arch(self, arch):
40+
def build_arch(self, arch, with_harfbuzz=False):
2241
env = self.get_recipe_env(arch)
42+
harfbuzz_in_recipes = 'harfbuzz' in self.ctx.recipe_build_order
43+
prefix_path = self.get_build_dir(arch.arch)
44+
if not harfbuzz_in_recipes:
45+
info('Building freetype (harfbuzz support disabled)')
46+
elif harfbuzz_in_recipes and not with_harfbuzz:
47+
info('First Build of freetype (without harfbuzz, for now...)')
48+
prefix_path = join(prefix_path, 'install')
49+
elif harfbuzz_in_recipes and with_harfbuzz:
50+
# Is the second build, now we link with harfbuzz
51+
info('Second Build of freetype: enabling harfbuzz support ...')
52+
harfbuzz_build = self.get_recipe(
53+
'harfbuzz', self.ctx
54+
).get_build_dir(arch.arch)
55+
freetype_install = join(self.get_build_dir(arch.arch), 'install')
56+
env['CFLAGS'] = ' '.join(
57+
[
58+
env['CFLAGS'],
59+
'-DFT_CONFIG_OPTION_USE_HARFBUZZ',
60+
'-I{harfbuzz}'.format(harfbuzz=harfbuzz_build),
61+
'-I{harfbuzz}/src'.format(harfbuzz=harfbuzz_build),
62+
'-I{freetype}/include/freetype2'.format(
63+
freetype=freetype_install
64+
),
65+
]
66+
)
2367

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'))])
68+
env['HARFBUZZ_CFLAGS'] = '-I{harfbuzz} -I{harfbuzz}/src'.format(
69+
harfbuzz=harfbuzz_build
70+
)
71+
env['HARFBUZZ_LIBS'] = (
72+
'-L{freetype}/lib -lfreetype '
73+
'-L{harfbuzz}/src/.libs -lharfbuzz'.format(
74+
freetype=freetype_install, harfbuzz=harfbuzz_build
75+
)
76+
)
2977

78+
# Build freetype library
79+
config_args = {
80+
'--host={}'.format(arch.command_prefix),
81+
'--prefix={}'.format(prefix_path),
82+
'--without-zlib',
83+
'--with-png=no',
84+
}
85+
if not with_harfbuzz and harfbuzz_in_recipes:
86+
info('Build freetype for First time (without harfbuzz)')
87+
config_args = config_args.union({'--disable-shared'})
88+
elif with_harfbuzz or not harfbuzz_in_recipes:
89+
info(
90+
'Build freetype {}'.format(
91+
'for Second time (with harfbuzz)'
92+
if harfbuzz_in_recipes
93+
else '(without harfbuzz)'
94+
)
95+
)
96+
config_args = config_args.union(
97+
{'--disable-static', '--enable-shared'}
98+
)
99+
info('Configure args are: {}'.format('\n\t-'.join(config_args)))
30100
with current_directory(self.get_build_dir(arch.arch)):
31101
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)
102+
shprint(configure, *config_args, _env=env)
103+
shprint(sh.make, '-j', str(cpu_count()), _env=env)
104+
105+
if not with_harfbuzz and harfbuzz_in_recipes:
106+
# First build, install the compiled lib, and clean build env
107+
shprint(sh.make, 'install', _env=env)
108+
shprint(sh.make, 'distclean', _env=env)
109+
else:
110+
# Second build (or the first if harfbuzz not enabled), now we
111+
# copy definitive libs to libs collection. Be sure to link your
112+
# recipes to the definitive library, located at: objs/.libs
113+
self.install_libs(arch, 'objs/.libs/libfreetype.so')
42114

43115

44116
recipe = FreetypeRecipe()
Lines changed: 67 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,88 @@
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+
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+
)
1733

1834
def build_arch(self, arch):
1935

2036
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))
37+
env['LDFLAGS'] += ' -L{} -L{}'.format(
38+
self.ctx.get_libs_dir(arch.arch), self.ctx.libs_dir
39+
)
40+
41+
with_freetype = 'no'
42+
# freetype flags
43+
if 'freetype' in self.ctx.recipe_build_order:
44+
with_freetype = 'yes'
45+
freetype = self.get_recipe('freetype', self.ctx)
46+
freetype_install = join(
47+
freetype.get_build_dir(arch.arch), 'install'
48+
)
49+
env['CFLAGS'] = ' '.join(
50+
[
51+
env['CFLAGS'],
52+
'-I{}/include/freetype2'.format(freetype_install),
53+
'-L{}/lib'.format(freetype_install),
54+
'-lfreetype',
55+
]
56+
)
57+
# harfbuzz flags
58+
env['CFLAGS'] = ' '.join(
59+
[
60+
env['CFLAGS'],
61+
'-I{}'.format(self.get_build_dir(arch.arch)),
62+
'-I{}/src'.format(self.get_build_dir(arch.arch)),
63+
]
64+
)
65+
env['LDFLAGS'] += ' -L{}/src/.libs'.format(
66+
self.get_build_dir(arch.arch)
67+
)
68+
2469
with current_directory(self.get_build_dir(arch.arch)):
2570
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)
71+
shprint(
72+
configure,
73+
'--without-icu',
74+
'--host={}'.format(arch.command_prefix),
75+
'--prefix={}'.format(self.get_build_dir(arch.arch)),
76+
'--with-freetype={}'.format(with_freetype),
77+
'--without-glib',
78+
_env=env,
79+
)
80+
shprint(sh.make, '-j', str(cpu_count()), _env=env)
81+
self.install_libs(arch, join('src', '.libs', 'libharfbuzz.so'))
82+
83+
if 'freetype' in self.ctx.recipe_build_order:
84+
# Rebuild freetype with harfbuzz support
85+
freetype.build_arch(arch, with_harfbuzz=True)
3786

3887

3988
recipe = HarfbuzzRecipe()

0 commit comments

Comments
 (0)