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