meson.build 29.6 KB
Newer Older
Emmanuele Bassi's avatar
Emmanuele Bassi committed
1
project('gtk', 'c',
Matthias Clasen's avatar
Matthias Clasen committed
2
        version: '3.94.0',
Emmanuele Bassi's avatar
Emmanuele Bassi committed
3 4
        default_options: [
          'buildtype=debugoptimized',
5
          'warning_level=1',
6 7 8
          # We only need c99, but glib needs GNU-specific features
          # https://github.com/mesonbuild/meson/issues/2289
          'c_std=gnu99',
Emmanuele Bassi's avatar
Emmanuele Bassi committed
9
        ],
10
        meson_version : '>= 0.48.0',
Emmanuele Bassi's avatar
Emmanuele Bassi committed
11 12
        license: 'LGPLv2.1+')

13
glib_major_req = 2
14 15
glib_minor_req = 55
glib_micro_req = 0
16 17 18 19 20 21 22 23 24 25 26 27 28

if glib_minor_req.is_odd()
  glib_min_required = 'GLIB_VERSION_@0@_@1@'.format(glib_major_req, glib_minor_req - 1)
else
  glib_min_required = 'GLIB_VERSION_@0@_@1@'.format(glib_major_req, glib_minor_req)
endif

if glib_minor_req.is_odd()
  glib_max_allowed = 'GLIB_VERSION_@0@_@1@'.format(glib_major_req, glib_minor_req + 1)
else
  glib_max_allowed = 'GLIB_VERSION_@0@_@1@'.format(glib_major_req, glib_minor_req)
endif

29
glib_req           = '>= @0@.@1@.@2@'.format(glib_major_req, glib_minor_req, glib_micro_req)
30
pango_req          = '>= 1.41.0'
31
fribidi_req        = '>= 0.19.7'
32 33 34 35
atk_req            = '>= 2.15.1'
cairo_req          = '>= 1.14.0'
gdk_pixbuf_req     = '>= 2.30.0'
introspection_req  = '>= 1.39.0'
36
wayland_proto_req  = '>= 1.12'
37
wayland_req        = '>= 1.14.91'
38
graphene_req       = '>= 1.5.1'
39
epoxy_req          = '>= 1.4'
40
cloudproviders_req = '>= 0.2.5'
41
xkbcommon_req      = '>= 0.2.0'
42

Timm Bäder's avatar
Timm Bäder committed
43 44
gnome = import('gnome')

45
add_project_arguments('-DG_LOG_USE_STRUCTURED=1', language: 'c')
46 47
add_project_arguments('-DGLIB_MIN_REQUIRED_VERSION=' + glib_min_required, language: 'c')
add_project_arguments('-DGLIB_MAX_ALLOWED_VERSION=' + glib_max_allowed, language: 'c')
Timm Bäder's avatar
Timm Bäder committed
48

49 50 51 52 53 54 55 56 57
# Making releases:
#  1. gtk_micro_version += 1;
#  2. gtk_interface_age += 1;
#  3. if any functions have been added, set gtk_interface_age to 0.
#  4. if backwards compatibility has been broken, we're in trouble
gtk_version       = meson.project_version()
gtk_major_version = gtk_version.split('.')[0].to_int()
gtk_minor_version = gtk_version.split('.')[1].to_int()
gtk_micro_version = gtk_version.split('.')[2].to_int()
Timm Bäder's avatar
Timm Bäder committed
58
gtk_interface_age = 0
59
add_project_arguments('-DGTK_VERSION="@0@"'.format(meson.project_version()), language: 'c')
60

61 62 63 64
add_project_arguments('-D_GNU_SOURCE', language: 'c')

gtk_debug_cflags = []
buildtype = get_option('buildtype')
65
if buildtype.startswith('debug')
66 67 68 69
  gtk_debug_cflags += '-DG_ENABLE_DEBUG'
  if buildtype == 'debug'
    gtk_debug_cflags += '-DG_ENABLE_CONSISTENCY_CHECKS'
  endif
70 71
elif buildtype == 'release'
  gtk_debug_cflags += '-DG_DISABLE_CAST_CHECKS'
72 73 74
endif

add_project_arguments(gtk_debug_cflags, language: 'c')
75

76 77 78 79 80
# Define a string for the earliest version that this release has
# backwards binary compatibility with for all interfaces a module
# might. Unless we add module-only API with lower stability
# guarantees, this should be unchanged until we break binary compat
# for GTK+.
81
gtk_binary_version = '4.0.0'
Emmanuele Bassi's avatar
Emmanuele Bassi committed
82

83
gtk_binary_age = 100 * gtk_minor_version + gtk_micro_version
84

85 86
gtk_soversion = '0.@0@.@1@'.format(gtk_binary_age - gtk_interface_age, gtk_interface_age)

87
gtk_api_version = '4.0'
Emmanuele Bassi's avatar
Emmanuele Bassi committed
88

89 90 91 92 93
x11_enabled            = get_option('x11-backend')
wayland_enabled        = get_option('wayland-backend')
broadway_enabled       = get_option('broadway-backend')
quartz_enabled         = get_option('quartz-backend')
win32_enabled          = get_option('win32-backend')
94

