1# 2# Meson project file for FreeType 2 3# 4 5# Copyright (C) 2020-2023 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# 15# Say 16# 17# meson configure 18# 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 21# with 22# 23# meson setup -Ddefault_library=shared 24# 25 26project('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(), 31) 32 33 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. 37 38python_exe = find_program('python3') 39 40ft2_so_version = run_command(python_exe, 41 files('builds/meson/extract_libtool_version.py'), 42 '--soversion', 43 files('builds/unix/configure.raw'), 44 check: true).stdout().strip() 45 46ft2_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() 50 51ft2_includes = include_directories('include') 52 53freetype_includedir = join_paths(get_option('includedir'), 'freetype2') 54 55ft2_defines = [] 56 57# Generate a custom `ftmodule.h` version based on the content of 58# `modules.cfg`. 59 60ftmodule_h = custom_target('ftmodule.h', 61 output: 'ftmodule.h', 62 input: 'modules.cfg', 63 command: [python_exe, files('builds/meson/parse_modules_cfg.py'), 64 '--format=ftmodule.h', '@INPUT@', '--output', '@OUTPUT@'], 65 install: true, 66 install_dir: join_paths(freetype_includedir, 'freetype/config'), 67) 68ft2_sources = [ftmodule_h] 69ft2_defines += ['-DFT_CONFIG_MODULES_H=<ftmodule.h>'] 70 71 72# FreeType 2 modules. 73 74ft_main_modules = run_command(python_exe, 75 files('builds/meson/parse_modules_cfg.py'), 76 '--format=main-modules', 77 files('modules.cfg'), 78 check: true).stdout().strip().split() 79 80ft2_sources += files([ 81 'src/base/ftbase.c', 82 'src/base/ftinit.c', 83]) 84 85foreach mod: ft_main_modules 86 source = mod 87 if mod == 'winfonts' 88 source = 'winfnt' 89 elif mod == 'cid' 90 source = 'type1cid' 91 endif 92 ft2_sources += 'src/@0@/@[email protected]'.format(mod, source) 93endforeach 94 95# NOTE: The `bzip2` aux module is handled through options. 96ft_aux_modules = run_command(python_exe, 97 files('builds/meson/parse_modules_cfg.py'), 98 '--format=aux-modules', 99 files('modules.cfg'), 100 check: true).stdout().strip().split() 101 102foreach auxmod: ft_aux_modules 103 source = auxmod 104 # Most sources are named `src/<module>/<module>.c`, but there are a few 105 # exceptions handled here. 106 if auxmod == 'cache' 107 source = 'ftcache' 108 elif auxmod == 'lzw' 109 source = 'ftlzw' 110 elif auxmod == 'gzip' 111 source = 'ftgzip' 112 elif auxmod == 'bzip2' 113 # Handled through options instead, see below. 114 continue 115 endif 116 ft2_sources += 'src/@0@/@[email protected]'.format(auxmod, source) 117endforeach 118 119 120# FreeType 2 base extensions. 121# To be configured in `modules.cfg`. 122 123base_extensions = run_command(python_exe, 124 files('builds/meson/parse_modules_cfg.py'), 125 '--format=base-extensions-list', 126 files('modules.cfg'), 127 check: true).stdout().split() 128 129foreach ext: base_extensions 130 ft2_sources += files('src/base/' + ext) 131endforeach 132 133 134# Header files. 135 136ft2_public_headers = files([ 137 'include/freetype/freetype.h', 138 'include/freetype/ftadvanc.h', 139 'include/freetype/ftbbox.h', 140 'include/freetype/ftbdf.h', 141 'include/freetype/ftbitmap.h', 142 'include/freetype/ftbzip2.h', 143 'include/freetype/ftcache.h', 144 'include/freetype/ftchapters.h', 145 'include/freetype/ftcid.h', 146 'include/freetype/ftcolor.h', 147 'include/freetype/ftdriver.h', 148 'include/freetype/fterrdef.h', 149 'include/freetype/fterrors.h', 150 'include/freetype/ftfntfmt.h', 151 'include/freetype/ftgasp.h', 152 'include/freetype/ftglyph.h', 153 'include/freetype/ftgxval.h', 154 'include/freetype/ftgzip.h', 155 'include/freetype/ftimage.h', 156 'include/freetype/ftincrem.h', 157 'include/freetype/ftlcdfil.h', 158 'include/freetype/ftlist.h', 159 'include/freetype/ftlzw.h', 160 'include/freetype/ftmac.h', 161 'include/freetype/ftmm.h', 162 'include/freetype/ftmodapi.h', 163 'include/freetype/ftmoderr.h', 164 'include/freetype/ftotval.h', 165 'include/freetype/ftoutln.h', 166 'include/freetype/ftparams.h', 167 'include/freetype/ftpfr.h', 168 'include/freetype/ftrender.h', 169 'include/freetype/ftsizes.h', 170 'include/freetype/ftsnames.h', 171 'include/freetype/ftstroke.h', 172 'include/freetype/ftsynth.h', 173 'include/freetype/ftsystem.h', 174 'include/freetype/fttrigon.h', 175 'include/freetype/fttypes.h', 176 'include/freetype/ftwinfnt.h', 177 'include/freetype/otsvg.h', 178 'include/freetype/t1tables.h', 179 'include/freetype/ttnameid.h', 180 'include/freetype/tttables.h', 181 'include/freetype/tttags.h', 182]) 183 184ft2_config_headers = files([ 185 'include/freetype/config/ftconfig.h', 186 'include/freetype/config/ftheader.h', 187 'include/freetype/config/ftstdlib.h', 188 'include/freetype/config/integer-types.h', 189 'include/freetype/config/mac-support.h', 190 'include/freetype/config/public-macros.h', 191]) 192 193ft2_defines += ['-DFT2_BUILD_LIBRARY=1'] 194 195 196# System support file. 197 198cc = meson.get_compiler('c') 199 200# NOTE: msys2 on Windows has `unistd.h` and `fcntl.h` but not `sys/mman.h`! 201has_unistd_h = cc.has_header('unistd.h') 202has_fcntl_h = cc.has_header('fcntl.h') 203has_sys_mman_h = cc.has_header('sys/mman.h') 204 205mmap_option = get_option('mmap') 206 207use_unix_ftsystem_c = false 208if mmap_option.disabled() 209 ft2_sources += files(['src/base/ftsystem.c',]) 210elif host_machine.system() == 'windows' 211 ft2_sources += files(['builds/windows/ftsystem.c',]) 212else 213 if has_unistd_h and has_fcntl_h and has_sys_mman_h 214 # This version of `ftsystem.c` uses `mmap` to read input font files. 215 ft2_sources += files(['builds/unix/ftsystem.c',]) 216 use_unix_ftsystem_c = true 217 elif mmap_option.enabled() 218 error('mmap was enabled via options but is not available,' 219 + ' required headers were not found!') 220 else 221 ft2_sources += files(['src/base/ftsystem.c',]) 222 endif 223endif 224 225 226# Debug support file 227# 228# NOTE: Some specialized versions exist for other platforms not supported by 229# Meson. Most implementation differences are extremely minor, i.e., in the 230# implementation of `FT_Message` and `FT_Panic`, and getting the `FT2_DEBUG` 231# value from the environment, when this is supported. A smaller refactor 232# might make these platform-specific files much smaller, and could be moved 233# into `ftsystem.c` as well. 234# 235if host_machine.system() == 'windows' 236 winmod = import('windows') 237 ft2_sources += [ 238 'builds/windows/ftdebug.c', 239 winmod.compile_resources('src/base/ftver.rc'), 240 ] 241else 242 ft2_sources += 'src/base/ftdebug.c' 243endif 244 245 246ft2_deps = [] 247common_ldflags = [] 248 249 250# Correct compatibility version for OS x. 251# 252# OSX sets the compatibility_version (aka libtools version) differently from 253# the library name. 254# 255if host_machine.system() == 'darwin' 256 # maintain compatibility with autotools on macOS 257 common_ldflags = [ 258 '-compatibility_version', ft2_pkgconfig_version.split('.')[0], 259 '-current_version', ft2_pkgconfig_version 260 ] 261endif 262 263 264# Generate `ftoption.h` based on available dependencies. 265 266process_header_command = [python_exe, 267 files('builds/meson/process_ftoption_h.py'), 268 '@INPUT@', '--output=@OUTPUT@'] 269ftoption_command = process_header_command 270 271 272# external GZip support 273zlib_option = get_option('zlib') 274 275# Backwards-compatible aliases. 276if zlib_option == 'disabled' 277 zlib_option = 'none' 278elif zlib_option == 'enabled' 279 zlib_option = 'auto' 280endif 281 282if zlib_option == 'auto' 283 # First try to find a system installation, otherwise fall back to 284 # the subproject. 285 zlib_dep = dependency('zlib', 286 required: false) 287 if zlib_dep.found() 288 zlib_option = 'system' 289 else 290 zlib_option = 'external' 291 endif 292endif 293 294if zlib_option == 'none' 295 ftoption_command += [ '--disable=FT_CONFIG_OPTION_USE_ZLIB' ] 296elif zlib_option == 'internal' 297 ftoption_command += [ '--enable=FT_CONFIG_OPTION_USE_ZLIB' ] 298elif zlib_option == 'external' 299 ftoption_command += [ '--enable=FT_CONFIG_OPTION_USE_ZLIB' ] 300 zlib_project = subproject('zlib', 301 required: true, 302 default_options: 'default_library=static') 303 zlib_dep = zlib_project.get_variable('zlib_dep') 304 ft2_deps += [zlib_dep] 305elif zlib_option == 'system' 306 zlib_dep = dependency('zlib', 307 required: true) 308 assert(zlib_dep.found(), 'Could not find system zlib installation!') 309 ftoption_command += [ 310 '--enable=FT_CONFIG_OPTION_USE_ZLIB', 311 '--enable=FT_CONFIG_OPTION_SYSTEM_ZLIB', 312 ] 313 ft2_deps += [zlib_dep] 314else 315 assert(false, 'Invalid zlib option ' + zlib_option) 316endif 317 318# BZip2 support 319bzip2_dep = cc.find_library('bz2', 320 required: get_option('bzip2')) 321 322if bzip2_dep.found() 323 ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_BZIP2'] 324 ft2_sources += files(['src/bzip2/ftbzip2.c',]) 325 ft2_deps += [bzip2_dep] 326endif 327 328# PNG support 329libpng_dep = dependency('libpng', 330 required: get_option('png'), 331 fallback: 'libpng') 332 333if libpng_dep.found() 334 ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_PNG'] 335 ft2_deps += [libpng_dep] 336endif 337 338# Harfbuzz support 339harfbuzz_dep = dependency('harfbuzz', 340 version: '>= 2.0.0', 341 required: get_option('harfbuzz'), 342 default_options: ['freetype=disabled']) 343 344if harfbuzz_dep.found() 345 ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_HARFBUZZ'] 346 ft2_deps += [harfbuzz_dep] 347endif 348 349# Brotli decompression support 350brotli_dep = dependency('libbrotlidec', 351 required: get_option('brotli')) 352 353if brotli_dep.found() 354 ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_BROTLI'] 355 ft2_deps += [brotli_dep] 356endif 357 358# We can now generate `ftoption.h`. 359ftoption_h = custom_target('ftoption.h', 360 input: 'include/freetype/config/ftoption.h', 361 output: 'ftoption.h', 362 command: ftoption_command, 363 install: true, 364 install_dir: join_paths(freetype_includedir, 'freetype/config'), 365) 366ft2_sources += ftoption_h 367ft2_defines += ['-DFT_CONFIG_OPTIONS_H=<ftoption.h>'] 368 369if host_machine.system() == 'windows' 370 ft2_defines += ['-DDLL_EXPORT=1'] 371endif 372 373 374# Generate `ftconfig.h`. 375 376ftconfig_command = process_header_command 377if has_unistd_h 378 ftconfig_command += '--enable=HAVE_UNISTD_H' 379endif 380if has_fcntl_h 381 ftconfig_command += '--enable=HAVE_FCNTL_H' 382endif 383 384if use_unix_ftsystem_c 385 ftconfig_h_in = files('builds/unix/ftconfig.h.in') 386 ftconfig_h = custom_target('ftconfig.h', 387 input: ftconfig_h_in, 388 output: 'ftconfig.h', 389 command: ftconfig_command, 390 install: true, 391 install_dir: join_paths(freetype_includedir, 'freetype/config'), 392 ) 393 ft2_sources += ftconfig_h 394 ft2_defines += ['-DFT_CONFIG_CONFIG_H=<ftconfig.h>'] 395endif 396 397 398ft2_lib = library('freetype', 399 sources: ft2_sources + [ftmodule_h], 400 c_args: ft2_defines, 401 gnu_symbol_visibility: 'hidden', 402 include_directories: ft2_includes, 403 dependencies: ft2_deps, 404 install: true, 405 version: ft2_so_version, 406 link_args: common_ldflags, 407) 408 409 410# To be used by other projects including this one through `subproject`. 411freetype_dep = declare_dependency( 412 include_directories: ft2_includes, 413 link_with: ft2_lib, 414 version: ft2_pkgconfig_version) 415 416meson.override_dependency('freetype2', freetype_dep) 417 418 419# NOTE: Using both `install_dir` and `subdir` doesn't seem to work below, 420# i.e., the subdir value seems to be ignored, contrary to examples in the 421# Meson documentation. 422install_headers('include/ft2build.h', 423 install_dir: freetype_includedir) 424install_headers(ft2_public_headers, 425 install_dir: join_paths(freetype_includedir, 'freetype')) 426install_headers(ft2_config_headers, 427 install_dir: join_paths(freetype_includedir, 'freetype/config')) 428 429 430pkgconfig = import('pkgconfig') 431 432pkgconfig.generate(ft2_lib, 433 filebase: 'freetype2', 434 name: 'FreeType 2', 435 description: 'A free, high-quality, and portable font engine.', 436 url: 'https://freetype.org', 437 subdirs: 'freetype2', 438 version: ft2_pkgconfig_version, 439) 440 441if get_option('tests').enabled() 442 subdir('tests') 443endif 444 445# NOTE: Unlike the old `make refdoc` command, this generates the 446# documentation under `$BUILD/docs/` since Meson doesn't support modifying 447# the source root directory (which is a good thing). 448gen_docs = custom_target('freetype2 reference documentation', 449 output: 'docs', 450 input: ft2_public_headers + ft2_config_headers, 451 command: [python_exe, 452 files('builds/meson/generate_reference_docs.py'), 453 '--version=' + meson.project_version(), 454 '--input-dir=' + meson.current_source_dir(), 455 '--output-dir=@OUTPUT@' 456 ], 457) 458 459 460summary({'OS': host_machine.system(), 461 }, section: 'Operating System') 462 463summary({'Zlib': zlib_option, 464 'Bzip2': bzip2_dep.found() ? 'yes' : 'no', 465 'Png': libpng_dep.found() ? 'yes' : 'no', 466 'Harfbuzz': harfbuzz_dep.found() ? 'yes' : 'no', 467 'Brotli': brotli_dep.found() ? 'yes' : 'no', 468 }, section: 'Used Libraries') 469 470# EOF 471