1project('harfbuzz', 'c', 'cpp', 2 meson_version: '>= 0.55.0', 3 version: '6.0.0', 4 default_options: [ 5 'cpp_rtti=false', # Just to support msvc, we are passing -fno-exceptions also anyway 6 'cpp_std=c++11', 7 'wrap_mode=nofallback', # Use --wrap-mode=default to revert, https://github.com/harfbuzz/harfbuzz/pull/2548 8 ], 9) 10 11hb_version_arr = meson.project_version().split('.') 12hb_version_major = hb_version_arr[0].to_int() 13hb_version_minor = hb_version_arr[1].to_int() 14hb_version_micro = hb_version_arr[2].to_int() 15 16# libtool versioning 17hb_version_int = hb_version_major*10000 + hb_version_minor*100 + hb_version_micro 18hb_libtool_version_info = '@0@:0:@0@'.format(hb_version_int) 19 20pkgmod = import('pkgconfig') 21cpp = meson.get_compiler('cpp') 22null_dep = dependency('', required: false) 23 24if cpp.get_argument_syntax() == 'msvc' 25 # Ignore several spurious warnings for things HarfBuzz does very commonly. 26 # If a warning is completely useless and spammy, use '/wdXXXX' to suppress it 27 # If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once 28 # NOTE: Only add warnings here if you are sure they're spurious 29 msvc_args = [ 30 '/wd4018', # implicit signed/unsigned conversion 31 '/wd4146', # unary minus on unsigned (beware INT_MIN) 32 '/wd4244', # lossy type conversion (e.g. double -> int) 33 '/wd4305', # truncating type conversion (e.g. double -> float) 34 cpp.get_supported_arguments(['/utf-8']), # set the input encoding to utf-8 35 ] 36 add_project_arguments(msvc_args, language: ['c', 'cpp']) 37 # Disable SAFESEH with MSVC for libs that use external deps that are built with MinGW 38 # noseh_link_args = ['/SAFESEH:NO'] 39 # disable exception handling 40 add_project_arguments(['/EHs-', '/EHc-'], language: 'cpp') 41endif 42 43add_project_link_arguments(cpp.get_supported_link_arguments([ 44 '-Bsymbolic-functions' 45]), language: 'c') 46 47add_project_arguments(cpp.get_supported_arguments([ 48 '-fno-exceptions', 49 '-fno-rtti', 50 '-fno-threadsafe-statics', 51 '-fvisibility-inlines-hidden', 52]), language: 'cpp') 53 54if host_machine.cpu_family() == 'arm' and cpp.alignment('struct { char c; }') != 1 55 if cpp.has_argument('-mstructure-size-boundary=8') 56 add_project_arguments('-mstructure-size-boundary=8', language: 'cpp') 57 endif 58endif 59 60if host_machine.system() == 'windows' 61 add_project_arguments(cpp.get_supported_arguments([ 62 '-Wa,-mbig-obj' 63 ]), language : 'cpp') 64endif 65 66check_headers = [ 67 ['unistd.h'], 68 ['sys/mman.h'], 69 ['stdbool.h'], 70 ['xlocale.h'], 71] 72 73check_funcs = [ 74 ['atexit'], 75 ['mprotect'], 76 ['sysconf'], 77 ['getpagesize'], 78 ['mmap'], 79 ['isatty'], 80 ['uselocale'], 81 ['newlocale'], 82] 83 84m_dep = cpp.find_library('m', required: false) 85 86if meson.version().version_compare('>=0.60.0') 87 # pkg-config: freetype2, cmake: Freetype 88 freetype_dep = dependency('freetype2', 'Freetype', 89 required: get_option('freetype'), 90 default_options: ['harfbuzz=disabled'], 91 allow_fallback: true) 92else 93 # painful hack to handle multiple dependencies but also respect options 94 freetype_opt = get_option('freetype') 95 # we want to handle enabled manually after fallbacks, but also handle disabled normally 96 if freetype_opt.enabled() 97 freetype_opt = false 98 endif 99 # try pkg-config name 100 freetype_dep = dependency('freetype2', method: 'pkg-config', required: freetype_opt) 101 # when disabled, leave it not-found 102 if not freetype_dep.found() and not get_option('freetype').disabled() 103 # Try cmake name 104 freetype_dep = dependency('Freetype', method: 'cmake', required: false) 105 # Subproject fallback, `allow_fallback: true` means the fallback will be 106 # tried even if the freetype option is set to `auto`. 107 if not freetype_dep.found() 108 freetype_dep = dependency('freetype2', 109 method: 'pkg-config', 110 required: get_option('freetype'), 111 default_options: ['harfbuzz=disabled'], 112 allow_fallback: true) 113 endif 114 endif 115endif 116 117glib_dep = dependency('glib-2.0', required: get_option('glib')) 118gobject_dep = dependency('gobject-2.0', required: get_option('gobject')) 119graphite2_dep = dependency('graphite2', required: get_option('graphite2')) 120graphite_dep = dependency('graphite2', required: get_option('graphite')) 121 122if meson.version().version_compare('>=0.60.0') 123 # pkg-config: icu-uc, cmake: ICU but with components 124 icu_dep = dependency('icu-uc', 'ICU', 125 components: 'uc', 126 required: get_option('icu'), 127 default_options: ['harfbuzz=disabled'], 128 allow_fallback: true) 129else 130 # painful hack to handle multiple dependencies but also respect options 131 icu_opt = get_option('icu') 132 # we want to handle enabled manually after fallbacks, but also handle disabled normally 133 if icu_opt.enabled() 134 icu_opt = false 135 endif 136 # try pkg-config name 137 icu_dep = dependency('icu-uc', method: 'pkg-config', required: icu_opt) 138 # when disabled, leave it not-found 139 if not icu_dep.found() and not get_option('icu').disabled() 140 # Try cmake name 141 icu_dep = dependency('ICU', method: 'cmake', components: 'uc', required: false) 142 # Try again with subproject fallback. `allow_fallback: true` means the 143 # fallback will be tried even if the icu option is set to `auto`, but 144 # we cannot pass this option until Meson 0.59.0, because no wrap file 145 # is checked into git. 146 if not icu_dep.found() 147 icu_dep = dependency('icu-uc', 148 method: 'pkg-config', 149 required: get_option('icu')) 150 endif 151 endif 152endif 153 154if icu_dep.found() and icu_dep.type_name() == 'pkgconfig' 155 icu_defs = icu_dep.get_variable(pkgconfig: 'DEFS', default_value: '').split() 156 if icu_defs.length() > 0 157 add_project_arguments(icu_defs, language: ['c', 'cpp']) 158 endif 159endif 160 161cairo_dep = null_dep 162cairo_ft_dep = null_dep 163if not get_option('cairo').disabled() 164 cairo_dep = dependency('cairo', required: false) 165 cairo_ft_dep = dependency('cairo-ft', required: false) 166 167 if (not cairo_dep.found() and 168 cpp.get_argument_syntax() == 'msvc' and 169 cpp.has_header('cairo.h')) 170 cairo_dep = cpp.find_library('cairo', required: false) 171 if cairo_dep.found() and cpp.has_function('cairo_ft_font_face_create_for_ft_face', 172 prefix: '#include <cairo-ft.h>', 173 dependencies: cairo_dep) 174 cairo_ft_dep = cairo_dep 175 endif 176 endif 177 178 if not cairo_dep.found() 179 # Note that we don't have harfbuzz -> cairo -> freetype2 -> harfbuzz fallback 180 # dependency cycle here because we have configured freetype2 above with 181 # harfbuzz support disabled, so when cairo will lookup freetype2 dependency 182 # it will be forced to use that one. 183 cairo_dep = dependency('cairo', required: get_option('cairo')) 184 cairo_ft_required = get_option('cairo').enabled() and get_option('freetype').enabled() 185 cairo_ft_dep = dependency('cairo-ft', required: cairo_ft_required) 186 endif 187endif 188 189chafa_dep = dependency('chafa', version: '>= 1.6.0', required: get_option('chafa')) 190 191conf = configuration_data() 192incconfig = include_directories('.') 193 194add_project_arguments('-DHAVE_CONFIG_H', language: ['c', 'cpp']) 195 196warn_cflags = [ 197 '-Wno-non-virtual-dtor', 198] 199 200cpp_args = cpp.get_supported_arguments(warn_cflags) 201 202if glib_dep.found() 203 conf.set('HAVE_GLIB', 1) 204endif 205 206if gobject_dep.found() 207 conf.set('HAVE_GOBJECT', 1) 208endif 209 210if cairo_dep.found() 211 conf.set('HAVE_CAIRO', 1) 212 if cairo_dep.type_name() == 'internal' 213 conf.set('HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC', 1) 214 else 215 check_funcs += [['cairo_user_font_face_set_render_color_glyph_func', {'deps': cairo_dep}]] 216 endif 217endif 218 219if cairo_ft_dep.found() 220 conf.set('HAVE_CAIRO_FT', 1) 221endif 222 223if chafa_dep.found() 224 conf.set('HAVE_CHAFA', 1) 225endif 226 227if graphite2_dep.found() or graphite_dep.found() 228 conf.set('HAVE_GRAPHITE2', 1) 229endif 230 231if icu_dep.found() 232 conf.set('HAVE_ICU', 1) 233endif 234 235if get_option('icu_builtin') 236 conf.set('HAVE_ICU_BUILTIN', 1) 237endif 238 239if get_option('experimental_api') 240 conf.set('HB_EXPERIMENTAL_API', 1) 241endif 242 243if freetype_dep.found() 244 conf.set('HAVE_FREETYPE', 1) 245 check_freetype_funcs = [ 246 ['FT_Get_Var_Blend_Coordinates', {'deps': freetype_dep}], 247 ['FT_Set_Var_Blend_Coordinates', {'deps': freetype_dep}], 248 ['FT_Done_MM_Var', {'deps': freetype_dep}], 249 ['FT_Get_Transform', {'deps': freetype_dep}], 250 ] 251 252 if freetype_dep.type_name() == 'internal' 253 foreach func: check_freetype_funcs 254 name = func[0] 255 conf.set('HAVE_@0@'.format(name.to_upper()), 1) 256 endforeach 257 else 258 check_funcs += check_freetype_funcs 259 endif 260endif 261 262gdi_uniscribe_deps = [] 263# GDI (Uniscribe) (Windows) 264if host_machine.system() == 'windows' and not get_option('gdi').disabled() 265 if (get_option('directwrite').enabled() and 266 not (cpp.has_header('usp10.h') and cpp.has_header('windows.h'))) 267 error('GDI/Uniscribe was enabled explicitly, but required headers are missing.') 268 endif 269 270 gdi_deps_found = true 271 foreach usplib : ['usp10', 'gdi32', 'rpcrt4'] 272 dep = cpp.find_library(usplib, required: get_option('gdi')) 273 gdi_deps_found = gdi_deps_found and dep.found() 274 gdi_uniscribe_deps += dep 275 endforeach 276 277 if gdi_deps_found 278 conf.set('HAVE_UNISCRIBE', 1) 279 conf.set('HAVE_GDI', 1) 280 endif 281endif 282 283# DirectWrite (Windows) 284if host_machine.system() == 'windows' and not get_option('directwrite').disabled() 285 if get_option('directwrite').enabled() and not cpp.has_header('dwrite_1.h') 286 error('DirectWrite was enabled explicitly, but required header is missing.') 287 endif 288 289 conf.set('HAVE_DIRECTWRITE', 1) 290endif 291 292# CoreText (macOS) 293coretext_deps = [] 294if host_machine.system() == 'darwin' and not get_option('coretext').disabled() 295 app_services_dep = dependency('appleframeworks', modules: ['ApplicationServices'], required: false) 296 if cpp.has_type('CTFontRef', prefix: '#include <ApplicationServices/ApplicationServices.h>', dependencies: app_services_dep) 297 coretext_deps += [app_services_dep] 298 conf.set('HAVE_CORETEXT', 1) 299 # On iOS CoreText and CoreGraphics are stand-alone frameworks 300 # Check for a different symbol to avoid getting cached result 301 else 302 coretext_dep = dependency('appleframeworks', modules: ['CoreText'], required: false) 303 coregraphics_dep = dependency('appleframeworks', modules: ['CoreGraphics'], required: false) 304 corefoundation_dep = dependency('appleframeworks', modules: ['CoreFoundation'], required: false) 305 if cpp.has_type('CTRunRef', prefix: '#include <CoreText/CoreText.h>', dependencies: [coretext_dep, coregraphics_dep, corefoundation_dep]) 306 coretext_deps += [coretext_dep, coregraphics_dep, corefoundation_dep] 307 conf.set('HAVE_CORETEXT', 1) 308 elif get_option('coretext').enabled() 309 error('CoreText was enabled explicitly, but required headers or frameworks are missing.') 310 endif 311 endif 312endif 313 314# threads 315thread_dep = null_dep 316if host_machine.system() != 'windows' 317 thread_dep = dependency('threads', required: false) 318 319 if thread_dep.found() 320 conf.set('HAVE_PTHREAD', 1) 321 endif 322endif 323 324conf.set_quoted('PACKAGE_NAME', 'HarfBuzz') 325conf.set_quoted('PACKAGE_VERSION', meson.project_version()) 326 327foreach check : check_headers 328 name = check[0] 329 330 if cpp.has_header(name) 331 conf.set('HAVE_@0@'.format(name.to_upper().underscorify()), 1) 332 endif 333endforeach 334 335harfbuzz_extra_deps = [] 336foreach check : check_funcs 337 name = check[0] 338 opts = check.get(1, {}) 339 link_withs = opts.get('link_with', []) 340 check_deps = opts.get('deps', []) 341 extra_deps = [] 342 found = true 343 344 # First try without linking 345 found = cpp.has_function(name, dependencies: check_deps) 346 347 if not found and link_withs.length() > 0 348 found = true 349 350 foreach link_with : link_withs 351 dep = cpp.find_library(link_with, required: false) 352 if dep.found() 353 extra_deps += dep 354 else 355 found = false 356 endif 357 endforeach 358 359 if found 360 found = cpp.has_function(name, dependencies: check_deps + extra_deps) 361 endif 362 endif 363 364 if found 365 harfbuzz_extra_deps += extra_deps 366 conf.set('HAVE_@0@'.format(name.to_upper()), 1) 367 endif 368endforeach 369 370subdir('src') 371subdir('util') 372 373if not get_option('tests').disabled() 374 subdir('test') 375endif 376 377if not get_option('benchmark').disabled() 378 subdir('perf') 379endif 380 381if not get_option('docs').disabled() 382 subdir('docs') 383endif 384 385configure_file(output: 'config.h', configuration: conf) 386 387build_summary = { 388 'Directories': 389 {'prefix': get_option('prefix'), 390 'bindir': get_option('bindir'), 391 'libdir': get_option('libdir'), 392 'includedir': get_option('includedir'), 393 'datadir': get_option('datadir'), 394 }, 395 'Unicode callbacks (you want at least one)': 396 {'Builtin': true, 397 'Glib': conf.get('HAVE_GLIB', 0) == 1, 398 'ICU': conf.get('HAVE_ICU', 0) == 1, 399 }, 400 'Font callbacks (the more the merrier)': 401 {'FreeType': conf.get('HAVE_FREETYPE', 0) == 1, 402 }, 403 'Dependencies used for command-line utilities': 404 {'Cairo': conf.get('HAVE_CAIRO', 0) == 1, 405 'Chafa': conf.get('HAVE_CHAFA', 0) == 1, 406 }, 407 'Additional shapers': 408 {'Graphite2': conf.get('HAVE_GRAPHITE2', 0) == 1, 409 }, 410 'Platform shapers (not normally needed)': 411 {'CoreText': conf.get('HAVE_CORETEXT', 0) == 1, 412 'DirectWrite': conf.get('HAVE_DIRECTWRITE', 0) == 1, 413 'GDI/Uniscribe': (conf.get('HAVE_GDI', 0) == 1) and (conf.get('HAVE_UNISCRIBE', 0) == 1), 414 }, 415 'Other features': 416 {'Documentation': conf.get('HAVE_GTK_DOC', 0) == 1, 417 'GObject bindings': conf.get('HAVE_GOBJECT', 0) == 1, 418 'Introspection': conf.get('HAVE_INTROSPECTION', 0) == 1, 419 'Experimental APIs': conf.get('HB_EXPERIMENTAL_API', 0) == 1, 420 }, 421 'Testing': 422 {'Tests': get_option('tests').enabled(), 423 'Benchmark': get_option('benchmark').enabled(), 424 }, 425} 426foreach section_title, section : build_summary 427 summary(section, bool_yn: true, section: section_title) 428endforeach 429