1#
2# Meson project file for FreeType 2
3#
4
5# Copyright (C) 2020 by
6# David Turner, Robert Wilhelm, and Werner Lemberg.
7#
8# This file is part of the FreeType project, and may only be used, modified,
9# and distributed under the terms of the FreeType project license,
10# LICENSE.TXT.  By continuing to use, modify, or distribute this file you
11# indicate that you have read the license and understand and accept it
12# fully.
13
14
15project('freetype2', 'c',
16  meson_version: '>= 0.55.0',
17  default_options: ['default_library=both'],
18)
19
20#
21# Rules to compile the FreeType 2 library itself
22#
23
24
25# Apparently meson doesn't provide a read_file() function, so instead
26# running an external command is required.
27
28python = import('python')
29python_exe = python.find_installation(required: true)
30
31ft2_version = run_command(python_exe,
32  files('builds/meson/extract_freetype_version.py'),
33  files('include/freetype/freetype.h')).stdout().strip()
34
35ft2_libtool_version = run_command(python_exe,
36  files('builds/meson/extract_libtool_version.py'),
37  '--soversion',
38  files('builds/unix/configure.raw')).stdout().strip()
39
40ft2_includes = include_directories('include')
41
42
43# Generate a custom `ftmodule.h` version based on the content of
44# `modules.cfg`.
45
46ftmodule_h = custom_target('ftmodule.h',
47  output: 'ftmodule.h',
48  input: 'modules.cfg',
49  command: [python_exe, files('builds/meson/parse_modules_cfg.py'),
50            '--format=ftmodule.h', '@INPUT@', '--output', '@OUTPUT@'],
51  install: true,
52  install_dir: 'include/freetype2/freetype/config',
53)
54ft2_sources = [ftmodule_h]
55
56
57# FreeType 2 modules.
58
59ft_main_modules = run_command(python_exe,
60  files('builds/meson/parse_modules_cfg.py'),
61  '--format=main-modules',
62  files('modules.cfg')).stdout().strip().split()
63
64ft2_sources += files([
65  'src/base/ftbase.c',
66  'src/base/ftinit.c',
67])
68
69foreach mod: ft_main_modules
70  source = mod
71  if mod == 'winfonts'
72    source = 'winfnt'
73  elif mod == 'cid'
74    source = 'type1cid'
75  endif
76  ft2_sources += 'src/@0@/@1@.c'.format(mod, source)
77endforeach
78
79# NOTE: The `gzip` and `bzip2` aux modules are handled through options.
80ft_aux_modules = run_command(python_exe,
81  files('builds/meson/parse_modules_cfg.py'),
82  '--format=aux-modules',
83  files('modules.cfg')).stdout().strip().split()
84
85foreach auxmod: ft_aux_modules
86  source = auxmod
87  # Most sources are named `src/<module>/<module>.c`, but there are a few
88  # exceptions handled here.
89  if auxmod == 'cache'
90    source = 'ftcache'
91  elif auxmod == 'lzw'
92    source = 'ftlzw'
93  elif auxmod == 'gzip' or auxmod == 'bzip2'
94    # Handled through options instead, see below.
95    continue
96  endif
97  ft2_sources += 'src/@0@/@1@.c'.format(auxmod, source)
98endforeach
99
100
101# FreeType 2 base extensions.
102# Normally configured through `modules.cfg`.
103
104base_extensions = run_command(python_exe,
105  files('builds/meson/parse_modules_cfg.py'),
106  '--format=base-extensions-list',
107  files('modules.cfg')).stdout().split()
108
109foreach ext: base_extensions
110  ft2_sources += files('src/base/' + ext)
111endforeach
112
113
114# Header files.
115
116ft2_public_headers = files([
117  'include/freetype/freetype.h',
118  'include/freetype/ftadvanc.h',
119  'include/freetype/ftbbox.h',
120  'include/freetype/ftbdf.h',
121  'include/freetype/ftbitmap.h',
122  'include/freetype/ftbzip2.h',
123  'include/freetype/ftcache.h',
124  'include/freetype/ftchapters.h',
125  'include/freetype/ftcolor.h',
126  'include/freetype/ftdriver.h',
127  'include/freetype/fterrdef.h',
128  'include/freetype/fterrors.h',
129  'include/freetype/ftfntfmt.h',
130  'include/freetype/ftgasp.h',
131  'include/freetype/ftglyph.h',
132  'include/freetype/ftgxval.h',
133  'include/freetype/ftgzip.h',
134  'include/freetype/ftimage.h',
135  'include/freetype/ftincrem.h',
136  'include/freetype/ftlcdfil.h',
137  'include/freetype/ftlist.h',
138  'include/freetype/ftlzw.h',
139  'include/freetype/ftmac.h',
140  'include/freetype/ftmm.h',
141  'include/freetype/ftmodapi.h',
142  'include/freetype/ftmoderr.h',
143  'include/freetype/ftotval.h',
144  'include/freetype/ftoutln.h',
145  'include/freetype/ftparams.h',
146  'include/freetype/ftpfr.h',
147  'include/freetype/ftrender.h',
148  'include/freetype/ftsizes.h',
149  'include/freetype/ftsnames.h',
150  'include/freetype/ftstroke.h',
151  'include/freetype/ftsynth.h',
152  'include/freetype/ftsystem.h',
153  'include/freetype/fttrigon.h',
154  'include/freetype/fttypes.h',
155  'include/freetype/ftwinfnt.h',
156  'include/freetype/t1tables.h',
157  'include/freetype/ttnameid.h',
158  'include/freetype/tttables.h',
159  'include/freetype/tttags.h',
160])
161
162ft2_config_headers = files([
163  'include/freetype/config/ftconfig.h',
164  'include/freetype/config/ftheader.h',
165  'include/freetype/config/ftstdlib.h',
166  'include/freetype/config/integer-types.h',
167  'include/freetype/config/mac-support.h',
168  'include/freetype/config/public-macros.h',
169])
170
171ft2_defines = []
172
173
174# System support file.
175
176cc = meson.get_compiler('c')
177
178# NOTE: msys2 on Windows has `unistd.h` and `fcntl.h` but not `sys/mman.h`!
179has_unistd_h = cc.has_header('unistd.h')
180has_fcntl_h = cc.has_header('fcntl.h')
181has_sys_mman_h = cc.has_header('sys/mman.h')
182
183if has_unistd_h
184  ft2_defines += ['-DHAVE_UNISTD_H=1']
185endif
186if has_fcntl_h
187  ft2_defines += ['-DHAVE_FCNTL_H']
188endif
189
190mmap_option = get_option('mmap')
191if mmap_option.auto()
192  use_mmap = has_unistd_h and has_fcntl_h and has_sys_mman_h
193else
194  use_mmap = mmap_option.enabled()
195endif
196if use_mmap
197  # This version of ftsystem.c uses mmap() to read input font files.
198  ft2_sources += files(['builds/unix/ftsystem.c',])
199else
200  ft2_sources += files(['src/base/ftsystem.c',])
201endif
202
203
204# Debug support file
205#
206# NOTE: Some specialized versions exist for other platforms not supported by
207# Meson.  Most implementation differences are extremely minor, i.e., in the
208# implementation of FT_Message() and FT_Panic(), and getting the `FT2_DEBUG`
209# value from the environment, when this is supported.  A smaller refactor
210# might make these platform-specific files much smaller, and could be moved
211# into `ftsystem.c` as well.
212#
213if host_machine.system() == 'windows'
214  ft2_debug_src = 'builds/windows/ftdebug.c'
215else
216  ft2_debug_src = 'src/base/ftdebug.c'
217endif
218ft2_sources += files([ft2_debug_src])
219
220ft2_deps = []
221
222
223# Generate `ftoption.h` based on available dependencies.
224
225ftoption_command = [python_exe,
226  files('builds/meson/process_ftoption_h.py'),
227  '@INPUT@', '--output=@OUTPUT@']
228
229# GZip support
230zlib_option = get_option('zlib')
231if zlib_option == 'disabled'
232  ftoption_command += ['--disable=FT_CONFIG_OPTION_USE_ZLIB']
233else
234  ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_ZLIB']
235  if zlib_option == 'builtin'
236    ftoption_command += ['--disable=FT_CONFIG_OPTION_SYSTEM_ZLIB']
237  else
238    # Probe for the system version.
239    zlib_system = dependency('zlib', required: zlib_option == 'system')
240    ft2_deps += [zlib_system]
241    ftoption_command += ['--enable=FT_CONFIG_OPTION_SYSTEM_ZLIB']
242  endif
243  ft2_sources += files(['src/gzip/ftgzip.c',])
244endif
245
246# BZip2 support
247#
248# IMPORTANT NOTE: Without `static: false` here, Meson will find both the
249# static library version and the shared library version when they are
250# installed on the system, and will try to link them *both* to the final
251# library!
252bzip2_dep = meson.get_compiler('c').find_library('bz2',
253              static: false,
254              required: get_option('bzip2'))
255if bzip2_dep.found()
256  ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_BZIP2']
257  ft2_sources += files(['src/bzip2/ftbzip2.c',])
258  ft2_deps += [bzip2_dep]
259endif
260
261# PNG support
262libpng_dep = dependency('libpng', required: get_option('png'))
263ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_PNG']
264ft2_deps += [libpng_dep]
265
266# Harfbuzz support
267harfbuzz_dep = dependency('harfbuzz',
268                 version: '>= 1.8.0',
269                 required: get_option('harfbuzz'))
270ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_HARFBUZZ']
271ft2_deps += [harfbuzz_dep]
272
273# Brotli decompression support
274brotli_dep = dependency('libbrotlidec', required: get_option('brotli'))
275ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_BROTLI']
276ft2_deps += [brotli_dep]
277
278# We can now generate `ftoption.h`.
279ftoption_h = custom_target('ftoption.h',
280  input: 'include/freetype/config/ftoption.h',
281  output: 'ftoption.h',
282  command: ftoption_command,
283  install: true,
284  install_dir: 'include/freetype2/freetype/config',
285)
286ft2_sources += ftoption_h
287
288
289# QUESTION: What if the compiler doesn't support `-D` but uses `/D` instead
290# as on Windows?
291#
292# Other build systems have something like c_defines to list defines in a
293# more portable way.  For now assume the compiler supports `-D` (hint: Visual
294# Studio does).
295ft2_defines += ['-DFT2_BUILD_LIBRARY=1']
296
297
298# Ensure that the `ftoption.h` file generated above will be used to build
299# FreeType.  Unfortunately, and very surprisingly, configure_file() does not
300# support putting the output file in a sub-directory, so we have to override
301# the default which is `<freetype/config/ftoption.h>`.
302#
303# It would be cleaner to generate the file directly into
304# `${MESON_BUILD_DIR}/freetype/config/ftoption.h`.  See
305# 'https://github.com/mesonbuild/meson/issues/2320' for details.
306ft2_defines += ['-DFT_CONFIG_OPTIONS_H=<ftoption.h>']
307
308ft2_c_args = ft2_defines
309if cc.has_function_attribute('visibility:hidden')
310  ft2_c_args += ['-fvisibility=hidden']
311endif
312
313ft2_lib = library('freetype',
314  sources: ft2_sources + [ftmodule_h],
315  c_args: ft2_c_args,
316  include_directories: ft2_includes,
317  dependencies: ft2_deps,
318  install: true,
319  version: ft2_libtool_version,
320)
321
322
323# To be used by other projects including this one through subproject().
324freetype2_dep = declare_dependency(
325  include_directories: ft2_includes,
326  link_with: ft2_lib,
327  version: ft2_libtool_version)
328
329
330# NOTE: Using both `install_dir` and `subdir` doesn't seem to work below,
331# i.e., the subdir value seems to be ignored, contrary to examples in the
332# Meson documentation.
333install_headers('include/ft2build.h',
334   install_dir: 'include/freetype2')
335install_headers(ft2_public_headers,
336  install_dir: 'include/freetype2/freetype')
337install_headers(ft2_config_headers,
338  install_dir: 'include/freetype2/freetype/config')
339
340
341# TODO(david): Declare_dependency() for using this in a Meson subproject
342#
343pkgconfig = import('pkgconfig')
344pkgconfig.generate(ft2_lib,
345  filebase: 'freetype2',
346  name: 'FreeType 2',
347  description: 'A free, high-quality, and portable font engine.',
348  url: 'https://freetype.org',
349  subdirs: 'freetype2',
350  version: ft2_libtool_version,
351)
352
353
354# NOTE: Unlike the old `make refdoc` command, this generates the
355# documentation under `$BUILD/docs/` since Meson doesn't support modifying
356# the source root directory (which is a good thing).
357gen_docs = custom_target('freetype2 reference documentation',
358  output: 'docs',
359  input: ft2_public_headers + ft2_config_headers,
360  command: [python_exe,
361    files('builds/meson/generate_reference_docs.py'),
362    '--version=' + ft2_version,
363    '--input-dir=' + meson.source_root(),
364    '--output-dir=@OUTPUT@'
365  ],
366)
367
368# EOF
369