95 96 97 98 99
os_unix   = false
os_linux  = false
os_win32  = false
os_darwin = false

100 101 102 103 104
# Some windowing system backends depend on the platform we're
# building for, so we need to ensure they are disabled; in other
# cases, they are the only windowing system available, so we need
# to ensure they are enabled
if host_machine.system() == 'darwin'
105
  os_darwin = true
106
elif host_machine.system() == 'windows'
107
  os_win32 = true
108
elif host_machine.system() == 'linux'
109
  os_linux = true
110 111 112 113 114 115
endif
os_unix = not os_win32

if os_darwin
  wayland_enabled = false
else
116
  quartz_enabled = false
117 118
endif

119 120 121 122 123 124
if os_win32
  wayland_enabled = false
  x11_enabled = false
else
  win32_enabled = false
endif
125

126
gtk_prefix = get_option('prefix')
127
gtk_includedir = join_paths(gtk_prefix, get_option('includedir'))
128 129 130
gtk_libdir = join_paths(gtk_prefix, get_option('libdir'))
gtk_datadir = join_paths(gtk_prefix, get_option('datadir'))
gtk_localedir = join_paths(gtk_prefix, get_option('localedir'))
131
gtk_sysconfdir = join_paths(gtk_prefix, get_option('sysconfdir'))
132 133
gtk_applicationsdir = join_paths(gtk_datadir, 'applications')
gtk_schemasdir = join_paths(gtk_datadir, 'glib-2.0/schemas')
134
gtk_appdatadir = join_paths(gtk_datadir, 'metainfo')
135

Emmanuele Bassi's avatar
Emmanuele Bassi committed
136
cc = meson.get_compiler('c')
137

Emmanuele Bassi's avatar
Emmanuele Bassi committed
138
cdata = configuration_data()
139 140 141 142
cdata.set_quoted('PACKAGE_VERSION', meson.project_version())
cdata.set_quoted('GTK_LOCALEDIR', gtk_localedir)
cdata.set_quoted('GTK_DATADIR', gtk_datadir)
cdata.set_quoted('GTK_LIBDIR', gtk_libdir)
143
cdata.set_quoted('GTK_SYSCONFDIR', gtk_sysconfdir)
144
cdata.set_quoted('GETTEXT_PACKAGE', 'gtk40')
Timm Bäder's avatar
Timm Bäder committed
145
cdata.set('GTK_MAJOR_VERSION', gtk_major_version)
Timm Bäder's avatar
Timm Bäder committed
146 147 148 149
cdata.set('GTK_MINOR_VERSION', gtk_minor_version)
cdata.set('GTK_MICRO_VERSION', gtk_micro_version)
cdata.set('GTK_BINARY_AGE', gtk_binary_age)
cdata.set('GTK_INTERFACE_AGE', gtk_interface_age)
150

Emmanuele Bassi's avatar
Emmanuele Bassi committed
151
check_headers = [
152
  'crt/externs.h',
153
  'dev/evdev/input.h',
154 155 156
  'dlfcn.h',
  'ftw.h',
  'inttypes.h',
157
  'linux/input.h',
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
  'linux/memfd.h',
  'locale.h',
  'memory.h',
  'stdint.h',
  'stdlib.h',
  'strings.h',
  'string.h',
  'sys/mman.h',
  'sys/param.h',
  'sys/stat.h',
  'sys/sysinfo.h',
  'sys/systeminfo.h',
  'sys/time.h',
  'sys/types.h',
  'unistd.h',
Emmanuele Bassi's avatar
Emmanuele Bassi committed
173 174 175
]

foreach h : check_headers
176 177
  if cc.has_header(h)
    cdata.set('HAVE_' + h.underscorify().to_upper(), 1)
Emmanuele Bassi's avatar
Emmanuele Bassi committed
178 179 180
  endif
endforeach

181
# Maths functions might be implemented in libm
182
libm = cc.find_library('m', required: false)
183

184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
check_functions = [
  'dcgettext',
  'getpagesize',
  'getresuid',
  'lstat',
  'mmap',
  'nearbyint',
  'posix_fallocate',
  '_lock_file',
  'flockfile',
  'mkstemp',
  'mallinfo',
  'round',
  'rint',
  'log2',
  'exp2',
  'sincos',
Emmanuele Bassi's avatar
Emmanuele Bassi committed
201 202
]

203
foreach func : check_functions
204
  if cc.has_function(func, dependencies: libm)
205
    cdata.set('HAVE_' + func.underscorify().to_upper(), 1)
Emmanuele Bassi's avatar
Emmanuele Bassi committed
206 207 208
  endif
endforeach

209 210 211
cdata.set('HAVE_DECL_ISINF', cc.has_header_symbol('math.h', 'isinf'))
cdata.set('HAVE_DECL_ISNAN', cc.has_header_symbol('math.h', 'isnan'))

212 213 214 215 216
# Disable deprecation checks for all libraries we depend on on stable branches.
# This is so newer versions of those libraries don't cause more warnings with
# a stable GTK version.
# We don't ever want to turn off deprecation warnings for master however, because
# that's where we get rid of deprecated API we use.
217
if gtk_minor_version.is_even()
218 219 220
  cdata.set('GLIB_DISABLE_DEPRECATION_WARNINGS', 1)
