Skip to content

Commit 80fe311

Browse files
authored
Merge pull request #1825 from opacam/freetype-harfbuzz-cyclic
Rework of freetype/harfbuzz recipes
2 parents 00bd9d5 + 5691837 commit 80fe311

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)