1project( 2 'virt-viewer','c', 3 version: '11.0', 4 license: 'GPLv3+', 5 default_options: [ 6 'buildtype=debugoptimized', 7 'b_pie=true', 8 'c_std=gnu99', 9 'warning_level=1', 10 ], 11 meson_version: '>= 0.54.0' 12) 13 14pod2man = find_program('pod2man') 15 16cc = meson.get_compiler('c') 17python3 = find_program('python3', required: true) 18# Python3 < 3.7 treats the C locale as 7-bit only. We must force env vars so 19# it treats it as UTF-8 regardless of the user's locale. 20runutf8 = [ 'LC_ALL=', 'LANG=C', 'LC_CTYPE=en_US.UTF-8' ] 21git = run_command('test', '-d', '.git').returncode() == 0 22 23conf_data = configuration_data() 24conf_data.set('VERSION', meson.project_version()) 25conf_data.set('PACKAGE_STRING', 'virt-viewer ' + meson.project_version()) 26 27# Keep these two definitions in agreement. 28glib_min_version='>=2.48' 29glib_min_version_symbol='GLIB_VERSION_2_48' 30 31# Keep these two definitions in agreement. 32gtk_min_version='>=3.18' 33gtk_min_version_symbol='GDK_VERSION_3_18' 34 35libxml_min_version='>=2.6.0' 36libvirt_min_version='>=1.2.8' 37libvirt_glib_min_version='>=0.1.8' 38gtk_vnc_min_version='>=0.4.0' 39spice_gtk_min_version='>=0.35' 40spice_protocol_min_version='>=0.12.7' 41govirt_min_version='>=0.3.7' 42rest_min_version='>=0.8' 43vte_min_version='>=0.46.0' 44bash_completion_version='2.0' 45 46add_global_arguments('-DGLIB_VERSION_MIN_REQUIRED=@0@'.format(glib_min_version_symbol), language: 'c') 47add_global_arguments('-DGLIB_VERSION_MAX_ALLOWED=@0@'.format(glib_min_version_symbol), language: 'c') 48 49add_global_arguments('-DGDK_VERSION_MIN_REQUIRED=@0@'.format(gtk_min_version_symbol), language: 'c') 50add_global_arguments('-DGDK_VERSION_MAX_ALLOWED=@0@'.format(gtk_min_version_symbol), language: 'c') 51 52cc_flags = [] 53 54git_werror = get_option('git_werror') 55if git_werror.enabled() or git_werror.auto() and git 56 cc_flags += [ '-Werror' ] 57endif 58 59cc_flags += [ 60 '-fno-common', 61 '-W', 62 '-Wabsolute-value', 63 '-Waddress', 64 '-Waddress-of-packed-member', 65 '-Waggressive-loop-optimizations', 66 '-Wall', 67 '-Wattribute-warning', 68 '-Wattributes', 69 '-Wbool-compare', 70 '-Wbool-operation', 71 '-Wbuiltin-declaration-mismatch', 72 '-Wbuiltin-macro-redefined', 73 '-Wcannot-profile', 74 '-Wcast-align', 75 '-Wcast-align=strict', 76 '-Wcast-function-type', 77 '-Wchar-subscripts', 78 '-Wclobbered', 79 '-Wcomment', 80 '-Wcomments', 81 '-Wcoverage-mismatch', 82 '-Wcpp', 83 '-Wdangling-else', 84 '-Wdate-time', 85 '-Wdeprecated-declarations', 86 '-Wdesignated-init', 87 '-Wdouble-promotion', 88 '-Wdiscarded-array-qualifiers', 89 '-Wdiscarded-qualifiers', 90 '-Wdiv-by-zero', 91 '-Wduplicated-cond', 92 '-Wduplicate-decl-specifier', 93 '-Wempty-body', 94 '-Wendif-labels', 95 '-Wexpansion-to-defined', 96 '-Wextra', 97 '-Wformat-contains-nul', 98 '-Wformat-extra-args', 99 '-Wformat-nonliteral', 100 '-Wformat-security', 101 '-Wformat-y2k', 102 '-Wformat-zero-length', 103 '-Wframe-address', 104 '-Wfree-nonheap-object', 105 '-Whsa', 106 '-Wif-not-aligned', 107 '-Wignored-attributes', 108 '-Wignored-qualifiers', 109 '-Wimplicit', 110 '-Wimplicit-function-declaration', 111 '-Wimplicit-int', 112 '-Wincompatible-pointer-types', 113 '-Winit-self', 114 '-Winline', 115 '-Wint-conversion', 116 '-Wint-in-bool-context', 117 '-Wint-to-pointer-cast', 118 '-Winvalid-memory-model', 119 '-Winvalid-pch', 120 '-Wlogical-not-parentheses', 121 '-Wlogical-op', 122 '-Wmain', 123 '-Wmaybe-uninitialized', 124 '-Wmemset-elt-size', 125 '-Wmemset-transposed-args', 126 '-Wmisleading-indentation', 127 '-Wmissing-attributes', 128 '-Wmissing-braces', 129 '-Wmissing-declarations', 130 '-Wmissing-field-initializers', 131 '-Wmissing-include-dirs', 132 '-Wmissing-parameter-type', 133 '-Wmissing-profile', 134 '-Wmissing-prototypes', 135 '-Wmultichar', 136 '-Wmultistatement-macros', 137 '-Wnarrowing', 138 '-Wnested-externs', 139 '-Wnonnull', 140 '-Wnonnull-compare', 141 '-Wnull-dereference', 142 '-Wodr', 143 '-Wold-style-declaration', 144 '-Wold-style-definition', 145 '-Wopenmp-simd', 146 '-Woverflow', 147 '-Woverride-init', 148 '-Wpacked-bitfield-compat', 149 '-Wpacked-not-aligned', 150 '-Wparentheses', 151 '-Wpointer-arith', 152 '-Wpointer-compare', 153 '-Wpointer-sign', 154 '-Wpointer-to-int-cast', 155 '-Wpragmas', 156 '-Wpsabi', 157 '-Wrestrict', 158 '-Wreturn-local-addr', 159 '-Wreturn-type', 160 '-Wscalar-storage-order', 161 '-Wsequence-point', 162 '-Wshadow', 163 '-Wshift-count-negative', 164 '-Wshift-count-overflow', 165 '-Wshift-negative-value', 166 '-Wsizeof-array-argument', 167 '-Wsizeof-pointer-div', 168 '-Wsizeof-pointer-memaccess', 169 '-Wstrict-aliasing', 170 '-Wstrict-prototypes', 171 '-Wstringop-truncation', 172 '-Wsuggest-attribute=cold', 173 '-Wsuggest-attribute=const', 174 '-Wsuggest-attribute=format', 175 '-Wsuggest-attribute=noreturn', 176 '-Wsuggest-attribute=pure', 177 '-Wsuggest-final-methods', 178 '-Wsuggest-final-types', 179 '-Wswitch', 180 '-Wswitch-bool', 181 '-Wswitch-unreachable', 182 '-Wsync-nand', 183 '-Wtautological-compare', 184 '-Wtrampolines', 185 '-Wtrigraphs', 186 '-Wtype-limits', 187 '-Wuninitialized', 188 '-Wunknown-pragmas', 189 '-Wunused', 190 '-Wunused-but-set-parameter', 191 '-Wunused-but-set-variable', 192 '-Wunused-function', 193 '-Wunused-label', 194 '-Wunused-local-typedefs', 195 '-Wunused-parameter', 196 '-Wunused-result', 197 '-Wunused-value', 198 '-Wunused-variable', 199 '-Wvarargs', 200 '-Wvariadic-macros', 201 '-Wvector-operation-performance', 202 '-Wvla', 203 '-Wvolatile-register-var', 204 '-Wwrite-strings', 205] 206 207# gcc --help=warnings outputs 208ptrdiff_max = cc.sizeof('ptrdiff_t', prefix: '#include <stddef.h>') 209size_max = cc.sizeof('size_t', prefix: '#include <stdint.h>') 210# Compute max safe object size by checking ptrdiff_t and size_t sizes. 211# Ideally we would get PTRDIFF_MAX and SIZE_MAX values but it would 212# give us (2147483647L) and we would have to remove the () and the suffix 213# in order to convert it to numbers to be able to pick the smaller one. 214alloc_max = run_command( 215 'python3', '-c', 216 'print(min(2**(@0@ * 8 - 1) - 1, 2**(@1@ * 8) - 1))'.format(ptrdiff_max, size_max), 217) 218cc_flags += [ 219 '-Walloc-size-larger-than=@0@'.format(alloc_max.stdout().strip()), 220 '-Warray-bounds=2', 221 '-Wattribute-alias=2', 222 '-Wformat-overflow=2', 223 '-Wformat-truncation=2', 224 '-Wimplicit-fallthrough=5', 225 '-Wnormalized=nfc', 226 '-Wshift-overflow=2', 227 '-Wstringop-overflow=2', 228 '-Wunused-const-variable=2', 229 '-Wvla-larger-then=4031', 230] 231 232cc_flags += [ 233 # So we have -W enabled, and then have to explicitly turn off... 234 '-Wno-sign-compare', 235 236 # We do "bad" function casts all the time for event callbacks 237 '-Wno-cast-function-type', 238 239 # Clang incorrectly complains about dup typedefs win gnu99 mode 240 # so use this Clang-specific arg to keep it quiet 241 '-Wno-typedef-redefinition', 242 243 # We don't use -Wc++-compat so we have to enable it explicitly 244 '-Wjump-misses-init', 245 246 # -Wswitch is enabled but that doesn't report missing enums if a default: 247 # is present 248 '-Wswitch-enum', 249 250 # -Wformat=2 implies -Wformat-nonliteral so we need to manually exclude it 251 '-Wno-format-nonliteral', 252 253 # -Wformat enables this by default, and we should keep it, 254 # but need to rewrite various areas of code first 255 '-Wno-format-truncation', 256 257 # This should be < 256 really. Currently we're down to 4096, 258 # but using 1024 bytes sized buffers (mostly for virStrerror) 259 # stops us from going down further 260 '-Wframe-larger-than=4096', 261 262 # extra special flags 263 '-fexceptions', 264 '-fasynchronous-unwind-tables', 265 266 # Need -fipa-pure-const in order to make -Wsuggest-attribute=pure 267 # fire even without -O. 268 '-fipa-pure-const', 269 270 # We should eventually enable this, but right now there are at 271 # least 75 functions triggering warnings. 272 '-Wno-suggest-attribute=pure', 273 '-Wno-suggest-attribute=const', 274] 275 276# on aarch64 error: -fstack-protector not supported for this target 277if host_machine.cpu_family() != 'aarch64' 278 if host_machine.system() in [ 'linux', 'freebsd', 'windows' ] 279 # we prefer -fstack-protector-strong but fallback to -fstack-protector-all 280 fstack_cflags = cc.first_supported_argument([ 281 '-fstack-protector-strong', 282 '-fstack-protector-all', 283 ]) 284 cc_flags += fstack_cflags 285 286 # When building with mingw using -fstack-protector requires libssp library 287 # which is included by using -fstack-protector with linker. 288 if fstack_cflags.length() == 1 and host_machine.system() == 'windows' 289 add_project_link_arguments(fstack_cflags, language: 'c') 290 endif 291 endif 292endif 293 294# Clang complains about unused static inline functions which are common 295# with G_DEFINE_AUTOPTR_CLEANUP_FUNC. 296w_unused_function_args = ['-Wunused-function', '-Werror'] 297w_unused_function_code = ''' 298 static inline void foo(void) {} 299 300 int main(void) { return 0; } 301''' 302# -Wunused-function is implied by -Wall, we must turn it off explicitly. 303if not cc.compiles(w_unused_function_code, args: w_unused_function_args) 304 cc_flags += ['-Wno-unused-function'] 305endif 306 307cc_flags_disabled = [ 308 # In meson this is specified using 'c_std=gnu99' in project() function. 309 '-std=gnu99', 310 311 # don't care about C++ compiler compat 312 '-Wc++-compat', 313 '-Wabi', 314 '-Wdeprecated', 315 316 # Don't care about ancient C standard compat 317 '-Wtraditional', 318 '-Wtraditional-conversion', 319 320 # Ignore warnings in /usr/include 321 '-Wsystem-headers', 322 323 # Happy for compiler to add struct padding 324 '-Wpadded', 325 326 # GCC very confused with -O2 327 '-Wunreachable-code', 328 329 # Too many to deal with 330 '-Wconversion', 331 '-Wsign-conversion', 332 333 # Need to allow bad cast for execve() 334 '-Wcast-qual', 335 336 # We need to use long long in many places 337 '-Wlong-long', 338 339 # We allow manual list of all enum cases without default 340 '-Wswitch-default', 341 342 # Not a problem since we don't use -fstrict-overflow 343 '-Wstrict-overflow', 344 345 # Not a problem since we don't use -funsafe-loop-optimizations 346 '-Wunsafe-loop-optimizations', 347 348 # gcc 4.4.6 complains this is C++ only; gcc 4.7.0 implies this from -Wall 349 '-Wenum-compare', 350 351 # gcc 5.1 -Wformat-signedness mishandles enums, not ready for prime time 352 '-Wformat-signedness', 353 354 # Several conditionals expand the same on both branches depending on the 355 # particular platform/architecture 356 '-Wduplicated-branches', 357 358 # > This warning does not generally indicate that there is anything wrong 359 # > with your code; it merely indicates that GCC's optimizers are unable 360 # > to handle the code effectively. 361 # Source: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html 362 '-Wdisabled-optimization', 363 364 # Various valid glib APIs/macros trigger this warning 365 '-Wbad-function-cast', 366 367 # We might fundamentally need some of these disabled forever, but 368 # ideally we'd turn many of them on 369 '-Wfloat-equal', 370 '-Wpacked', 371 '-Wunused-macros', 372 '-Woverlength-strings', 373 '-Wstack-protector', 374 '-Wsuggest-attribute=malloc', 375 376 # g_return_val_if_fail usage violates this often 377 '-Wdeclaration-after-statement', 378] 379 380foreach flag : cc_flags_disabled 381 if cc_flags.contains(flag) 382 error('@0@ is disabled but listed in cc_flags'.format(flag)) 383 endif 384endforeach 385 386supported_cc_flags = cc.get_supported_arguments(cc_flags) 387add_project_arguments(supported_cc_flags, language: 'c') 388 389 390prefix = get_option('prefix') 391localedir = join_paths(prefix, get_option('localedir')) 392datadir = join_paths(prefix, get_option('datadir')) 393mandir = join_paths(prefix, get_option('mandir')) 394 395add_global_arguments('-DLOCALE_DIR="@0@"'.format(localedir), language: 'c') 396 397libm_dep = cc.find_library('m', required : true) 398 399glib_dep = dependency('glib-2.0', version: glib_min_version) 400gmodule_dep = dependency('gmodule-2.0', version: glib_min_version) 401gtk_dep = dependency('gtk+-3.0', version: gtk_min_version) 402 403libxml_dep = dependency('libxml-2.0', version: libxml_min_version) 404 405libvirt_dep = dependency('libvirt', version: libvirt_min_version, required: get_option('libvirt')) 406libvirt_glib_dep = dependency('libvirt-glib-1.0', version: libvirt_glib_min_version, required: get_option('libvirt')) 407if get_option('libvirt').auto() 408 if libvirt_dep.found() and not libvirt_glib_dep.found() 409 libvirt_dep = dependency('', required: false) 410 endif 411 if not libvirt_dep.found() and libvirt_glib_dep.found() 412 libvirt_glib_dep = dependency('', required: false) 413 endif 414endif 415if libvirt_dep.found() 416 conf_data.set('HAVE_LIBVIRT', '1') 417endif 418 419gtk_vnc_dep = dependency('gtk-vnc-2.0', version: gtk_vnc_min_version, required: get_option('vnc')) 420if gtk_vnc_dep.found() 421 conf_data.set('HAVE_GTK_VNC', '1') 422endif 423 424spice_glib_dep = dependency('spice-client-glib-2.0', version: spice_gtk_min_version, required: get_option('spice')) 425spice_gtk_dep = dependency('spice-client-gtk-3.0', version: spice_gtk_min_version, required: get_option('spice')) 426spice_protocol_dep = dependency('spice-protocol', version: spice_protocol_min_version, required: get_option('spice')) 427if get_option('spice').auto() 428 if not spice_protocol_dep.found() or not spice_gtk_dep.found() or not spice_glib_dep.found() 429 spice_protocol_dep = dependency('', required: false) 430 spice_glib_dep = dependency('', required: false) 431 spice_gtk_dep = dependency('', required: false) 432 endif 433endif 434if spice_gtk_dep.found() 435 conf_data.set('HAVE_SPICE_GTK', '1') 436endif 437 438govirt_dep = dependency('govirt-1.0', version: govirt_min_version, required: get_option('ovirt')) 439rest_dep = dependency('rest-0.7', version: rest_min_version, required: get_option('ovirt')) 440if get_option('ovirt').auto() 441 if govirt_dep.found() and not rest_dep.found() 442 govirt_dep = dependency('', required: false) 443 endif 444 if not govirt_dep.found() and rest_dep.found() 445 rest_dep = dependency('', required: false) 446 endif 447endif 448if govirt_dep.found() 449 if cc.has_function('ovirt_storage_domain_get_disks', dependencies: govirt_dep) 450 conf_data.set('HAVE_OVIRT_STORAGE_DOMAIN_GET_DISKS', '1') 451 endif 452 conf_data.set('HAVE_OVIRT', '1') 453endif 454 455vte_dep = dependency('vte-2.91', version: vte_min_version, required: get_option('vte')) 456if vte_dep.found() 457 conf_data.set('HAVE_VTE', '1') 458endif 459 460bash_completion_dep = dependency('bash-completion', version: '>=' + bash_completion_version, required: get_option('bash_completion')) 461 462if bash_completion_dep.found() 463 bash_completion_dir = get_option('bash_completion_dir') 464 if bash_completion_dir == '' 465 bash_completion_dir = bash_completion_dep.get_pkgconfig_variable('completionsdir') 466 bash_completion_prefix = bash_completion_dep.get_pkgconfig_variable('prefix') 467 rc = run_command( 468 'python3', '-c', 469 'print("@0@".replace("@1@", "@2@"))'.format( 470 bash_completion_dir, bash_completion_prefix, prefix, 471 ), 472 check: true, 473 ) 474 bash_completion_dir = rc.stdout().strip() 475 endif 476endif 477 478id = get_option('build-id') 479if id != '' 480 conf_data.set('BUILDID', '-@0@'.format(id)) 481else 482 conf_data.set('BUILDID', '') 483endif 484osid = get_option('os-id') 485if osid != '' 486 conf_data.set('REMOTE_VIEWER_OS_ID', '"' + osid + '"') 487endif 488 489arr_version = meson.project_version().split('.') 490 491conf_data.set('WINDOWS_PRODUCTVERSION', '@0@.@1@.@2@'.format( 492 arr_version[0], 493 arr_version[1], 494 get_option('build-id'))) 495 496if host_machine.system() == 'windows' 497 if host_machine.cpu() != 'x86_64' 498 wixl_arch = 'x86' 499 else 500 wixl_arch = 'x64' 501 endif 502 conf_data.set('WIXL_ARCH', wixl_arch) 503endif 504 505configure_file( 506 input: 'config.h.in', 507 output: 'config.h', 508 configuration: conf_data 509) 510 511if git 512 authors_helper = join_paths(meson.source_root(), 'build-aux', 'gen-authors.py') 513 authors = run_command(python3.path(), authors_helper, env: runutf8) 514 authors_file = 'AUTHORS.in' 515 516 authors_conf = configuration_data() 517 authors_conf.set('authorslist', authors.stdout()) 518 519 configure_file( 520 input: authors_file, 521 output: '@BASENAME@', 522 configuration: authors_conf, 523 ) 524 525 configure_file( 526 input: 'virt-viewer.spec.in', 527 output: 'virt-viewer.spec', 528 configuration: conf_data 529 ) 530 531 configure_file( 532 input: 'mingw-virt-viewer.spec.in', 533 output: 'mingw-virt-viewer.spec', 534 configuration: conf_data 535 ) 536 537 dist_helper = join_paths(meson.source_root(), 'build-aux', 'dist.py') 538 meson.add_dist_script(python3.path(), dist_helper, meson.build_root(), 'AUTHORS') 539 meson.add_dist_script(python3.path(), dist_helper, meson.build_root(), 'virt-viewer.spec') 540endif 541 542gnome = import('gnome') 543i18n = import('i18n') 544 545i18n_itsdir = join_paths(meson.source_root(), 'data', 'gettext') 546top_include_dir = [include_directories('.')] 547 548update_mime_database = find_program('update-mime-database', required: false) 549update_icon_cache = find_program('gtk-update-icon-cache', required: false) 550update_desktop_database = find_program('update-desktop-database', required: false) 551 552update_mime_database_path = '' 553if update_mime_database.found() 554 update_mime_database_path = update_mime_database.path() 555endif 556 557update_icon_cache_path = '' 558if update_icon_cache.found() 559 update_icon_cache_path = update_icon_cache.path() 560endif 561 562update_desktop_database_path = '' 563if update_desktop_database.found() 564 update_desktop_database_path = update_desktop_database.path() 565endif 566 567meson.add_install_script('build-aux/post_install.py', 568 update_mime_database_path, 569 update_icon_cache_path, 570 update_desktop_database_path) 571 572subdir('icons') 573subdir('src') 574subdir('po') 575subdir('man') 576subdir('tests') 577if bash_completion_dep.found() 578 subdir('bash-completion') 579endif 580subdir('data') 581