endif

221 222 223 224
# Compiler flags
if cc.get_id() == 'msvc'
  # Compiler options taken from msvc_recommended_pragmas.h
  # in GLib, based on _Win32_Programming_ by Rector and Newcomer
225 226 227
  test_cflags = []
  add_project_arguments('-FImsvc_recommended_pragmas.h', language: 'c')
  add_project_arguments('-D_USE_MATH_DEFINES', language: 'c')
228 229 230
elif cc.get_id() == 'gcc' or cc.get_id() == 'clang'
  test_cflags = [
    '-fno-strict-aliasing',
231
    '-Wcast-align',
232 233 234
    '-Wformat=2',
    '-Wformat-nonliteral',
    '-Wformat-security',
235 236 237 238 239 240
    '-Wignored-qualifiers',
    '-Wimplicit-function-declaration',
    '-Wlogical-op',
    '-Wmissing-format-attribute',
    '-Wmissing-include-dirs',
    '-Wmissing-noreturn',
241 242
    '-Wnested-externs',
    '-Wold-style-definition',
243
    '-Wpointer-arith',
244
    '-Wshadow',
245
    '-Wstrict-prototypes',
246 247
    '-Wswitch-default',
    '-Wswitch-enum',
248
    '-Wundef',
249
    '-Wuninitialized',
250 251 252 253
    '-Wunused',
    '-Werror=address',
    '-Werror=array-bounds',
    '-Werror=empty-body',
254 255
    '-Werror=implicit',
    '-Werror=init-self',
256
    '-Werror=int-to-pointer-cast',
257 258
    '-Werror=main',
    '-Werror=missing-braces',
259 260
    '-Werror=missing-declarations',
    '-Werror=missing-prototypes',
261 262 263
    '-Werror=nonnull',
    '-Werror=pointer-to-int-cast',
    '-Werror=redundant-decls',
264
    '-Werror=return-type',
265
    '-Werror=sequence-point',
266 267 268 269 270 271 272
    '-Werror=trigraphs',
    '-Werror=write-strings',
  ]
else
  test_cflags = []
endif

273
common_cflags = cc.get_supported_arguments(test_cflags)
Emmanuele Bassi's avatar
Emmanuele Bassi committed
274

275 276
# Symbol visibility
if get_option('default_library') != 'static'
277
  if os_win32
278
    cdata.set('DLL_EXPORT', true)
279 280
    cdata.set('_GDK_EXTERN', '__declspec(dllexport) extern')
    if cc.get_id() != 'msvc'
281 282 283 284 285 286 287 288
      common_cflags += ['-fvisibility=hidden']
    endif
  else
    cdata.set('_GDK_EXTERN', '__attribute__((visibility("default"))) extern')
    common_cflags += ['-fvisibility=hidden']
  endif
endif

289 290
common_ldflags = []

291 292 293 294 295 296
if os_unix and not os_darwin
  foreach ldflag: [ '-Wl,-Bsymbolic', '-Wl,-z,relro', '-Wl,-z,now', ]
    if cc.links('int main () { return 0; }', name: ldflag, args: ldflag)
      common_ldflags += [ ldflag ]
    endif
  endforeach
297 298 299
endif

# Maintain compatibility with autotools
300
if os_darwin
301
  common_ldflags += [ '-compatibility_version 1', '-current_version 1.0', ]
302 303
endif

Emmanuele Bassi's avatar
Emmanuele Bassi committed
304 305
confinc = include_directories('.')
gdkinc = include_directories('gdk')
306
gskinc = include_directories('gsk')
Timm Bäder's avatar
Timm Bäder committed
307
gtkinc = include_directories('gtk')
308
testinc = include_directories('tests')
Timm Bäder's avatar
Timm Bäder committed
309

310
# Dependencies
311 312 313 314
glib_dep       = dependency('glib-2.0', version: glib_req,
                            fallback : ['glib', 'libglib_dep'])
gobject_dep    = dependency('gobject-2.0', version: glib_req,
                            fallback : ['glib', 'libgobject_dep'])
315
if os_win32
316 317
  giowin32_dep = dependency('gio-windows-2.0', version: glib_req, required: win32_enabled,
                            fallback : ['glib', 'libgio_dep'])
318 319
endif
if os_unix
320
  giounix_dep  = dependency('gio-unix-2.0', version: glib_req, required: false,
321
                            fallback : ['glib', 'libgio_dep'])
322
endif
323 324
gmodule_dep    = dependency('gmodule-2.0', version: glib_req,
                            fallback : ['glib', 'libgmodule_dep'])
325 326
cairo_dep      = dependency('cairo', version: cairo_req, required : cc.get_id() != 'msvc')
cairogobj_dep  = dependency('cairo-gobject', version: cairo_req, required : cc.get_id() != 'msvc')
327 328
pango_dep      = dependency('pango', version: pango_req,
                            fallback : ['pango', 'libpango_dep'])
329 330
fribidi_dep    = dependency('fribidi', version: fribidi_req,
                            fallback : ['fribidi', 'libfribidi_dep'])
331

