Skip to content

Commit

Permalink
[libraries] Rework of freetype/harfbuzz recipes
Browse files Browse the repository at this point in the history
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
  • Loading branch information
opacam committed May 26, 2019
1 parent 00bd9d5 commit d2b88f7
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 38 deletions.
1 change: 1 addition & 0 deletions Dockerfile.py2
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ RUN dpkg --add-architecture i386 \
# specific recipes dependencies (e.g. libffi requires autoreconf binary)
RUN ${RETRY} apt -y install -qq --no-install-recommends \
libffi-dev autoconf automake cmake gettext libltdl-dev libtool pkg-config \
libfreetype6-dev \
&& apt -y autoremove \
&& apt -y clean

Expand Down
1 change: 1 addition & 0 deletions Dockerfile.py3
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ RUN dpkg --add-architecture i386 \
# specific recipes dependencies (e.g. libffi requires autoreconf binary)
RUN ${RETRY} apt -y install -qq --no-install-recommends \
libffi-dev autoconf automake cmake gettext libltdl-dev libtool pkg-config \
libfreetype6-dev \
&& apt -y autoremove \
&& apt -y clean

Expand Down
118 changes: 96 additions & 22 deletions pythonforandroid/recipes/freetype/__init__.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,118 @@
from pythonforandroid.toolchain import Recipe
from pythonforandroid.logger import shprint, info
from pythonforandroid.util import current_directory
from pythonforandroid.logger import shprint
from os.path import exists, join, realpath
from os.path import exists, join
from multiprocessing import cpu_count
import sh


class FreetypeRecipe(Recipe):
"""The freetype library it's special, because has cyclic dependencies with
harfbuzz library, so freetype can be build with harfbuzz support, and
harfbuzz can be build with freetype support. This complicates the build of
both recipes because in order to get the full set we need to compile those
recipes several times:
- build freetype without harfbuzz
- build harfbuzz with freetype
- build freetype with harfbuzz support
.. note::
To build freetype with harfbuzz support you must add `harfbuzz` to your
requirements, otherwise freetype will be build without harfbuzz
.. seealso::
https://sourceforge.net/projects/freetype/files/freetype2/2.5.3/
"""

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

depends = ['harfbuzz']

def should_build(self, arch):
if exists(join(self.get_build_dir(arch.arch),
'objs', '.libs', 'libfreetype.a')):
if exists(
join(
self.get_build_dir(arch.arch),
'objs',
'.libs',
'libfreetype.so',
)
):
return False
return True

def build_arch(self, arch):
def build_arch(self, arch, with_harfbuzz=False):
env = self.get_recipe_env(arch)
harfbuzz_in_recipes = 'harfbuzz' in self.ctx.recipe_build_order
prefix_path = self.get_build_dir(arch.arch)
if not harfbuzz_in_recipes:
info('Building freetype (harfbuzz support disabled)')
elif harfbuzz_in_recipes and not with_harfbuzz:
info('First Build of freetype (without harfbuzz, for now...)')
prefix_path = join(prefix_path, 'install')
elif harfbuzz_in_recipes and with_harfbuzz:
# Is the second build, now we link with harfbuzz
info('Second Build of freetype: enabling harfbuzz support ...')
harfbuzz_build = self.get_recipe(
'harfbuzz', self.ctx
).get_build_dir(arch.arch)
freetype_install = join(self.get_build_dir(arch.arch), 'install')
env['CFLAGS'] = ' '.join(
[
env['CFLAGS'],
'-DFT_CONFIG_OPTION_USE_HARFBUZZ',
'-I{harfbuzz}'.format(harfbuzz=harfbuzz_build),
'-I{harfbuzz}/src'.format(harfbuzz=harfbuzz_build),
'-I{freetype}/include/freetype2'.format(
freetype=freetype_install
),
]
)

harfbuzz_recipe = Recipe.get_recipe('harfbuzz', self.ctx)
env['LDFLAGS'] = ' '.join(
[env['LDFLAGS'],
'-L{}'.format(join(harfbuzz_recipe.get_build_dir(arch.arch),
'src', '.libs'))])
env['HARFBUZZ_CFLAGS'] = '-I{harfbuzz} -I{harfbuzz}/src'.format(
harfbuzz=harfbuzz_build
)
env['HARFBUZZ_LIBS'] = (
'-L{freetype}/lib -lfreetype '
'-L{harfbuzz}/src/.libs -lharfbuzz'.format(
freetype=freetype_install, harfbuzz=harfbuzz_build
)
)

