1project('pango', 'c', 'cpp',
2        version: '1.48.11',
3        license: 'LGPLv2.1+',
4        default_options: [
5          'buildtype=debugoptimized',
6          'warning_level=1',
7          # We only need c99, but glib needs GNU-specific features
8          # https://github.com/mesonbuild/meson/issues/2289
9          'c_std=gnu99',
10        ],
11        meson_version : '>= 0.55.3')
12
13add_project_arguments([ '-D_POSIX_C_SOURCE=200809L', '-D_POSIX_THREAD_SAFE_FUNCTIONS', '-D_GNU_SOURCE', ], language: 'c')
14
15pango_prefix = get_option('prefix')
16pango_libdir = join_paths(pango_prefix, get_option('libdir'))
17pango_sysconfdir = join_paths(pango_prefix, get_option('sysconfdir'))
18pango_includedir = join_paths(pango_prefix, get_option('includedir'))
19pango_datadir = join_paths(pango_prefix, get_option('datadir'))
20pango_libexecdir = join_paths(pango_prefix, get_option('libexecdir'))
21
22version = meson.project_version().split('.')
23pango_major_version = version[0].to_int()
24pango_minor_version = version[1].to_int()
25pango_micro_version = version[2].to_int()
26
27pango_interface_age = pango_minor_version.is_odd() ? 0 : pango_micro_version
28pango_binary_age = pango_minor_version * 100 + pango_micro_version
29
30pango_api_version = '@0@.0'.format(pango_major_version)
31pango_api_name = 'pango-@0@'.format(pango_api_version)
32pango_api_path = join_paths(pango_api_name, 'pango')
33
34pango_conf = configuration_data()
35
36pango_conf.set('PANGO_BINARY_AGE', pango_binary_age)
37pango_conf.set('PANGO_INTERFACE_AGE', pango_interface_age)
38pango_conf.set('PANGO_VERSION_MAJOR', pango_major_version)
39pango_conf.set('PANGO_VERSION_MINOR', pango_minor_version)
40pango_conf.set('PANGO_VERSION_MICRO', pango_micro_version)
41
42# Maintain version scheme with libtool
43pango_soversion = 0
44pango_libversion = '@0@.@1@.@2@'.format(pango_soversion, (pango_binary_age - pango_interface_age), pango_interface_age)
45osx_current = pango_binary_age - pango_interface_age + 1
46pango_osxversion = [osx_current, '@0@.@1@.0'.format(osx_current, pango_interface_age)]
47
48cc = meson.get_compiler('c')
49host_system = host_machine.system()
50
51# Compiler and linker flags
52common_cflags = []
53common_cppflags = []
54common_ldflags = []
55
56# Add more compiler warnings to the default set
57if cc.get_id() == 'msvc'
58  # Compiler options taken from msvc_recommended_pragmas.h
59  # in GLib, based on _Win32_Programming_ by Rector and Newcomer
60  test_cflags = ['-FImsvc_recommended_pragmas.h', '-utf-8']
61  add_project_arguments(cc.get_supported_arguments(test_cflags), language: 'c')
62  test_c_only_flags = []
63elif cc.get_id() == 'gcc' or cc.get_id() == 'clang'
64  test_c_only_flags = [
65    '-Wimplicit-function-declaration',
66    '-Wstrict-prototypes',
67    '-Wmissing-prototypes',
68    '-Wnested-externs',
69    '-Wold-style-definition',
70    '-Wno-int-conversion',
71    '-Wno-discarded-qualifiers',
72    '-Werror=implicit',
73    '-Werror=pointer-to-int-cast',
74  ]
75
76  test_cflags = test_c_only_flags + [
77    '-fno-strict-aliasing',
78    '-Wpointer-arith',
79    '-Wmissing-declarations',
80    '-Wformat=2',
81    '-Wformat-nonliteral',
82    '-Wformat-security',
83    '-Wunused',
84    '-Wcast-align',
85    '-Wmissing-noreturn',
86    '-Wmissing-format-attribute',
87    '-Wmissing-include-dirs',
88    '-Wlogical-op',
89    '-Wno-uninitialized',
90    '-Wno-shadow',
91    '-Werror=implicit-fallthrough',
92    '-Werror=nonnull',
93    '-Werror=init-self',
94    '-Werror=main',
95    '-Werror=missing-braces',
96    '-Werror=sequence-point',
97    '-Werror=return-type',
98    '-Werror=trigraphs',
99    '-Werror=array-bounds',
100    '-Werror=write-strings',
101    '-Werror=address',
102    '-Werror=int-to-pointer-cast',
103    '-Werror=empty-body',
104    '-Werror=write-strings',
105    '-Werror=unused-but-set-variable',
106    '-Wundef', # FIXME: https://bugzilla.gnome.org/show_bug.cgi?id=792481
107  ]
108
109  if host_system == 'windows'
110    test_cflags += [ '-mms-bitfields' ]
111  else
112    test_cflags += [ '-Werror=redundant-decls' ]
113  endif
114else
115  test_cflags = []
116  test_c_only_flags = []
117endif
118
119# Symbol visibility
120if get_option('default_library') != 'static'
121  if host_system == 'windows'
122    pango_conf.set('DLL_EXPORT', true)
123    pango_conf.set('_PANGO_EXTERN', '__declspec(dllexport) extern')
124    if cc.get_id() != 'msvc'
125      test_cflags += ['-fvisibility=hidden']
126    endif
127  else
128    pango_conf.set('_PANGO_EXTERN', '__attribute__((visibility("default"))) extern')
129    test_cflags += ['-fvisibility=hidden']
130  endif
131endif
132
133# Check all compiler flags
134common_cflags += cc.get_supported_arguments(test_cflags)
135
136# Isolate the C++ compiler flags
137foreach cflag: common_cflags
138  if not test_c_only_flags.contains(cflag)
139    common_cppflags += [ cflag ]
140  endif
141endforeach
142
143# Linker flags
144if host_machine.system() == 'linux'
145  common_ldflags += cc.get_supported_link_arguments([ '-Wl,-Bsymbolic', '-Wl,-z,relro', '-Wl,-z,now', ])
146endif
147
148# Functions
149checked_funcs = [
150  'sysconf',
151  'getpagesize',
152  'flockfile',
153  'strtok_r',
154]
155
156foreach f: checked_funcs
157  if cc.has_function(f)
158    pango_conf.set('HAVE_' + f.underscorify().to_upper(), 1)
159  endif
160endforeach
161
162# Headers
163checked_headers = [
164  'unistd.h',
165  'sys/mman.h',
166  'dirent.h',
167]
168
169foreach h: checked_headers
170  if cc.has_header(h)
171    pango_conf.set('HAVE_' + h.underscorify().to_upper(), 1)
172  endif
173endforeach
174
175# Use debug/optimization flags to determine whether to enable debug or disable
176# cast checks
177pango_debug_cflags = []
178if get_option('debug')
179  pango_debug_cflags = [ '-DPANGO_ENABLE_DEBUG' ]
180  message('Enabling various debug infrastructure')
181elif get_option('optimization') in ['2', '3', 's']
182  pango_debug_cflags = [ '-DG_DISABLE_CAST_CHECKS' ]
183  message('Disabling cast checks')
184  # TODO: We may want a configuration argument to add `G_DISABLE_CHECKS`
185  # and `G_DISABLE_ASSERT` from the build, for specific build environments.
186  # On the other hand, those who need these symbols can inject them in their
187  # build as well.
188endif
189
190# Dependencies
191pango_deps = []
192
193glib_req_version = '>= 2.62'
194fribidi_req_version = '>= 1.0.6'
195libthai_req_version = '>= 0.1.9'
196harfbuzz_req_version = '>= 2.2.0'
197fontconfig_req_version = '>= 2.11.91'
198xft_req_version = '>= 2.0.0'
199cairo_req_version = '>= 1.12.10'
200
201# libm
202mathlib_dep = cc.find_library('m', required: false)
203pango_deps += mathlib_dep
204
205# gobject
206glib_dep = dependency('glib-2.0', version: glib_req_version,
207                      fallback: ['glib', 'libglib_dep'])
208gobject_dep = dependency('gobject-2.0', version: glib_req_version,
209                         fallback: ['glib', 'libgobject_dep'])
210gio_dep = dependency('gio-2.0', version: glib_req_version,
211                         fallback: ['glib', 'libgio_dep'])
212pango_deps += [glib_dep, gobject_dep, gio_dep]
213
214fribidi_dep = dependency('fribidi', version: fribidi_req_version,
215                         fallback: ['fribidi', 'libfribidi_dep'],
216                         default_options: ['docs=false'])
217pango_deps += fribidi_dep
218
219thai_dep = dependency('libthai', version: libthai_req_version, required: get_option('libthai'))
220if thai_dep.found()
221  pango_conf.set('HAVE_LIBTHAI', 1)
222  pango_deps += thai_dep
223
224  if cc.has_function('th_brk_find_breaks', dependencies: thai_dep)
225    pango_conf.set('HAVE_TH_BRK_FIND_BREAKS', 1)
226  endif
227endif
228
229# These are for the various .pc files so that things will link
230# properly, depending on whether we have the pkg-config files
231# for those non-GNOME dependencies, or when we find them manually
232# for MSVC builds, as their MSVC build systems do not generate
233# pkg-config files for them
234cairo_pc = ''
235cairo_lib = ''
236harfbuzz_pc=''
237freetype2_pc=''
238fontconfig_pc=''
239harfbuzz_lib=''
240fontconfig_lib=''
241
242harfbuzz_dep = dependency('harfbuzz', version: harfbuzz_req_version, required: false)
243if harfbuzz_dep.found()
244  harfbuzz_pc = 'harfbuzz'
245else
246  if cc.get_id() == 'msvc' and cc.has_header('hb.h')
247    # The CMake build files for HarfBuzz (which is used for MSVC builds) do not
248    # generate pkg-config files, so look for harfbuzz.lib.  Ensure that we
249    # we look for HarfBuzz 2.0.0 or later.
250    harfbuzz_lib = cc.find_library('harfbuzz', required: false)
251    if harfbuzz_lib.found()
252      if cc.has_function('hb_ot_tags_from_script_and_language', dependencies: harfbuzz_lib)
253        harfbuzz_dep = harfbuzz_lib
254      endif
255    endif
256  endif
257endif
258
259# Remove when Meson acquires ability to declare deps declaratively, or
260# when finding dependencies via CMake files is fixed.
261if not harfbuzz_dep.found()
262  harfbuzz_dep = dependency('harfbuzz', version: harfbuzz_req_version,
263                            fallback: ['harfbuzz', 'libharfbuzz_dep'],
264                            default_options: ['coretext=enabled'])
265endif
266
267if not harfbuzz_dep.found()
268  error('harfbuzz not found')
269endif
270
271pango_deps += harfbuzz_dep
272
273# If option is 'auto' or 'enabled' it is not required to find fontconfig on the
274# system because a fallback is done at the end. Override 'disabled' option on
275# platforms that requires it.
276fontconfig_option = get_option('fontconfig')
277fontconfig_required = host_system not in ['windows', 'darwin']
278if not fontconfig_option.disabled() or fontconfig_required
279  fontconfig_option = false
280endif
281
282fontconfig_dep = dependency('fontconfig', version: fontconfig_req_version, required: fontconfig_option)
283if fontconfig_dep.found()
284  fontconfig_pc = 'fontconfig'
285else
286  if cc.get_id() == 'msvc' and cc.has_header('fontconfig/fontconfig.h')
287    # Look for the Visual Studio-style import library if FontConfig's .pc file cannot be
288    # found on Visual Studio
289    fontconfig_dep = cc.find_library('fontconfig', required: fontconfig_option)
290    if fontconfig_dep.found()
291      fontconfig_lib = '-lfontconfig'
292    endif
293  endif
294endif
295
296# Do the fallback now if fontconfig has not been found on the system. Override
297# user option on platforms that always require fontconfig.
298fontconfig_option = fontconfig_required ? true : get_option('fontconfig')
299if not fontconfig_dep.found()
300  fontconfig_dep = dependency('fontconfig', version: fontconfig_req_version,
301                              fallback: ['fontconfig', 'fontconfig_dep'],
302                              required: fontconfig_option)
303endif
304
305if fontconfig_dep.found()
306  pango_deps += fontconfig_dep
307
308  if fontconfig_dep.type_name() != 'library'
309    if fontconfig_dep.version().version_compare('>=2.12.92')
310      pango_conf.set('HAVE_FCWEIGHTFROMOPENTYPEDOUBLE', 1)
311    endif
312  elif cc.has_function('FcWeightFromOpenTypeDouble', dependencies: fontconfig_dep)
313    pango_conf.set('HAVE_FCWEIGHTFROMOPENTYPEDOUBLE', 1)
314  endif
315endif
316
317if pango_conf.has('HAVE_FCWEIGHTFROMOPENTYPEDOUBLE')
318  res = 'YES'
319else
320  res = 'NO'
321endif
322message('fontconfig has FcWeightFromOpenTypeDouble: ' + res)
323
324# If option is 'auto' or 'enabled' it is not required to find freetype2 on the
325# system because a fallback is done at the end. Override 'disabled' option on
326# if fontconfig has been found.
327freetype_option = get_option('freetype')
328freetype_required = fontconfig_dep.found()
329if not freetype_option.disabled() or freetype_required
330  freetype_option = false
331endif
332
333# The first version of freetype with a pkg-config file is 2.1.5
334freetype_dep = dependency('freetype2', required: freetype_option)
335
336if freetype_dep.found()
337  freetype2_pc = 'freetype2'
338else
339  if cc.get_id() == 'msvc' and cc.has_header('ft2build.h')
340    foreach ft2_lib: ['freetype', 'freetypemt']
341      if not freetype_dep.found()
342        freetype_dep = cc.find_library(ft2_lib, required: freetype_option)
343        if freetype_dep.found()
344          freetype2_lib = '-l@0@'.format(ft2_lib)
345        endif
346      endif
347    endforeach
348  endif
349endif
350
351# Do the fallback now if freetype2 has not been found on the system.
352freetype_option = freetype_required ? true : get_option('freetype')
353if not freetype_dep.found()
354  freetype_dep = dependency('freetype2', required: freetype_option,
355                            fallback: ['freetype2', 'freetype_dep'])
356endif
357
358# To build pangoft2, we need HarfBuzz, FontConfig and FreeType
359build_pangoft2 = harfbuzz_dep.found() and fontconfig_dep.found() and freetype_dep.found()
360if build_pangoft2
361  pango_conf.set('HAVE_FREETYPE', 1)
362  pango_deps += freetype_dep
363endif
364
365xft_dep = dependency('xft', version: xft_req_version, required: get_option('xft'))
366if xft_dep.found() and fontconfig_dep.found() and freetype_dep.found()
367  pango_conf.set('HAVE_XFT', 1)
368  pango_deps += dependency('xrender', required: false)
369  pango_deps += xft_dep
370endif
371
372if host_system == 'darwin'
373  has_core_text = cc.links('''#include <Carbon/Carbon.h>
374                              int main (void) {
375                                CTGetCoreTextVersion ();
376                                return 0;
377                              }''',
378                           name: 'CoreText availability',
379                           dependencies: dependency('appleframeworks', modules: 'ApplicationServices'))
380  if has_core_text
381    pango_conf.set('HAVE_CORE_TEXT', 1)
382  endif
383
384  pango_deps += dependency('appleframeworks', modules: [ 'CoreFoundation', 'ApplicationServices' ])
385endif
386
387# If option is 'auto' or 'enabled' it is not required to find cairo on the
388# system because a fallback is done at the end.
389cairo_option = get_option('cairo')
390if not cairo_option.disabled()
391  cairo_option = false
392endif
393
394cairo_found_type = ''
395cairo_dep = dependency('cairo', version: cairo_req_version, required: cairo_option)
396
397if cairo_dep.found()
398  cairo_found_type = cairo_dep.type_name()
399else
400  if cc.get_id() == 'msvc' and cc.has_header('cairo.h')
401    cairo_dep = cc.find_library('cairo', required: cairo_option)
402    cairo_found_type = 'library'
403  endif
404endif
405
406# Remove once Meson gains capability to declare dependencies
407# in a declarative way
408if not cairo_dep.found()
409  cairo_dep = dependency('cairo', version: cairo_req_version,
410                         fallback: ['cairo', 'libcairo_dep'], required: get_option('cairo'),
411                         default_options: ['freetype=enabled', 'fontconfig=enabled'])
412  cairo_found_type = cairo_dep.type_name()
413endif
414
415pango_font_backends = []
416pango_cairo_backends = []
417
418if ['pkgconfig', 'internal'].contains(cairo_found_type)
419  # Check the following Cairo font backends
420  # - dependency
421  # - version
422  # - define
423  # - backend name
424  # Note that Cairo can be built with FreeType but without FontConfig
425
426  cairo_font_backends = [
427    [ 'cairo-ft', cairo_req_version, 'HAVE_CAIRO_FREETYPE', 'freetype', ],
428    [ 'cairo-win32', cairo_req_version, 'HAVE_CAIRO_WIN32', 'win32', ],
429    [ 'cairo-quartz', cairo_req_version, 'HAVE_CAIRO_QUARTZ', 'quartz', ],
430  ]
431
432  if cairo_found_type == 'internal'
433    cairo_features = subproject('cairo').get_variable('built_features')
434  endif
435
436  foreach b: cairo_font_backends
437    if cairo_found_type == 'pkgconfig'
438      dep = dependency(b[0], version: b[1], required: false)
439    else
440      dep = dependency('', required: false)
441      foreach f: cairo_features
442        if f['name'] == b[0]
443          dep = cairo_dep
444          message('Cairo font backend "@0@" enabled'.format(b))
445        endif
446      endforeach
447    endif
448    if dep.found()
449      if b[0] == 'cairo-ft'
450        if build_pangoft2
451          pango_conf.set(b[2], 1)
452          pango_font_backends += b[3]
453        endif
454      else
455        pango_conf.set(b[2], 1)
456        pango_font_backends += b[3]
457      endif
458    endif
459  endforeach
460
461  if pango_font_backends.length() == 0
462    error('No Cairo font backends found')
463  endif
464
465  # Check the following Cairo surface backends
466  # - dependency
467  # - version
468  # - define
469  # - backend name
470  cairo_surface_backends = [
471    [ 'cairo-png', cairo_req_version, 'HAVE_CAIRO_PNG', 'png', ],
472    [ 'cairo-ps', cairo_req_version, 'HAVE_CAIRO_PS', 'ps', ],
473    [ 'cairo-pdf', cairo_req_version, 'HAVE_CAIRO_PDF', 'pdf', ],
474    [ 'cairo-xlib', cairo_req_version, 'HAVE_CAIRO_XLIB', 'xlib', ],
475  ]
476
477  foreach b: cairo_surface_backends
478    if cairo_found_type == 'pkgconfig'
479      dep = dependency(b[0], version: b[1], required: false)
480    else
481      dep = dependency('', required: false)
482      foreach f: cairo_features
483        if f['name'] == b[0]
484          dep = cairo_dep
485          message('Cairo surface backend "@0@" enabled'.format(b))
486        endif
487      endforeach
488    endif
489    if dep.found()
490      pango_conf.set(b[2], 1)
491      pango_cairo_backends += b[3]
492    endif
493  endforeach
494
495  # This is to set up pangocairo.pc so that things that refer to
496  # it will link correctly
497  cairo_pc = 'cairo'
498elif cairo_found_type == 'library'
499  # Fallback: Look for Cairo items manually
500  # We need to check for headers for some
501  cairo_headers = [ 'win32', 'quartz', 'ps', 'pdf', 'xlib' ]
502
503  foreach header : cairo_headers
504    if cc.has_header('cairo-@0@.h'.format(header))
505      pango_conf.set('HAVE_CAIRO_@0@'.format(header.underscorify().to_upper()), 1)
506      if header == 'win32' or header == 'quartz'
507        pango_font_backends += header
508      else
509        pango_cairo_backends += header
510      endif
511    endif
512  endforeach
513
514  # Other cairo features that we need to check for symbols
515  # Note that Cairo with FreeType support can be without FontConfig
516  # support, so we must check for FontConfig support in Cairo
517  if cc.links('''#include <cairo-ft.h>
518                 int main() {
519                   FcPattern *p = NULL;
520                   cairo_ft_font_face_create_for_pattern (p);
521                   return 0;
522                 }''',
523                 dependencies: cairo_dep,
524                 name : 'Cairo is built with FreeType and FontConfig support')
525    if build_pangoft2
526      pango_conf.set('HAVE_CAIRO_FREETYPE', 1)
527      pango_font_backends += 'freetype'
528    endif
529  endif
530
531  if pango_font_backends.length() == 0
532    error('Cairo found, but no Cairo font backends found')
533  endif
534
535  # Check for Cairo's libpng output surface support
536  if cc.links('''#include <cairo.h>
537                 #include <stdio.h>
538                 int main() {
539                   cairo_surface_t *s = NULL;
540                   const char *f = "abc.png";
541                   cairo_surface_write_to_png (s, f);
542                   return 0;
543                 }''',
544                 dependencies: cairo_dep,
545                 name : 'Cairo is built with PNG output surface support')
546    pango_conf.set('HAVE_CAIRO_PNG', 1)
547    pango_cairo_backends += 'png'
548  endif
549
550  # This is to set up pangocairo.pc so that things that refer to
551  # it will link correctly, when we don't have pkg-config files for cairo
552  cairo_lib = '-lcairo'
553endif
554
555if cairo_dep.found()
556  pango_conf.set('HAVE_CAIRO', 1)
557  pango_deps += cairo_dep
558
559  pangocairo_requires = ''
560
561  if pango_font_backends.contains('freetype')
562    pangocairo_requires += 'pangoft2 '
563  endif
564
565  if pango_font_backends.contains('win32')
566    pangocairo_requires += 'pangowin32 '
567  endif
568endif
569
570# libsysprof-capture support
571libsysprof_capture_dep = dependency('sysprof-capture-4',
572  required: get_option('sysprof'),
573  default_options: [
574    'enable_examples=false',
575    'enable_gtk=false',
576    'enable_tests=false',
577    'enable_tools=false',
578    'libsysprof=false',
579    'with_sysprofd=none',
580    'help=false',
581  ],
582  fallback: ['sysprof', 'libsysprof_capture_dep'],
583)
584pango_conf.set('HAVE_SYSPROF', libsysprof_capture_dep.found())
585pango_deps += libsysprof_capture_dep
586
587gidocgen_dep = dependency('gi-docgen', version: '>= 2021.1',
588                          required: get_option('gtk_doc'))
589
590gnome = import('gnome')
591pkgconfig = import('pkgconfig')
592
593# Internal configuration header
594configure_file(output: 'config.h', configuration: pango_conf)
595
596root_inc = include_directories('.')
597pango_inc = include_directories('pango')
598
599subdir('pango')
600subdir('utils')
601subdir('examples')
602subdir('tests')
603subdir('tools')
604
605if get_option('gtk_doc')
606  subdir('docs')
607endif
608
609if not meson.is_subproject()
610  meson.add_dist_script('build-aux/meson/dist-docs.py')
611endif
612