332 333
# Require PangoFT2 if on X11 or wayland
require_pangoft2 = wayland_enabled or x11_enabled
334 335
pangoft_dep    = dependency('pangoft2', required: require_pangoft2,
                            fallback : ['pango', 'libpangoft2_dep'])
336

337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
if pangoft_dep.found()
  # Need at least 2.7.1 for FT_Get_Var_Design_Coordinates()
  # We get the dependency itself from pango, but pango doesn't care
  # about ft2 version, so an extra check is needed.
  ft2_dep      = dependency('freetype2', version: '>= 2.7.1', required: require_pangoft2)

  # Fallback case: Look for the FreeType2 headers and library manually when its .pc
  # file is not available, such as on Visual Studio
  if not ft2_dep.found()
    ft2lib = ft2_dep
    if cc.has_header('ft2build.h')
      ft2_libnames = ['freetype', 'freetypemt']
      foreach lib: ft2_libnames
        if not ft2_dep.found()
          ft2lib = cc.find_library(lib)
          # If the FreeType2 library is found, check for FT_Get_Var_Design_Coordinates()
          if ft2lib.found()
            if cc.has_function('FT_Get_Var_Design_Coordinates', dependencies: ft2lib)
              ft2_dep = ft2lib
            endif
          endif
        endif
      endforeach
    endif
  endif
endif

LRN's avatar
LRN committed
364 365 366 367 368
if win32_enabled
  # for GTK_IM_CONTEXT_IME
  pangowin32_dep  = dependency('pangowin32')
endif

369
pangocairo_dep = dependency('pangocairo', version: cairo_req,
370 371 372
                            fallback : ['pango', 'libpangocairo_dep'])
pixbuf_dep     = dependency('gdk-pixbuf-2.0', version: gdk_pixbuf_req,
                            fallback : ['gdk-pixbuf', 'gdkpixbuf_dep'])
373 374
epoxy_dep      = dependency('epoxy', version: epoxy_req,
                            fallback: ['libepoxy', 'libepoxy_dep'])
375
atk_dep        = dependency('atk', version: atk_req)
376 377
harfbuzz_dep   = dependency('harfbuzz', version: '>= 0.9', required: false,
                            fallback: ['harfbuzz', 'libharfbuzz_dep'])
378
xkbdep         = dependency('xkbcommon', version: xkbcommon_req, required: wayland_enabled)
379
graphene_dep   = dependency('graphene-gobject-1.0', version: graphene_req,
380
                            fallback: ['graphene', 'graphene_dep'])
381
iso_codes_dep  = dependency('iso-codes', required: false)
382

383 384 385
fontconfig_dep = [] # only used in x11 backend
atkbridge_dep  = [] # only used in x11 backend

386
if os_win32
387
  platform_gio_dep = giowin32_dep
388 389
endif
if os_unix
390 391 392
  platform_gio_dep = giounix_dep
endif

393 394 395 396 397 398
if iso_codes_dep.found()
  cdata.set_quoted('ISO_CODES_PREFIX', iso_codes_dep.get_pkgconfig_variable('prefix'))
else
  cdata.set_quoted('ISO_CODES_PREFIX', '/usr')
endif

399 400
backend_immodules = []

401 402 403
pc_gdk_extra_libs = []

cairo_backends = []
404 405 406
foreach backend: [ ['cairo-xlib', cairo_req, x11_enabled],
                   ['cairo-win32', cairo_req, win32_enabled],
                   ['cairo-quartz', cairo_req, quartz_enabled],
Matthias Clasen's avatar
Matthias Clasen committed
407
                   ['cairo', cairo_req, broadway_enabled or wayland_enabled], ]
408 409 410 411
 backend_enabled = backend.get(2)
 cairo_backend_req = backend.get(1)
 cairo_backend = backend.get(0)
 if backend_enabled
412 413 414
   if dependency(cairo_backend, version: cairo_backend_req, required : cc.get_id() != 'msvc').found()
     cairo_backends += [ cairo_backend ]
   endif
415 416 417
 endif
endforeach

418 419 420 421 422 423 424 425 426 427
cairo_pkg_found = false
cairogobj_pkg_found = false

if cairo_dep.found()
  cairo_pkg_found = true
endif
if cairogobj_dep.found()
  cairogobj_pkg_found = true
endif

428
cairo_libs = []
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
if cc.get_id() == 'msvc'
  # Fallback depedency discovery for those on Visual Studio that do not generate
  # pkg-config files in their build systems for MSVC
  # Fallback for Cairo
  if not cairo_dep.found()
    if (cc.has_header('cairo.h') and cc.has_header('cairo-win32.h'))
      cairo_dep = cc.find_library('cairo')
      if cairo_dep.found()
        cairo_libs += '-lcairo'
      endif
    endif
  endif

  # Fallback for Cairo-GObject
  if not cairogobj_dep.found()
    if cc.has_header('cairo-gobject.h')
      cairogobj_dep = cc.find_library('cairo-gobject')
      if cairogobj_dep.found()
        cairo_libs += '-lcairo-gobject'
      endif
    endif
  endif

  # Fallback for HarfBuzz
  if not harfbuzz_dep.found()