# Build freetype library
config_args = {
'--host={}'.format(arch.command_prefix),
'--prefix={}'.format(prefix_path),
'--without-zlib',
'--with-png=no',
}
if not with_harfbuzz and harfbuzz_in_recipes:
info('Build freetype for First time (without harfbuzz)')
config_args = config_args.union({'--disable-shared'})
elif with_harfbuzz or not harfbuzz_in_recipes:
info(
'Build freetype {}'.format(
'for Second time (with harfbuzz)'
if harfbuzz_in_recipes
else '(without harfbuzz)'
)
)
config_args = config_args.union(
{'--disable-static', '--enable-shared'}
)
info('Configure args are: {}'.format('\n\t-'.join(config_args)))
with current_directory(self.get_build_dir(arch.arch)):
configure = sh.Command('./configure')
shprint(configure,
'--host=arm-linux-androideabi',
'--prefix={}'.format(realpath('.')),
'--without-zlib',
'--with-png=no',
'--disable-shared',
_env=env)
shprint(sh.make, '-j5', _env=env)

shprint(sh.cp, 'objs/.libs/libfreetype.a', self.ctx.libs_dir)
shprint(configure, *config_args, _env=env)
shprint(sh.make, '-j', str(cpu_count()), _env=env)

if not with_harfbuzz and harfbuzz_in_recipes:
# First build, install the compiled lib, and clean build env
shprint(sh.make, 'install', _env=env)
shprint(sh.make, 'distclean', _env=env)
else:
# Second build (or the first if harfbuzz not enabled), now we
# copy definitive libs to libs collection. Be sure to link your
# recipes to the definitive library, located at: objs/.libs
self.install_libs(arch, 'objs/.libs/libfreetype.so')


recipe = FreetypeRecipe()
82 changes: 66 additions & 16 deletions pythonforandroid/recipes/harfbuzz/__init__.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,89 @@
from pythonforandroid.toolchain import Recipe
from pythonforandroid.util import current_directory
from pythonforandroid.logger import shprint
from multiprocessing import cpu_count
from os.path import exists, join
import sh


class HarfbuzzRecipe(Recipe):
"""The harfbuzz library it's special, because has cyclic dependencies with
freetype library, so freetype can be build with harfbuzz support, and
harfbuzz can be build with freetype support. This complicates the build of
both recipes because in order to get the full set we need to compile those
recipes several times:
- build freetype without harfbuzz
- build harfbuzz with freetype
- build freetype with harfbuzz support
.. seealso::
https://sourceforge.net/projects/freetype/files/freetype2/2.5.3/
"""
version = '0.9.40'
url = 'http://www.freedesktop.org/software/harfbuzz/release/harfbuzz-{version}.tar.bz2' # noqa
depends = ['freetype']

def should_build(self, arch):
if exists(join(self.get_build_dir(arch.arch),
'src', '.libs', 'libharfbuzz.a')):
if exists(
join(
self.get_build_dir(arch.arch), 'src', '.libs', 'libharfbuzz.so'
)
):
return False
return True

def build_arch(self, arch):

env = self.get_recipe_env(arch)
env['LDFLAGS'] = env['LDFLAGS'] + ' -L{}'.format(
self.ctx.get_libs_dir(arch.arch) +
'-L{}'.format(self.ctx.libs_dir))
env['LDFLAGS'] += ' -L{} -L{}'.format(
self.ctx.get_libs_dir(arch.arch), self.ctx.libs_dir
)

with_freetype = 'no'
# freetype flags
if 'freetype' in self.ctx.recipe_build_order:
with_freetype = 'yes'
freetype = self.get_recipe('freetype', self.ctx)
freetype_install = join(
freetype.get_build_dir(arch.arch), 'install'
)
env['CFLAGS'] = ' '.join(
[
env['CFLAGS'],
'-I{}/include/freetype2'.format(freetype_install),
'-L{}/lib'.format(freetype_install),
'-lfreetype',
]
)
# harfbuzz flags
env['CFLAGS'] = ' '.join(
[
env['CFLAGS'],
'-I{}'.format(self.get_build_dir(arch.arch)),
'-I{}/src'.format(self.get_build_dir(arch.arch)),
]
)
env['LDFLAGS'] += ' -L{}/src/.libs'.format(
self.get_build_dir(arch.arch)
)

with current_directory(self.get_build_dir(arch.arch)):
configure = sh.Command('./configure')
shprint(configure, '--without-icu', '--host=arm-linux=androideabi',
'--prefix={}'.format(
join(self.ctx.build_dir, 'python-install')),
'--without-freetype',
'--without-glib',
'--disable-shared',
_env=env)
shprint(sh.make, '-j5', _env=env)

shprint(sh.cp, '-L', join('src', '.libs', 'libharfbuzz.a'),
self.ctx.libs_dir)
shprint(
configure,
'--without-icu',
'--host={}'.format(arch.command_prefix),
'--prefix={}'.format(self.get_build_dir(arch.arch)),
'--with-freetype={}'.format(with_freetype),
'--without-glib',
_env=env,
)
shprint(sh.make, '-j', str(cpu_count()), _env=env)
self.install_libs(arch, join('src', '.libs', 'libharfbuzz.so'))

if 'freetype' in self.ctx.recipe_build_order:
# Rebuild freetype with harfbuzz support
freetype.build_arch(arch, with_harfbuzz=True)


recipe = HarfbuzzRecipe()

0 comments on commit d2b88f7

Please sign in to comment.