2 # Meson project file for FreeType 2
5 # Copyright (C) 2020-2024 by
6 # David Turner, Robert Wilhelm, and Werner Lemberg.
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
19 # to see all configuration options and their default values. For example,
20 # to build only a shared version of FreeType, override the default value
23 # meson setup -Ddefault_library=shared
26 project('freetype2', 'c',
27 meson_version: '>= 0.55.0',
28 version: run_command('builds/meson/extract_freetype_version.py',
29 'include/freetype/freetype.h',
30 check: true).stdout().strip(),
34 # Only meson >= 0.57 can read a file and assign its contents to a
35 # variable; we thus use an external command to have this functionality
36 # with older versions, too.
38 python_exe = find_program('python3')
40 ft2_so_version = run_command(python_exe,
41 files('builds/meson/extract_libtool_version.py'),
43 files('builds/unix/configure.raw'),
44 check: true).stdout().strip()
46 ft2_pkgconfig_version = run_command(python_exe,
47 files('builds/meson/extract_libtool_version.py'),
48 files('builds/unix/configure.raw'),
49 check: true).stdout().strip()
51 ft2_includes = include_directories('include')
53 freetype_includedir = join_paths(get_option('includedir'), 'freetype2')
57 freetype_aclocaldir = join_paths(get_option('datadir'), 'aclocal')
60 # Generate a custom `ftmodule.h` version based on the content of
63 ftmodule_h = custom_target('ftmodule.h',
66 command: [python_exe, files('builds/meson/parse_modules_cfg.py'),
67 '--format=ftmodule.h', '@INPUT@', '--output', '@OUTPUT@'],
69 install_dir: join_paths(freetype_includedir, 'freetype/config'),
71 ft2_sources = [ftmodule_h]
72 ft2_defines += ['-DFT_CONFIG_MODULES_H=<ftmodule.h>']
77 ft_main_modules = run_command(python_exe,
78 files('builds/meson/parse_modules_cfg.py'),
79 '--format=main-modules',
81 check: true).stdout().strip().split()
83 ft2_sources += files([
88 foreach mod: ft_main_modules
95 ft2_sources += 'src/@0@/@1@.c'.format(mod, source)
98 # NOTE: The `bzip2` aux module is handled through options.
99 ft_aux_modules = run_command(python_exe,
100 files('builds/meson/parse_modules_cfg.py'),
101 '--format=aux-modules',
102 files('modules.cfg'),
103 check: true).stdout().strip().split()
105 foreach auxmod: ft_aux_modules
107 # Most sources are named `src/<module>/<module>.c`, but there are a few
108 # exceptions handled here.
113 elif auxmod == 'gzip'
115 elif auxmod == 'bzip2'
116 # Handled through options instead, see below.
119 ft2_sources += 'src/@0@/@1@.c'.format(auxmod, source)
123 # FreeType 2 base extensions.
124 # To be configured in `modules.cfg`.
126 base_extensions = run_command(python_exe,
127 files('builds/meson/parse_modules_cfg.py'),
128 '--format=base-extensions-list',
129 files('modules.cfg'),
130 check: true).stdout().split()
132 foreach ext: base_extensions
133 ft2_sources += files('src/base/' + ext)
139 ft2_public_headers = files([
140 'include/freetype/freetype.h',
141 'include/freetype/ftadvanc.h',
142 'include/freetype/ftbbox.h',
143 'include/freetype/ftbdf.h',
144 'include/freetype/ftbitmap.h',
145 'include/freetype/ftbzip2.h',
146 'include/freetype/ftcache.h',
147 'include/freetype/ftchapters.h',
148 'include/freetype/ftcid.h',
149 'include/freetype/ftcolor.h',
150 'include/freetype/ftdriver.h',
151 'include/freetype/fterrdef.h',
152 'include/freetype/fterrors.h',
153 'include/freetype/ftfntfmt.h',
154 'include/freetype/ftgasp.h',
155 'include/freetype/ftglyph.h',
156 'include/freetype/ftgxval.h',
157 'include/freetype/ftgzip.h',
158 'include/freetype/ftimage.h',
159 'include/freetype/ftincrem.h',
160 'include/freetype/ftlcdfil.h',
161 'include/freetype/ftlist.h',
162 'include/freetype/ftlzw.h',
163 'include/freetype/ftmac.h',
164 'include/freetype/ftmm.h',
165 'include/freetype/ftmodapi.h',
166 'include/freetype/ftmoderr.h',
167 'include/freetype/ftotval.h',
168 'include/freetype/ftoutln.h',
169 'include/freetype/ftparams.h',
170 'include/freetype/ftpfr.h',
171 'include/freetype/ftrender.h',
172 'include/freetype/ftsizes.h',
173 'include/freetype/ftsnames.h',
174 'include/freetype/ftstroke.h',
175 'include/freetype/ftsynth.h',
176 'include/freetype/ftsystem.h',
177 'include/freetype/fttrigon.h',
178 'include/freetype/fttypes.h',
179 'include/freetype/ftwinfnt.h',
180 'include/freetype/otsvg.h',
181 'include/freetype/t1tables.h',
182 'include/freetype/ttnameid.h',
183 'include/freetype/tttables.h',
184 'include/freetype/tttags.h',
187 ft2_config_headers = files([
188 'include/freetype/config/ftconfig.h',
189 'include/freetype/config/ftheader.h',
190 'include/freetype/config/ftstdlib.h',
191 'include/freetype/config/integer-types.h',
192 'include/freetype/config/mac-support.h',
193 'include/freetype/config/public-macros.h',
196 ft2_defines += ['-DFT2_BUILD_LIBRARY=1']
199 # System support file.
201 cc = meson.get_compiler('c')
203 # NOTE: msys2 on Windows has `unistd.h` and `fcntl.h` but not `sys/mman.h`!
204 has_unistd_h = cc.has_header('unistd.h')
205 has_fcntl_h = cc.has_header('fcntl.h')
206 has_sys_mman_h = cc.has_header('sys/mman.h')
208 mmap_option = get_option('mmap')
210 use_unix_ftsystem_c = false
211 if mmap_option.disabled()
212 ft2_sources += files(['src/base/ftsystem.c',])
213 elif host_machine.system() == 'windows'
214 ft2_sources += files(['builds/windows/ftsystem.c',])
216 if has_unistd_h and has_fcntl_h and has_sys_mman_h
217 # This version of `ftsystem.c` uses `mmap` to read input font files.
218 ft2_sources += files(['builds/unix/ftsystem.c',])
219 use_unix_ftsystem_c = true
220 elif mmap_option.enabled()
221 error('mmap was enabled via options but is not available,'
222 + ' required headers were not found!')
224 ft2_sources += files(['src/base/ftsystem.c',])
231 # NOTE: Some specialized versions exist for other platforms not supported by
232 # Meson. Most implementation differences are extremely minor, i.e., in the
233 # implementation of `FT_Message` and `FT_Panic`, and getting the `FT2_DEBUG`
234 # value from the environment, when this is supported. A smaller refactor
235 # might make these platform-specific files much smaller, and could be moved
236 # into `ftsystem.c` as well.
238 if host_machine.system() == 'windows'
239 winmod = import('windows')
241 'builds/windows/ftdebug.c',
242 winmod.compile_resources('src/base/ftver.rc'),
245 ft2_sources += 'src/base/ftdebug.c'
253 # Correct compatibility version for OS x.
255 # OSX sets the compatibility_version (aka libtools version) differently from
258 if host_machine.system() == 'darwin'
259 # maintain compatibility with autotools on macOS
261 '-compatibility_version', ft2_pkgconfig_version.split('.')[0],
262 '-current_version', ft2_pkgconfig_version
267 # Generate `ftoption.h` based on available dependencies.
269 process_header_command = [python_exe,
270 files('builds/meson/process_ftoption_h.py'),
271 '@INPUT@', '--output=@OUTPUT@']
273 ftoption_command = process_header_command
275 # External GZip support.
276 zlib_option = get_option('zlib')
278 # Backward-compatible aliases.
279 if zlib_option == 'disabled'
281 elif zlib_option == 'enabled'
285 if zlib_option == 'auto'
286 # First try to find a system installation, otherwise fall back to
288 zlib_dep = dependency('zlib',
291 zlib_option = 'system'
293 zlib_option = 'external'
297 if zlib_option == 'none'
298 ftoption_command += [ '--disable=FT_CONFIG_OPTION_USE_ZLIB' ]
299 elif zlib_option == 'internal'
300 ftoption_command += [ '--enable=FT_CONFIG_OPTION_USE_ZLIB' ]
301 elif zlib_option == 'external'
302 ftoption_command += [ '--enable=FT_CONFIG_OPTION_USE_ZLIB' ]
303 zlib_project = subproject('zlib',
305 default_options: 'default_library=static')
306 zlib_dep = zlib_project.get_variable('zlib_dep')
307 ft2_deps += [zlib_dep]
308 elif zlib_option == 'system'
309 zlib_dep = dependency('zlib',
311 assert(zlib_dep.found(), 'Could not find system zlib installation!')
312 ftoption_command += [
313 '--enable=FT_CONFIG_OPTION_USE_ZLIB',
314 '--enable=FT_CONFIG_OPTION_SYSTEM_ZLIB',
316 ft2_deps += [zlib_dep]
318 assert(false, 'Invalid zlib option ' + zlib_option)
322 bzip2_dep = dependency('bzip2', required: false)
323 if not bzip2_dep.found()
324 bzip2_dep = cc.find_library('bz2',
325 has_headers: ['bzlib.h'],
326 required: get_option('bzip2'))
330 ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_BZIP2']
331 ft2_sources += files(['src/bzip2/ftbzip2.c',])
332 ft2_deps += [bzip2_dep]
336 libpng_dep = dependency('libpng',
337 required: get_option('png'),
340 if libpng_dep.found()
341 ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_PNG']
342 ft2_deps += [libpng_dep]
346 harfbuzz_dep = dependency('harfbuzz',
348 required: get_option('harfbuzz'),
349 default_options: ['freetype=disabled'])
351 if harfbuzz_dep.found()
352 ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_HARFBUZZ']
353 ft2_deps += [harfbuzz_dep]
356 # Brotli decompression support.
357 brotli_dep = dependency('libbrotlidec',
358 required: get_option('brotli'))
360 if brotli_dep.found()
361 ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_BROTLI']
362 ft2_deps += [brotli_dep]
365 # We can now generate `ftoption.h`.
366 ftoption_h = custom_target('ftoption.h',
367 input: 'include/freetype/config/ftoption.h',
368 output: 'ftoption.h',
369 command: ftoption_command,
371 install_dir: join_paths(freetype_includedir, 'freetype/config'),
373 ft2_sources += ftoption_h
374 ft2_defines += ['-DFT_CONFIG_OPTIONS_H=<ftoption.h>']
376 if host_machine.system() == 'windows'
377 ft2_defines += ['-DDLL_EXPORT=1']
381 # Generate `ftconfig.h`.
383 ftconfig_command = process_header_command
386 ftconfig_command += '--enable=HAVE_UNISTD_H'
389 ftconfig_command += '--enable=HAVE_FCNTL_H'
392 if use_unix_ftsystem_c
393 ftconfig_h_in = files('builds/unix/ftconfig.h.in')
394 ftconfig_h = custom_target('ftconfig.h',
395 input: ftconfig_h_in,
396 output: 'ftconfig.h',
397 command: ftconfig_command,
399 install_dir: join_paths(freetype_includedir, 'freetype/config'),
401 ft2_sources += ftconfig_h
402 ft2_defines += ['-DFT_CONFIG_CONFIG_H=<ftconfig.h>']
406 ft2_lib = library('freetype',
407 sources: ft2_sources + [ftmodule_h],
409 gnu_symbol_visibility: 'hidden',
410 include_directories: ft2_includes,
411 dependencies: ft2_deps,
413 version: ft2_so_version,
414 link_args: common_ldflags,
418 # To be used by other projects including this one via `subproject`.
420 freetype_dep = declare_dependency(
421 include_directories: ft2_includes,
423 version: ft2_pkgconfig_version)
425 meson.override_dependency('freetype2', freetype_dep)
428 # NOTE: Using both `install_dir` and `subdir` doesn't seem to work
429 # below, i.e., the `subdir` value seems to be ignored, contrary to
430 # examples in the Meson documentation.
431 install_headers('include/ft2build.h',
432 install_dir: freetype_includedir)
433 install_headers(ft2_public_headers,
434 install_dir: join_paths(freetype_includedir, 'freetype'))
435 install_headers(ft2_config_headers,
436 install_dir: join_paths(freetype_includedir, 'freetype/config'))
439 install_data('builds/unix/freetype2.m4',
440 install_dir: freetype_aclocaldir)
443 pkgconfig = import('pkgconfig')
445 pkgconfig.generate(ft2_lib,
446 filebase: 'freetype2',
448 description: 'A free, high-quality, and portable font engine.',
449 url: 'https://freetype.org',
450 subdirs: 'freetype2',
451 version: ft2_pkgconfig_version,
454 if get_option('tests').enabled()
459 # NOTE: Unlike the old `make refdoc` command, this generates the
460 # documentation under `$BUILD/docs/` since Meson doesn't support modifying
461 # the source root directory (which is a good thing).
463 gen_docs = custom_target('freetype2 reference documentation',
465 input: ft2_public_headers + ft2_config_headers,
466 command: [python_exe,
467 files('builds/meson/generate_reference_docs.py'),
468 '--version=' + meson.project_version(),
469 '--input-dir=' + meson.current_source_dir(),
470 '--output-dir=@OUTPUT@'
475 summary({'OS': host_machine.system(),
476 }, section: 'Operating System')
478 summary({'Zlib': zlib_option,
479 'Bzip2': bzip2_dep.found() ? 'yes' : 'no',
480 'Png': libpng_dep.found() ? 'yes' : 'no',
481 'Harfbuzz': harfbuzz_dep.found() ? 'yes' : 'no',
482 'Brotli': brotli_dep.found() ? 'yes' : 'no',
483 }, section: 'Used Libraries')