454
    if cc.has_header('hb.h')
455 456 457 458 459
      harfbuzz_dep = cc.find_library('harfbuzz', required : false)
    endif
  endif
endif

460 461 462
cdata.set('HAVE_HARFBUZZ', harfbuzz_dep.found())
cdata.set('HAVE_PANGOFT', pangoft_dep.found())

463
atk_pkgs = ['atk']
Emmanuele Bassi's avatar
Emmanuele Bassi committed
464

465
wayland_pkgs = []
466
if wayland_enabled
467 468 469
  wlclientdep    = dependency('wayland-client', version:  wayland_req)
  wlprotocolsdep = dependency('wayland-protocols', version: wayland_proto_req)
  wlcursordep    = dependency('wayland-cursor', version: wayland_req)
470
  wlegldep       = dependency('wayland-egl')
471
  backend_immodules += ['wayland']
472 473 474 475

  wayland_pkgs = [
    'wayland-client', wayland_req,
    'wayland-protocols', wayland_proto_req,
476
    'xkbcommon', xkbcommon_req,
477 478 479
    'wayland-cursor', wayland_req,
    'wayland-egl',
  ]
Emmanuele Bassi's avatar
Emmanuele Bassi committed
480 481
endif

482
x11_pkgs = []
483 484 485 486 487 488 489 490 491 492 493
if x11_enabled
  xrandr_dep     = dependency('xrandr', version: '>= 1.2.99')
  xrandr15_dep   = dependency('xrandr', version: '>= 1.5', required: false)
  x11_dep        = dependency('x11')
  xrender_dep    = dependency('xrender')
  xi_dep         = dependency('xi')
  xext_dep       = dependency('xext')
  xcursor_dep    = dependency('xcursor', required: false)
  xdamage_dep    = dependency('xdamage', required: false)
  xfixes_dep     = dependency('xfixes', required: false)
  xcomposite_dep = dependency('xcomposite', required: false)
494 495
  fontconfig_dep = dependency('fontconfig')
  atkbridge_dep  = dependency('atk-bridge-2.0', version: atk_req)
496

497 498
  backend_immodules += ['xim']

499
  x11_pkgs = ['fontconfig', 'x11', 'xext', 'xi', 'xrandr']
500

501
  if xcursor_dep.found()
502 503 504 505
    x11_pkgs += ['xcursor']
  endif
  if xfixes_dep.found()
    x11_pkgs += ['xfixes']
506 507
  endif
  if xcomposite_dep.found()
508
    x11_pkgs += ['xcomposite']
509
  endif
510 511
  if xdamage_dep.found()
    x11_pkgs += ['xdamage']
512
  endif
513

514 515 516 517 518 519 520
  atk_pkgs += ['atk-bridge-2.0']

  cdata.set('HAVE_XDAMAGE', xdamage_dep.found())
  cdata.set('HAVE_XCURSOR', xcursor_dep.found())
  cdata.set('HAVE_XCOMPOSITE', xcomposite_dep.found())
  cdata.set('HAVE_XFIXES', xfixes_dep.found())

521
  if cc.has_function('XkbQueryExtension', dependencies: x11_dep,
522 523 524 525
                     prefix : '#include <X11/XKBlib.h>')
    cdata.set('HAVE_XKB', 1)
  endif

526 527 528
  if cc.has_function('XSyncQueryExtension', dependencies: xext_dep,
                     prefix: '''#include <X11/Xlib.h>
                                #include <X11/extensions/sync.h>''')
529 530
    cdata.set('HAVE_XSYNC', 1)
  endif
531

532
  if cc.has_function('XGetEventData', dependencies: x11_dep)
533 534
    cdata.set('HAVE_XGENERICEVENTS', 1)
  endif
535

536
  if xi_dep.found() and cc.has_header('X11/extensions/XInput2.h', dependencies: xi_dep)
537
    cdata.set('XINPUT_2', 1)
538 539 540
    # Note that we also check that the XIScrollClassInfo struct is defined,
    # because at least Ubuntu Oneiric seems to have XIAllowTouchEvents(),
    # but not the XIScrollClassInfo struct
541 542 543 544 545
    has_allow_touch_evens = cc.has_function('XIAllowTouchEvents', dependencies: xi_dep)
    has_scroll_class_info = cc.has_member('XIScrollClassInfo', 'number', dependencies: xi_dep,
                                          prefix: '''#include <X11/Xlib.h>
                                                     #include <X11/extensions/XInput2.h>''')
    if has_allow_touch_evens and has_scroll_class_info
546 547
      cdata.set('XINPUT_2_2', 1)
    endif
548 549
  endif

550
  enable_xinerama = get_option('xinerama')
551 552
  if enable_xinerama != 'no'
    want_xinerama = enable_xinerama == 'yes'
553 554
    xinerama_dep = dependency('xinerama', required: want_xinerama)
    if xinerama_dep.found() and cc.has_header_symbol('X11/extensions/Xinerama.h', 'XineramaQueryExtension', dependencies: xinerama_dep)
555 556 557 558 559 560 561
      cdata.set('HAVE_XFREE_XINERAMA', 1)
      x11_pkgs += ['xinerama']
    endif
  else
    xinerama_dep = []
  endif

