1project('fontconfig', 'c', 2 version: '2.15.0', 3 meson_version : '>= 0.60.0', 4 default_options: [ 'buildtype=debugoptimized'], 5) 6 7fc_version = meson.project_version() 8version_arr = fc_version.split('.') 9fc_version_major = version_arr[0].to_int() 10fc_version_minor = version_arr[1].to_int() 11fc_version_micro = version_arr[2].to_int() 12 13# Try and maintain compatibility with the previous libtool versioning 14# (this is a bit of a hack, but it should work fine for our case where 15# API is added, in which case LT_AGE and LIBT_CURRENT are both increased) 16soversion = fc_version_major - 1 17curversion = fc_version_minor - 1 18libversion = '@0@.@1@.0'.format(soversion, curversion) 19defversion = '@0@.@1@'.format(curversion, fc_version_micro) 20osxversion = curversion + 1 21 22freetype_req = '>= 21.0.15' 23freetype_req_cmake = '>= 2.8.1' 24 25cc = meson.get_compiler('c') 26 27 28freetype_dep = dependency('freetype2', method: 'pkg-config', version: freetype_req, required: false) 29 30# Give another shot using CMake 31if not freetype_dep.found() 32 freetype_dep = dependency('freetype', method: 'cmake', version: freetype_req_cmake, 33 fallback: ['freetype2', 'freetype_dep'], default_options: 'werror=false') 34endif 35 36# Linking expat should not be so difficult... see: https://github.com/mesonbuild/meson/issues/10516 37expat_dep = dependency('expat', required: false) 38if not expat_dep.found() 39 expat_dep = cc.find_library('expat', required : false) 40 if not expat_dep.found() 41 expat_dep = dependency('expat', method: 'system', fallback: ['expat', 'expat_dep']) 42 endif 43endif 44 45i18n = import('i18n') 46pkgmod = import('pkgconfig') 47python3 = import('python').find_installation() 48 49check_headers = [ 50 ['dirent.h'], 51 ['fcntl.h'], 52 ['stdlib.h'], 53 ['string.h'], 54 ['unistd.h'], 55 ['sys/statvfs.h'], 56 ['sys/vfs.h'], 57 ['sys/statfs.h'], 58 ['sys/param.h'], 59 ['sys/mount.h'], 60] 61 62check_funcs = [ 63 ['link'], 64 ['mkstemp'], 65 ['mkostemp'], 66 ['_mktemp_s'], 67 ['mkdtemp'], 68 ['getopt'], 69 ['getopt_long'], 70 ['getprogname'], 71 ['getexecname'], 72 ['rand'], 73 ['random'], 74 ['lrand48'], 75 ['random_r'], 76 ['rand_r'], 77 ['readlink'], 78 ['fstatvfs'], 79 ['fstatfs'], 80 ['lstat'], 81 ['mmap'], 82 ['vprintf'], 83] 84 85check_freetype_funcs = [ 86 ['FT_Get_BDF_Property', {'dependencies': freetype_dep}], 87 ['FT_Get_PS_Font_Info', {'dependencies': freetype_dep}], 88 ['FT_Has_PS_Glyph_Names', {'dependencies': freetype_dep}], 89 ['FT_Get_X11_Font_Format', {'dependencies': freetype_dep}], 90 ['FT_Done_MM_Var', {'dependencies': freetype_dep}], 91] 92 93check_header_symbols = [ 94 ['posix_fadvise', 'fcntl.h'] 95] 96 97check_struct_members = [ 98 ['struct statvfs', 'f_basetype', ['sys/statvfs.h']], 99 ['struct statvfs', 'f_fstypename', ['sys/statvfs.']], 100 ['struct statfs', 'f_flags', []], 101 ['struct statfs', 'f_fstypename', []], 102 ['struct dirent', 'd_type', ['sys/types.h', 'dirent.h']], 103] 104 105check_sizeofs = [ 106 ['void *', {'conf-name': 'SIZEOF_VOID_P'}], 107] 108 109check_alignofs = [ 110 ['void *', {'conf-name': 'ALIGNOF_VOID_P'}], 111 ['double'], 112] 113 114add_project_arguments('-DHAVE_CONFIG_H', language: 'c') 115 116c_args = [] 117 118conf = configuration_data() 119deps = [freetype_dep, expat_dep] 120incbase = include_directories('.') 121 122# We cannot try compiling against an internal dependency 123if freetype_dep.type_name() == 'internal' 124 foreach func: check_freetype_funcs 125 name = func[0] 126 conf.set('HAVE_@0@'.format(name.to_upper()), 1) 127 endforeach 128else 129 check_funcs += check_freetype_funcs 130endif 131 132foreach check : check_headers 133 name = check[0] 134 135 if cc.has_header(name) 136 conf.set('HAVE_@0@'.format(name.to_upper().underscorify()), 1) 137 endif 138endforeach 139 140foreach check : check_funcs 141 name = check[0] 142 opts = check.length() > 1 ? check[1] : {} 143 extra_deps = opts.get('dependencies', []) 144 145 if cc.has_function(name, dependencies: extra_deps) 146 conf.set('HAVE_@0@'.format(name.to_upper()), 1) 147 endif 148endforeach 149 150foreach check : check_header_symbols 151 name = check[0] 152 header = check[1] 153 154 if cc.has_header_symbol(header, name) 155 conf.set('HAVE_@0@'.format(name.to_upper()), 1) 156 endif 157endforeach 158 159foreach check : check_struct_members 160 struct_name = check[0] 161 member_name = check[1] 162 headers = check[2] 163 164 prefix = '' 165 166 foreach header : headers 167 prefix += '#include <@0@>\n'.format(header) 168 endforeach 169 170 if cc.has_member(struct_name, member_name, prefix: prefix) 171 conf.set('HAVE_@0@_@1@'.format(struct_name, member_name).to_upper().underscorify(), 1) 172 endif 173endforeach 174 175foreach check : check_sizeofs 176 type = check[0] 177 opts = check.length() > 1 ? check[1] : {} 178 179 conf_name = opts.get('conf-name', 'SIZEOF_@0@'.format(type.to_upper())) 180 181 conf.set(conf_name, cc.sizeof(type)) 182endforeach 183 184foreach check : check_alignofs 185 type = check[0] 186 opts = check.length() > 1 ? check[1] : {} 187 188 conf_name = opts.get('conf-name', 'ALIGNOF_@0@'.format(type.to_upper())) 189 190 conf.set(conf_name, cc.alignment(type)) 191endforeach 192 193if cc.compiles(files('meson-cc-tests/flexible-array-member-test.c')) 194 conf.set('FLEXIBLE_ARRAY_MEMBER', true) 195else 196 conf.set('FLEXIBLE_ARRAY_MEMBER', 1) 197endif 198 199if cc.links(files('meson-cc-tests/stdatomic-primitives-test.c'), name: 'stdatomic.h atomics') 200 conf.set('HAVE_STDATOMIC_PRIMITIVES', 1) 201endif 202 203if cc.links(files('meson-cc-tests/intel-atomic-primitives-test.c'), name: 'Intel atomics') 204 conf.set('HAVE_INTEL_ATOMIC_PRIMITIVES', 1) 205endif 206 207if cc.links(files('meson-cc-tests/solaris-atomic-operations.c'), name: 'Solaris atomic ops') 208 conf.set('HAVE_SOLARIS_ATOMIC_OPS', 1) 209endif 210 211 212# Check iconv support 213iconv_dep = [] 214found_iconv = 0 215if host_machine.system() != 'windows' 216 iconv_dep = dependency('iconv', required: get_option('iconv')) 217 found_iconv = iconv_dep.found().to_int() 218else 219 if get_option('iconv').enabled() 220 warning('-Diconv was set but this is not functional on Windows.') 221 endif 222endif 223conf.set('USE_ICONV', found_iconv) 224deps += [iconv_dep] 225 226prefix = get_option('prefix') 227 228fonts_conf = configuration_data() 229 230default_fonts_dirs = get_option('default-fonts-dirs') 231if default_fonts_dirs == ['yes'] 232 if host_machine.system() == 'windows' 233 fc_fonts_paths = ['WINDOWSFONTDIR', 'WINDOWSUSERFONTDIR'] 234 elif host_machine.system() == 'darwin' 235 fc_fonts_paths = ['/System/Library/Fonts', '/Library/Fonts', '~/Library/Fonts', '/System/Library/Assets/com_apple_MobileAsset_Font3', '/System/Library/Assets/com_apple_MobileAsset_Font4'] 236 else 237 fc_fonts_paths = ['/usr/share/fonts', '/usr/local/share/fonts'] 238 endif 239else 240 fc_fonts_paths = default_fonts_dirs 241endif 242xml_path = '' 243escaped_xml_path = '' 244foreach p : fc_fonts_paths 245 s = '\t<dir>' + p + '</dir>\n' 246 xml_path += s 247 # No substitution method for string 248 s = '\\t<dir>' + p + '</dir>\\n' 249 escaped_xml_path += s 250endforeach 251conf.set_quoted('FC_DEFAULT_FONTS', escaped_xml_path) 252fonts_conf.set('FC_DEFAULT_FONTS', xml_path) 253 254# Add more fonts if available. By default, add only the directories 255# with outline fonts; those with bitmaps can be added as desired in 256# local.conf or ~/.fonts.conf 257fc_add_fonts = [] 258additional_fonts_dirs = get_option('additional-fonts-dirs') 259if additional_fonts_dirs == ['yes'] 260 fs = import('fs') 261 foreach dir : ['/usr/X11R6/lib/X11', '/usr/X11/lib/X11', '/usr/lib/X11'] 262 if fs.is_dir(dir / 'fonts') 263 fc_add_fonts += [dir / 'fonts'] 264 endif 265 endforeach 266elif additional_fonts_dirs == ['no'] 267 # nothing to do 268else 269 fc_add_fonts = additional_fonts_dirs 270endif 271xml_path = '' 272escaped_xml_path = '' 273foreach p : fc_add_fonts 274 s = '\t<dir>' + p + '</dir>\n' 275 xml_path += s 276 # No substitution method for string 277 s = '\\t<dir>' + p + '</dir>\\n' 278 escaped_xml_path += s 279endforeach 280conf.set_quoted('FC_FONTPATH', escaped_xml_path) 281fonts_conf.set('FC_FONTPATH', xml_path) 282 283fc_cachedir = get_option('cache-dir') 284if fc_cachedir in ['yes', 'no', 'default'] 285 if host_machine.system() == 'windows' 286 fc_cachedir = 'LOCAL_APPDATA_FONTCONFIG_CACHE' 287 else 288 fc_cachedir = join_paths(prefix, get_option('localstatedir'), 'cache', meson.project_name()) 289 endif 290endif 291 292if host_machine.system() != 'windows' 293 thread_dep = dependency('threads') 294 conf.set('HAVE_PTHREAD', 1) 295 deps += [thread_dep] 296endif 297 298fc_templatedir = get_option('template-dir') 299if fc_templatedir in ['default', 'yes', 'no'] 300 fc_templatedir = prefix / get_option('datadir') / 'fontconfig/conf.avail' 301endif 302 303fc_baseconfigdir = get_option('baseconfig-dir') 304if fc_baseconfigdir in ['default', 'yes', 'no'] 305 fc_baseconfigdir = prefix / get_option('sysconfdir') / 'fonts' 306endif 307 308fc_configdir = get_option('config-dir') 309if fc_configdir in ['default', 'yes', 'no'] 310 fc_configdir = fc_baseconfigdir / 'conf.d' 311endif 312 313fc_xmldir = get_option('xml-dir') 314if fc_xmldir in ['default', 'yes', 'no'] 315 fc_xmldir = prefix / get_option('datadir') / 'xml/fontconfig' 316endif 317 318conf.set_quoted('CONFIGDIR', fc_configdir) 319conf.set_quoted('FC_CACHEDIR', fc_cachedir) 320conf.set_quoted('FC_TEMPLATEDIR', fc_templatedir) 321conf.set_quoted('FONTCONFIG_PATH', fc_baseconfigdir) 322conf.set_quoted('FC_FONTPATH', '') 323 324fonts_conf.set('FC_FONTPATH', '') 325fonts_conf.set('FC_CACHEDIR', fc_cachedir) 326fonts_conf.set('CONFIGDIR', fc_configdir) 327# strip off fc_baseconfigdir prefix if that is the prefix 328if fc_configdir.startswith(fc_baseconfigdir + '/') 329 fonts_conf.set('CONFIGDIR', fc_configdir.split(fc_baseconfigdir + '/')[1]) 330endif 331 332gperf = find_program('gperf', required: false) 333gperf_len_type = '' 334 335if gperf.found() 336 gperf_test_format = ''' 337 #include <string.h> 338 const char * in_word_set(const char *, @0@); 339 @1@ 340 ''' 341 gperf_snippet = run_command(gperf, '-L', 'ANSI-C', files('meson-cc-tests/gperf.txt'), 342 check: true).stdout() 343 344 foreach type : ['size_t', 'unsigned'] 345 if cc.compiles(gperf_test_format.format(type, gperf_snippet)) 346 gperf_len_type = type 347 break 348 endif 349 endforeach 350 351 if gperf_len_type == '' 352 error('unable to determine gperf len type') 353 endif 354else 355 # Fallback to subproject 356 gperf = find_program('gperf') 357 # assume if we are compiling from the wrap, the size is just size_t 358 gperf_len_type = 'size_t' 359endif 360 361message('gperf len type is @0@'.format(gperf_len_type)) 362 363conf.set('FC_GPERF_SIZE_T', gperf_len_type, 364 description : 'The type of gperf "len" parameter') 365 366conf.set('_GNU_SOURCE', true) 367 368conf.set_quoted('GETTEXT_PACKAGE', meson.project_name()) 369 370incsrc = include_directories('src') 371 372# We assume stdint.h is available 373foreach t : ['uint64_t', 'int32_t', 'uintptr_t', 'intptr_t'] 374 if not cc.has_type(t, prefix: '#include <stdint.h>') 375 error('Sanity check failed: type @0@ not provided via stdint.h'.format(t)) 376 endif 377endforeach 378 379fcstdint_h = configure_file( 380 input: 'src/fcstdint.h.in', 381 output: 'fcstdint.h', 382 copy: true) 383 384makealias = files('src/makealias.py')[0] 385 386alias_headers = custom_target('alias_headers', 387 output: ['fcalias.h', 'fcaliastail.h'], 388 input: ['fontconfig/fontconfig.h', 'src/fcdeprecate.h', 'fontconfig/fcprivate.h'], 389 command: [python3, makealias, join_paths(meson.current_source_dir(), 'src'), '@OUTPUT@', '@INPUT@'], 390 ) 391 392ft_alias_headers = custom_target('ft_alias_headers', 393 output: ['fcftalias.h', 'fcftaliastail.h'], 394 input: ['fontconfig/fcfreetype.h'], 395 command: [python3, makealias, join_paths(meson.current_source_dir(), 'src'), '@OUTPUT@', '@INPUT@'] 396 ) 397 398tools_man_pages = [] 399 400# Do not reorder 401subdir('fc-case') 402subdir('fc-lang') 403subdir('src') 404 405if not get_option('tools').disabled() 406 subdir('fc-cache') 407 subdir('fc-cat') 408 subdir('fc-conflist') 409 subdir('fc-list') 410 subdir('fc-match') 411 subdir('fc-pattern') 412 subdir('fc-query') 413 subdir('fc-scan') 414 subdir('fc-validate') 415endif 416 417if not get_option('tests').disabled() 418 subdir('test') 419endif 420 421subdir('conf.d') 422subdir('its') 423 424# xgettext is optional (on Windows for instance) 425if find_program('xgettext', required : get_option('nls')).found() 426 subdir('po') 427 subdir('po-conf') 428endif 429 430if not get_option('doc').disabled() 431 subdir('doc') 432endif 433 434configure_file(output: 'config.h', configuration: conf) 435 436configure_file(output: 'fonts.conf', 437 input: 'fonts.conf.in', 438 configuration: fonts_conf, 439 install_dir: fc_baseconfigdir, 440 install: true) 441 442install_data('fonts.dtd', 443 install_dir: join_paths(get_option('prefix'), get_option('datadir'), 'xml/fontconfig') 444 ) 445 446fc_headers = [ 447 'fontconfig/fontconfig.h', 448 'fontconfig/fcfreetype.h', 449 'fontconfig/fcprivate.h', 450] 451 452install_headers(fc_headers, subdir: meson.project_name()) 453 454# Summary 455doc_targets = get_variable('doc_targets', []) 456 457summary({ 458 'Documentation': (doc_targets.length() > 0 ? doc_targets : false), 459 'NLS': not get_option('nls').disabled(), 460 'Tests': not get_option('tests').disabled(), 461 'Tools': not get_option('tools').disabled(), 462 'iconv': found_iconv == 1, 463}, section: 'General', bool_yn: true, list_sep: ', ') 464summary({ 465 'Hinting': preferred_hinting, 466 'Font directories': fc_fonts_paths, 467 'Additional font directories': fc_add_fonts, 468}, section: 'Defaults', bool_yn: true, list_sep: ', ') 469summary({ 470 'Cache directory': fc_cachedir, 471 'Template directory': fc_templatedir, 472 'Base config directory': fc_baseconfigdir, 473 'Config directory': fc_configdir, 474 'XML directory': fc_xmldir, 475}, section: 'Paths', bool_yn: true, list_sep: ', ') 476