562 563
  cdata.set('HAVE_RANDR', xrandr_dep.found())
  cdata.set('HAVE_RANDR15', xrandr15_dep.found())
564 565
endif

566 567
if broadway_enabled
  pc_gdk_extra_libs += ['-lz']
568
  backend_immodules += ['broadway']
569 570
endif

571 572
if quartz_enabled
  pc_gdk_extra_libs += ['-framework Cocoa', '-framework Carbon']
573
  backend_immodules += ['quartz']
574 575
endif

576
extra_demo_ldflags = []
577
if win32_enabled
578
  pc_gdk_extra_libs += ['-lgdi32', '-limm32', '-lshell32', '-lole32']
579 580 581 582 583 584
  if cc.get_id() == 'msvc'
    # Since the demo programs are now built as pure GUI programs, we
    # need to pass in /entry:mainCRTStartup so that they will properly
    # link on Visual Studio builds
    extra_demo_ldflags = ['/entry:mainCRTStartup']
  else
585 586 587
    pc_gdk_extra_libs += ['-Wl,-luuid']
  endif
  pc_gdk_extra_libs += ['-lwinmm', '-ldwmapi', '-lsetupapi', '-lcfgmgr32']
588
  backend_immodules += ['ime']
589
endif
590

591 592 593
# Check for bind_textdomain_codeset, including -lintl if GLib brings it in by
# doing the same check as glib. We can't check that by linking to glib because
# it might be a subproject and hence not built yet.
594 595
if cc.has_function('ngettext')
  libintl_dep = []
596
  cdata.set('HAVE_BIND_TEXTDOMAIN_CODESET', 1)
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
else
  libintl_dep = cc.find_library('intl', required : false)
  if cc.has_function('bind_textdomain_codeset', dependencies: libintl_dep)
    cdata.set('HAVE_BIND_TEXTDOMAIN_CODESET', 1)
  else
    # Don't use subproject('proxy-libintl').get_variable('intl_dep') because that
    # makes the dependency unconditional. This way, people have the option of
    # either not providing the subproject or disabling it entirely with
    # --wrap-mode=nodownload or nofallback.
    libintl_dep = dependency('', required : false,
                             fallback: ['proxy-libintl', 'intl_dep'])
    if libintl_dep.found()
      cdata.set('HAVE_BIND_TEXTDOMAIN_CODESET', 1)
    endif
  endif
612 613
endif

614
if os_unix
615 616
  cdata.set('HAVE_GIO_UNIX', giounix_dep.found())
endif
617

618 619 620
# Check for Vulkan support
# TODO: move to gsk subfolder maybe? Or will it be used elsewhere too?
have_vulkan = false
621 622
vulkan_pkg_found = false
vulkan_dep = []
623

624
enable_vulkan = get_option('vulkan')
625 626 627 628 629
if enable_vulkan == 'no'
  message('Vulkan support explicitly disabled')
else
  vulkan_dep = dependency('vulkan', required: false)
  if vulkan_dep.found()
630
    have_vulkan = true
631 632 633 634 635 636 637 638
    vulkan_pkg_found = true
  else
    if cc.get_id() == 'msvc'
      vulkan_libname = 'vulkan-1'
    else
      vulkan_libname = 'vulkan'
    endif
    vulkan_dep = cc.find_library(vulkan_libname, required: false)
639
    if vulkan_dep.found() and cc.has_function('vkCreateInstance', dependencies: vulkan_dep) and cc.has_header('vulkan/vulkan.h')
640 641 642 643 644
      have_vulkan = true
      pc_gdk_extra_libs += ['-l@0@'.format(vulkan_libname)]
    endif
  endif
  if enable_vulkan == 'yes' and not have_vulkan
645
    error('Vulkan support not found, but was explicitly requested.')
646 647 648
  endif
endif

649
cloudproviders_enabled = get_option('cloudproviders')
650 651 652 653 654 655 656 657 658
if cloudproviders_enabled
  cloudproviders_dep = dependency('cloudproviders', required: true)
  if cloudproviders_dep.found()
    cdata.set('HAVE_CLOUDPROVIDERS', cloudproviders_dep.found())
  else
    error('Cloudproviders support not found, but was explicitly requested.')
  endif
endif

659 660 661 662 663 664 665 666 667
graphene_dep_type = graphene_dep.type_name()
if graphene_dep_type == 'pkgconfig'
  graphene_has_sse2 = graphene_dep.get_pkgconfig_variable('graphene_has_sse2') == '1'
  graphene_has_gcc = graphene_dep.get_pkgconfig_variable('graphene_has_gcc') == '1'
else
  graphene_simd = subproject('graphene').get_variable('graphene_simd')
  graphene_has_sse2 = graphene_simd.contains('sse2')
  graphene_has_gcc = graphene_simd.contains('gcc')
endif
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791

malloc_is_aligned = false

if not meson.is_cross_build() or meson.has_exe_wrapper()
  malloc_test = cc.run ('''
  #include <malloc.h>
  #include <stdio.h>

  #define COUNT 100
  #define is_aligned(POINTER, BYTE_COUNT) \
    (((uintptr_t)(const void *)(POINTER)) % (BYTE_COUNT) == 0)
  int
  main (int argc, char *argv[])
  {
    void **pointers;
    int i, a, min_a;
    FILE *f;
    int wrote;
    pointers = malloc (sizeof (void *) * COUNT);
    for (i = 0, min_a = 128; i < COUNT; i++, pointers++)
    {
      *pointers = malloc (sizeof (void *));
      for (a = 1; a <= 128; a = a * 2)
      {
        if (!is_aligned (*pointers, a))
        {
          a = a / 2;
          break;
        }
      }
      if (a > 128)
        a = 128;
      if (a < min_a)
        min_a = a;
    }
    wrote = fprintf (stderr, "%d", min_a);
    if (wrote <= 0)
      return 1;
    return 0;
  }
  ''')

  if not malloc_test.compiled() or malloc_test.returncode() != 0
    message ('malloc() alignment test failed, assuming unaligned malloc()')
  elif malloc_test.stderr().to_int() >= 16
    malloc_is_aligned = true
    cdata.set('MALLOC_IS_ALIGNED16', 1)
  endif
else
  # TODO: more reasinable cross-compiling defaults?
  message ('cross-compiling, assuming unaligned malloc()')
endif

if cc.get_id() == 'gcc' or cc.get_id() == 'clang'
    no_builtin_args = cc.get_supported_arguments(['-fno-builtin'])
else
    no_builtin_args = []
endif

# Check that posix_memalign() is not a builtin
have_posix_memalign = cc.links('''#include <stdlib.h>
                                  int main (int argc, char ** argv) {
                                    void *p;
                                    return posix_memalign (&p, 16, argc);
                                  }
                               ''',
                               args : no_builtin_args,
                               name : 'posix_memalign() is not a builtin')
if have_posix_memalign
  cdata.set('HAVE_POSIX_MEMALIGN', 1)
endif

# Check that memalign() is not a builtin
have_memalign = cc.links('''#include <malloc.h>
                            int main (int argc, char ** argv) {
                              return memalign (16, argc);
                            }
                         ''',
                         args : no_builtin_args,
                         name : 'memalign() is not a builtin')
if have_memalign
  cdata.set('HAVE_MEMALIGN', 1)
endif

# Check that aligned_alloc() is not a builtin
have_aligned_alloc = cc.links('''#include <stdlib.h>
                                 int main (int argc, char ** argv) {
                                   return aligned_alloc (16, argc);
                                 }
                              ''',
                              args : no_builtin_args,
                              name : 'aligned_alloc() is not a builtin')
  if have_aligned_alloc
  cdata.set('HAVE_ALIGNED_ALLOC', 1)
endif

# Check that _aligned_malloc() is not a builtin
have__aligned_malloc = cc.links('''#include <malloc.h>
                                   int main (int argc, char ** argv) {
                                     return _aligned_malloc (argc, 16);
                                   }
                                ''',
                                args : no_builtin_args,
                                name : '_aligned_malloc() is not a builtin')
if have__aligned_malloc
  cdata.set('HAVE__ALIGNED_MALLOC', 1)
endif

if graphene_has_sse2 or graphene_has_gcc
  message('Need aligned memory due to the use of SSE2 or GCC vector instructions')

  if os_win32 and cc.get_id() == 'gcc'
    add_global_arguments(['-mstackrealign'], language: 'c')
  endif

  if (not malloc_is_aligned and
      not have_posix_memalign and
      not have_memalign and
      not have_aligned_alloc and
      not have__aligned_malloc)
    error('Failed to find any means of allocating aligned memory')
  endif

endif
792

Emmanuele Bassi's avatar
Emmanuele Bassi committed
793
subdir('gdk')
Timm Bäder's avatar
Timm Bäder committed
794
subdir('gsk')
Timm Bäder's avatar
Timm Bäder committed
795
subdir('gtk')
796
subdir('modules')
797 798 799
if get_option('demos')
  subdir('demos')
endif
800 801 802 803
if get_option('build-tests')
  subdir('tests')
  subdir('testsuite')
endif
804 805 806
if get_option('build-examples')
  subdir('examples')
endif
807

808
# config.h
809 810 811
configure_file(input: 'config.h.meson',
               output: 'config.h',
               configuration: cdata)
812

813 814 815 816 817 818 819 820 821 822
# pkg-config files - bit of a mess all of this
pkgconf = configuration_data()

pkgconf.set('prefix', get_option('prefix'))
pkgconf.set('exec_prefix', '${prefix}')
pkgconf.set('libdir', '${prefix}/@0@'.format(get_option('libdir')))
pkgconf.set('includedir', '${prefix}/@0@'.format(get_option('includedir')))
pkgconf.set('GTK_API_VERSION', gtk_api_version)
pkgconf.set('VERSION', meson.project_version())
pkgconf.set('GTK_BINARY_VERSION', gtk_binary_version)
823
pkgconf.set('host', '@0@-@1@'.format(host_machine.cpu_family(), host_machine.system())) # FIXME
824 825 826

# Requires
pango_pkgname = win32_enabled ? 'pangowin32' : 'pango'
827
gdk_packages = ' '.join([ pango_pkgname, pango_req,
828
                       'pangocairo', pango_req,
829 830 831 832 833 834 835 836 837
                       'gdk-pixbuf-2.0', gdk_pixbuf_req ])

if cairo_pkg_found
  gdk_packages += ' '.join([ ' cairo', cairo_req ])
endif
if cairogobj_pkg_found
  gdk_packages += ' '.join([ ' cairo-gobject', cairo_req ])
endif

838 839 840 841
if vulkan_pkg_found
  gdk_packages += 'vulkan'
endif

842
pkgconf.set('GDK_PACKAGES', gdk_packages)
843 844 845 846 847
pkgconf.set('GSK_PACKAGES',
            ' '.join([ 'graphene-gobject-1.0', graphene_req ]))
pkgconf.set('GTK_PACKAGES',
            ' '.join([ 'atk', atk_req,
                       'gio-2.0', glib_req ]))
848 849

# Requires.private
850 851
pc_gdk_extra_libs += cairo_libs

852
gio_pkgname = os_unix ? 'gio-unix-2.0' : 'gio-2.0'
853 854
pkgconf.set('GDK_PRIVATE_PACKAGES',
            ' '.join([ gio_pkgname, glib_req,
Matthias Clasen's avatar
Matthias Clasen committed
855
                       'epoxy', epoxy_req ] + x11_pkgs + wayland_pkgs + cairo_backends))
856 857 858 859 860 861 862 863 864 865 866 867 868 869
pkgconf.set('GSK_PRIVATE_PACKAGES', '') # all already in GDK_PRIVATE_PACKAGES
pangoft2_pkgs = (wayland_enabled or x11_enabled) ? ['pangoft2'] : []
pkgconf.set('GTK_PRIVATE_PACKAGES', ' '.join(atk_pkgs + pangoft2_pkgs))

pkgconf.set('GDK_EXTRA_LIBS', ' '.join(pc_gdk_extra_libs))
pkgconf.set('GSK_EXTRA_LIBS', '')
pkgconf.set('GTK_EXTRA_LIBS', '')

pkgconf.set('GDK_EXTRA_CFLAGS', '')
pkgconf.set('GSK_EXTRA_CFLAGS', '')
pkgconf.set('GTK_EXTRA_CFLAGS', '')

pkg_install_dir = join_paths(get_option('libdir'), 'pkgconfig')

870
pkgs = [ 'gtk4.pc' ]
871 872

pkg_targets = ''
Matthias Clasen's avatar
Matthias Clasen committed
873
foreach backend: [ 'broadway', 'quartz', 'wayland', 'win32', 'x11', ]
874
  if get_variable('@0@_enabled'.format(backend))
875
    pkgs += ['gtk4-@0@.pc'.format(backend)]
876 877 878 879 880
    pkg_targets += ' ' + backend
  endif
endforeach
pkgconf.set('GDK_BACKENDS', pkg_targets.strip())

881
foreach pkg: pkgs
882
  configure_file(input: 'gtk4.pc.in',
883 884 885
                 output: pkg,
                 configuration: pkgconf,
                 install_dir: pkg_install_dir)
886 887
endforeach

888
if os_unix
889 890
  configure_file(input: 'gtk4-unix-print.pc.in',
                 output: 'gtk4-unix-print.pc',
891 892
                 configuration: pkgconf,
                 install_dir: pkg_install_dir)
893
endif
894 895 896

subdir('po')
subdir('po-properties')
897

898
if get_option('documentation')
899 900 901
  subdir('docs/tools')
  subdir('docs/reference')
endif
902

Timm Bäder's avatar
Timm Bäder committed
903 904 905 906 907 908 909
# Keep this in sync with post-install.sh expected arguments
meson.add_install_script('build-aux/meson/post-install.sh',
                         gtk_api_version,
                         gtk_binary_version,
                         gtk_libdir,
                         gtk_datadir)

910 911 912
summary = [
  '',
  '------',
913
  'GTK @0@ (@1@)'.format(gtk_version, gtk_api_version),
914
  '',
915
  '  Display backends: @0@'.format(pkg_targets.strip()),
916
  '    Print backends: @0@'.format(' '.join(print_backends)),
917
  '    Media backends: @0@'.format(' '.join(media_backends)),
918 919 920 921
  '    Vulkan support: @0@'.format(have_vulkan),
  '     Cloud support: @0@'.format(get_option('cloudproviders')),
  '    Colord support: @0@'.format(get_option('colord')),
  '     Introspection: @0@'.format(get_option('introspection')),
922
  '     Documentation: @0@'.format(get_option('documentation')),
923 924
  '       Build tests: @0@'.format(get_option('build-tests')),
  '     Install tests: @0@'.format(get_option('install-tests')),
925
  '             Demos: @0@'.format(get_option('demos')),
926
  '          Examples: @0@'.format(get_option('build-examples')),
927 928 929 930 931
  'Directories:',
  '            prefix: @0@'.format(gtk_prefix),
  '        includedir: @0@'.format(gtk_includedir),
  '            libdir: @0@'.format(gtk_libdir),
  '           datadir: @0@'.format(gtk_datadir),
932 933 934 935 936
  '------',
  ''
]

message('\n'.join(summary))