xref: /openbmc/qemu/meson.build (revision 2ebb09f34ffff152dda6d2b5d9a2348f3fefc6d3)
1project('qemu', ['c'], meson_version: '>=1.5.0',
2        default_options: ['warning_level=1', 'c_std=gnu11', 'cpp_std=gnu++11', 'b_colorout=auto',
3                          'b_staticpic=false', 'stdsplit=false', 'optimization=2', 'b_pie=true'],
4        version: files('VERSION'))
5
6meson.add_devenv({ 'MESON_BUILD_ROOT' : meson.project_build_root() })
7
8add_test_setup('quick', exclude_suites: ['slow', 'thorough'], is_default: true)
9add_test_setup('slow', exclude_suites: ['thorough'], env: ['G_TEST_SLOW=1', 'SPEED=slow'])
10add_test_setup('thorough', env: ['G_TEST_SLOW=1', 'SPEED=thorough'])
11
12meson.add_postconf_script(find_program('scripts/symlink-install-tree.py'))
13
14####################
15# Global variables #
16####################
17
18not_found = dependency('', required: false)
19keyval = import('keyval')
20rust = import('rust')
21ss = import('sourceset')
22fs = import('fs')
23
24host_os = host_machine.system()
25config_host = keyval.load(meson.current_build_dir() / 'config-host.mak')
26
27# Temporary directory used for files created while
28# configure runs. Since it is in the build directory
29# we can safely blow away any previous version of it
30# (and we need not jump through hoops to try to delete
31# it when configure exits.)
32tmpdir = meson.current_build_dir() / 'meson-private/temp'
33
34if get_option('qemu_suffix').startswith('/')
35  error('qemu_suffix cannot start with a /')
36endif
37
38qemu_confdir = get_option('sysconfdir') / get_option('qemu_suffix')
39qemu_datadir = get_option('datadir') / get_option('qemu_suffix')
40qemu_docdir = get_option('docdir') / get_option('qemu_suffix')
41qemu_moddir = get_option('libdir') / get_option('qemu_suffix')
42
43qemu_desktopdir = get_option('datadir') / 'applications'
44qemu_icondir = get_option('datadir') / 'icons'
45
46genh = []
47qapi_trace_events = []
48
49bsd_oses = ['gnu/kfreebsd', 'freebsd', 'netbsd', 'openbsd', 'dragonfly', 'darwin']
50supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux']
51supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv32', 'riscv64', 'x86', 'x86_64',
52  'arm', 'aarch64', 'loongarch64', 'mips', 'mips64', 'sparc64']
53
54cpu = host_machine.cpu_family()
55
56target_dirs = config_host['TARGET_DIRS'].split()
57
58# type of binaries to build
59have_linux_user = false
60have_bsd_user = false
61have_system = false
62foreach target : target_dirs
63  have_linux_user = have_linux_user or target.endswith('linux-user')
64  have_bsd_user = have_bsd_user or target.endswith('bsd-user')
65  have_system = have_system or target.endswith('-softmmu')
66endforeach
67have_user = have_linux_user or have_bsd_user
68
69############
70# Programs #
71############
72
73sh = find_program('sh')
74python = import('python').find_installation()
75
76cc = meson.get_compiler('c')
77all_languages = ['c']
78if host_os == 'windows' and add_languages('cpp', required: false, native: false)
79  all_languages += ['cpp']
80  cxx = meson.get_compiler('cpp')
81endif
82if host_os == 'darwin' and \
83   add_languages('objc', required: true, native: false)
84  all_languages += ['objc']
85  objc = meson.get_compiler('objc')
86endif
87
88have_rust = add_languages('rust', native: false,
89    required: get_option('rust').disable_auto_if(not have_system))
90have_rust = have_rust and add_languages('rust', native: true,
91    required: get_option('rust').disable_auto_if(not have_system))
92if have_rust
93  rustc = meson.get_compiler('rust')
94  if rustc.version().version_compare('<1.63.0')
95    if get_option('rust').enabled()
96      error('rustc version ' + rustc.version() + ' is unsupported. Please upgrade to at least 1.63.0')
97    else
98      warning('rustc version ' + rustc.version() + ' is unsupported, disabling Rust compilation.')
99      message('Please upgrade to at least 1.63.0 to use Rust.')
100      have_rust = false
101    endif
102  endif
103endif
104
105if have_rust
106  bindgen = find_program('bindgen', required: get_option('rust'))
107  if not bindgen.found() or bindgen.version().version_compare('<0.60.0')
108    if get_option('rust').enabled()
109      error('bindgen version ' + bindgen.version() + ' is unsupported. You can install a new version with "cargo install bindgen-cli"')
110    else
111      if bindgen.found()
112        warning('bindgen version ' + bindgen.version() + ' is unsupported, disabling Rust compilation.')
113      else
114        warning('bindgen not found, disabling Rust compilation.')
115      endif
116      message('To use Rust you can install a new version with "cargo install bindgen-cli"')
117      have_rust = false
118    endif
119  endif
120endif
121
122if have_rust
123  rustc_args = [find_program('scripts/rust/rustc_args.py'),
124    '--rustc-version', rustc.version(),
125    '--workspace', meson.project_source_root() / 'rust']
126  if get_option('strict_rust_lints')
127    rustc_args += ['--strict-lints']
128  endif
129
130  rustfmt = find_program('rustfmt', required: false)
131
132  rustc_lint_args = run_command(rustc_args, '--lints',
133     capture: true, check: true).stdout().strip().splitlines()
134
135  # Apart from procedural macros, our Rust executables will often link
136  # with C code, so include all the libraries that C code needs.  This
137  # is safe; https://github.com/rust-lang/rust/pull/54675 says that
138  # passing -nodefaultlibs to the linker "was more ideological to
139  # start with than anything".
140  add_project_arguments(rustc_lint_args +
141      ['--cfg', 'MESON', '-C', 'default-linker-libraries'],
142      native: false, language: 'rust')
143  add_project_arguments(rustc_lint_args + ['--cfg', 'MESON'],
144      native: true, language: 'rust')
145endif
146
147dtrace = not_found
148stap = not_found
149if 'dtrace' in get_option('trace_backends')
150  dtrace = find_program('dtrace', required: true)
151  stap = find_program('stap', required: false)
152  if stap.found()
153    # Workaround to avoid dtrace(1) producing a file with 'hidden' symbol
154    # visibility. Define STAP_SDT_V2 to produce 'default' symbol visibility
155    # instead. QEMU --enable-modules depends on this because the SystemTap
156    # semaphores are linked into the main binary and not the module's shared
157    # object.
158    add_global_arguments('-DSTAP_SDT_V2',
159                         native: false, language: all_languages)
160  endif
161endif
162
163if get_option('iasl') == ''
164  iasl = find_program('iasl', required: false)
165else
166  iasl = find_program(get_option('iasl'), required: true)
167endif
168
169edk2_targets = [ 'arm-softmmu', 'aarch64-softmmu', 'i386-softmmu', 'x86_64-softmmu', 'riscv64-softmmu', 'loongarch64-softmmu' ]
170unpack_edk2_blobs = false
171foreach target : edk2_targets
172  if target in target_dirs
173    bzip2 = find_program('bzip2', required: get_option('install_blobs'))
174    unpack_edk2_blobs = bzip2.found()
175    break
176  endif
177endforeach
178
179#####################
180# Option validation #
181#####################
182
183# Fuzzing
184if get_option('fuzzing') and get_option('fuzzing_engine') == '' and \
185    not cc.links('''
186          #include <stdint.h>
187          #include <sys/types.h>
188          int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
189          int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { return 0; }
190        ''',
191        args: ['-Werror', '-fsanitize=fuzzer'])
192  error('Your compiler does not support -fsanitize=fuzzer')
193endif
194
195# Tracing backends
196if 'ftrace' in get_option('trace_backends') and host_os != 'linux'
197  error('ftrace is supported only on Linux')
198endif
199if 'syslog' in get_option('trace_backends') and not cc.compiles('''
200    #include <syslog.h>
201    int main(void) {
202        openlog("qemu", LOG_PID, LOG_DAEMON);
203        syslog(LOG_INFO, "configure");
204        return 0;
205    }''')
206  error('syslog is not supported on this system')
207endif
208
209# Miscellaneous Linux-only features
210get_option('mpath') \
211  .require(host_os == 'linux', error_message: 'Multipath is supported only on Linux')
212
213multiprocess_allowed = get_option('multiprocess') \
214  .require(host_os == 'linux', error_message: 'Multiprocess QEMU is supported only on Linux') \
215  .allowed()
216
217vfio_user_server_allowed = get_option('vfio_user_server') \
218  .require(host_os == 'linux', error_message: 'vfio-user server is supported only on Linux') \
219  .allowed()
220
221have_tpm = get_option('tpm') \
222  .require(host_os != 'windows', error_message: 'TPM emulation only available on POSIX systems') \
223  .allowed()
224
225# vhost
226have_vhost_user = get_option('vhost_user') \
227  .disable_auto_if(host_os != 'linux') \
228  .require(host_os != 'windows',
229           error_message: 'vhost-user is not available on Windows').allowed()
230have_vhost_vdpa = get_option('vhost_vdpa') \
231  .require(host_os == 'linux',
232           error_message: 'vhost-vdpa is only available on Linux').allowed()
233have_vhost_kernel = get_option('vhost_kernel') \
234  .require(host_os == 'linux',
235           error_message: 'vhost-kernel is only available on Linux').allowed()
236have_vhost_user_crypto = get_option('vhost_crypto') \
237  .require(have_vhost_user,
238           error_message: 'vhost-crypto requires vhost-user to be enabled').allowed()
239
240have_vhost = have_vhost_user or have_vhost_vdpa or have_vhost_kernel
241
242have_vhost_net_user = have_vhost_user and get_option('vhost_net').allowed()
243have_vhost_net_vdpa = have_vhost_vdpa and get_option('vhost_net').allowed()
244have_vhost_net_kernel = have_vhost_kernel and get_option('vhost_net').allowed()
245have_vhost_net = have_vhost_net_kernel or have_vhost_net_user or have_vhost_net_vdpa
246
247have_tools = get_option('tools') \
248  .disable_auto_if(not have_system) \
249  .allowed()
250have_ga = get_option('guest_agent') \
251  .disable_auto_if(not have_system and not have_tools) \
252  .require(host_os in ['sunos', 'linux', 'windows', 'freebsd', 'netbsd', 'openbsd'],
253           error_message: 'unsupported OS for QEMU guest agent') \
254  .allowed()
255have_block = have_system or have_tools
256
257enable_modules = get_option('modules') \
258  .require(host_os != 'windows',
259           error_message: 'Modules are not available for Windows') \
260  .require(not get_option('prefer_static'),
261           error_message: 'Modules are incompatible with static linking') \
262  .allowed()
263
264#######################################
265# Variables for host and accelerators #
266#######################################
267
268if cpu not in supported_cpus
269  host_arch = 'unknown'
270elif cpu == 'x86'
271  host_arch = 'i386'
272elif cpu == 'mips64'
273  host_arch = 'mips'
274elif cpu in ['riscv32', 'riscv64']
275  host_arch = 'riscv'
276else
277  host_arch = cpu
278endif
279
280if cpu in ['x86', 'x86_64']
281  kvm_targets = ['i386-softmmu', 'x86_64-softmmu']
282elif cpu == 'aarch64'
283  kvm_targets = ['aarch64-softmmu']
284elif cpu == 's390x'
285  kvm_targets = ['s390x-softmmu']
286elif cpu in ['ppc', 'ppc64']
287  kvm_targets = ['ppc-softmmu', 'ppc64-softmmu']
288elif cpu in ['mips', 'mips64']
289  kvm_targets = ['mips-softmmu', 'mipsel-softmmu', 'mips64-softmmu', 'mips64el-softmmu']
290elif cpu in ['riscv32']
291  kvm_targets = ['riscv32-softmmu']
292elif cpu in ['riscv64']
293  kvm_targets = ['riscv64-softmmu']
294elif cpu in ['loongarch64']
295  kvm_targets = ['loongarch64-softmmu']
296else
297  kvm_targets = []
298endif
299accelerator_targets = { 'CONFIG_KVM': kvm_targets }
300
301if cpu in ['x86', 'x86_64']
302  xen_targets = ['i386-softmmu', 'x86_64-softmmu']
303elif cpu in ['arm', 'aarch64']
304  # i386 emulator provides xenpv machine type for multiple architectures
305  xen_targets = ['i386-softmmu', 'x86_64-softmmu', 'aarch64-softmmu']
306else
307  xen_targets = []
308endif
309accelerator_targets += { 'CONFIG_XEN': xen_targets }
310
311if cpu in ['aarch64']
312  accelerator_targets += {
313    'CONFIG_HVF': ['aarch64-softmmu']
314  }
315endif
316
317if cpu in ['x86', 'x86_64']
318  accelerator_targets += {
319    'CONFIG_HVF': ['x86_64-softmmu'],
320    'CONFIG_NVMM': ['i386-softmmu', 'x86_64-softmmu'],
321    'CONFIG_WHPX': ['i386-softmmu', 'x86_64-softmmu'],
322  }
323endif
324
325modular_tcg = []
326# Darwin does not support references to thread-local variables in modules
327if host_os != 'darwin'
328  modular_tcg = ['i386-softmmu', 'x86_64-softmmu']
329endif
330
331##################
332# Compiler flags #
333##################
334
335foreach lang : all_languages
336  compiler = meson.get_compiler(lang)
337  if compiler.get_id() == 'gcc' and compiler.version().version_compare('>=7.4')
338    # ok
339  elif compiler.get_id() == 'clang' and compiler.compiles('''
340      #ifdef __apple_build_version__
341      # if __clang_major__ < 15 || (__clang_major__ == 15 && __clang_minor__ < 0)
342      #  error You need at least XCode Clang v15.0 to compile QEMU
343      # endif
344      #else
345      # if __clang_major__ < 10 || (__clang_major__ == 10 && __clang_minor__ < 0)
346      #  error You need at least Clang v10.0 to compile QEMU
347      # endif
348      #endif''')
349    # ok
350  else
351    error('You either need GCC v7.4 or Clang v10.0 (or XCode Clang v15.0) to compile QEMU')
352  endif
353endforeach
354
355# default flags for all hosts
356# We use -fwrapv to tell the compiler that we require a C dialect where
357# left shift of signed integers is well defined and has the expected
358# 2s-complement style results. (Both clang and gcc agree that it
359# provides these semantics.)
360
361qemu_common_flags = [
362  '-D_GNU_SOURCE', '-D_FILE_OFFSET_BITS=64', '-D_LARGEFILE_SOURCE',
363  '-fno-strict-aliasing', '-fno-common', '-fwrapv' ]
364qemu_cflags = []
365qemu_ldflags = []
366
367if host_os == 'darwin'
368  # Disable attempts to use ObjectiveC features in os/object.h since they
369  # won't work when we're compiling with gcc as a C compiler.
370  if compiler.get_id() == 'gcc'
371    qemu_common_flags += '-DOS_OBJECT_USE_OBJC=0'
372  endif
373elif host_os == 'sunos'
374  # needed for CMSG_ macros in sys/socket.h
375  qemu_common_flags += '-D_XOPEN_SOURCE=600'
376  # needed for TIOCWIN* defines in termios.h
377  qemu_common_flags += '-D__EXTENSIONS__'
378elif host_os == 'haiku'
379  qemu_common_flags += ['-DB_USE_POSITIVE_POSIX_ERRORS', '-D_BSD_SOURCE', '-fPIC']
380elif host_os == 'windows'
381  # plugins use delaylib, and clang needs to be used with lld to make it work.
382  if compiler.get_id() == 'clang' and compiler.get_linker_id() != 'ld.lld'
383    error('On windows, you need to use lld with clang - use msys2 clang64/clangarm64 env')
384  endif
385endif
386
387# Choose instruction set (currently x86-only)
388
389qemu_isa_flags = []
390
391# __sync_fetch_and_and requires at least -march=i486. Many toolchains
392# use i686 as default anyway, but for those that don't, an explicit
393# specification is necessary
394if host_arch == 'i386' and not cc.links('''
395  static int sfaa(int *ptr)
396  {
397    return __sync_fetch_and_and(ptr, 0);
398  }
399
400  int main(void)
401  {
402    int val = 42;
403    val = __sync_val_compare_and_swap(&val, 0, 1);
404    sfaa(&val);
405    return val;
406  }''')
407  qemu_isa_flags += ['-march=i486']
408endif
409
410# Pick x86-64 baseline version
411if host_arch in ['i386', 'x86_64']
412  if get_option('x86_version') == '0' and host_arch == 'x86_64'
413    error('x86_64-v1 required for x86-64 hosts')
414  endif
415
416  # add flags for individual instruction set extensions
417  if get_option('x86_version') >= '1'
418    if host_arch == 'i386'
419      qemu_common_flags = ['-mfpmath=sse'] + qemu_common_flags
420    else
421      # present on basically all processors but technically not part of
422      # x86-64-v1, so only include -mneeded for x86-64 version 2 and above
423      qemu_isa_flags += ['-mcx16']
424    endif
425  endif
426  if get_option('x86_version') >= '2'
427    qemu_isa_flags += ['-mpopcnt']
428    qemu_isa_flags += cc.get_supported_arguments('-mneeded')
429  endif
430  if get_option('x86_version') >= '3'
431    qemu_isa_flags += ['-mmovbe', '-mabm', '-mbmi', '-mbmi2', '-mfma', '-mf16c']
432  endif
433
434  # add required vector instruction set (each level implies those below)
435  if get_option('x86_version') == '1'
436    qemu_isa_flags += ['-msse2']
437  elif get_option('x86_version') == '2'
438    qemu_isa_flags += ['-msse4.2']
439  elif get_option('x86_version') == '3'
440    qemu_isa_flags += ['-mavx2']
441  elif get_option('x86_version') == '4'
442    qemu_isa_flags += ['-mavx512f', '-mavx512bw', '-mavx512cd', '-mavx512dq', '-mavx512vl']
443  endif
444endif
445
446qemu_common_flags = qemu_isa_flags + qemu_common_flags
447
448if get_option('prefer_static')
449  qemu_ldflags += get_option('b_pie') ? '-static-pie' : '-static'
450endif
451
452# Meson currently only handles pie as a boolean for now, so if the user
453# has explicitly disabled PIE we need to extend our cflags.
454#
455# -no-pie is supposedly a linker flag that has no effect on the compiler
456# command line, but some distros, that didn't quite know what they were
457# doing, made local changes to gcc's specs file that turned it into
458# a compiler command-line flag.
459#
460# What about linker flags?  For a static build, no PIE is implied by -static
461# which we added above (and if it's not because of the same specs patching,
462# there's nothing we can do: compilation will fail, report a bug to your
463# distro and do not use --disable-pie in the meanwhile).  For dynamic linking,
464# instead, we can't add -no-pie because it overrides -shared: the linker then
465# tries to build an executable instead of a shared library and fails.  So
466# don't add -no-pie anywhere and cross fingers. :(
467if not get_option('b_pie')
468  qemu_common_flags += cc.get_supported_arguments('-fno-pie', '-no-pie')
469endif
470
471if not get_option('stack_protector').disabled()
472  stack_protector_probe = '''
473    int main(int argc, char *argv[])
474    {
475      char arr[64], *p = arr, *c = argv[argc - 1];
476      while (*c) {
477          *p++ = *c++;
478      }
479      return 0;
480    }'''
481  have_stack_protector = false
482  foreach arg : ['-fstack-protector-strong', '-fstack-protector-all']
483    # We need to check both a compile and a link, since some compiler
484    # setups fail only on a .c->.o compile and some only at link time
485    if cc.compiles(stack_protector_probe, args: ['-Werror', arg]) and \
486       cc.links(stack_protector_probe, args: ['-Werror', arg])
487      have_stack_protector = true
488      qemu_cflags += arg
489      qemu_ldflags += arg
490      break
491    endif
492  endforeach
493  get_option('stack_protector') \
494    .require(have_stack_protector, error_message: 'Stack protector not supported')
495endif
496
497coroutine_backend = get_option('coroutine_backend')
498ucontext_probe = '''
499  #include <ucontext.h>
500  #ifdef __stub_makecontext
501  #error Ignoring glibc stub makecontext which will always fail
502  #endif
503  int main(void) { makecontext(0, 0, 0); return 0; }'''
504
505# On Windows the only valid backend is the Windows specific one.
506# For POSIX prefer ucontext, but it's not always possible. The fallback
507# is sigcontext.
508supported_backends = []
509if host_os == 'windows'
510  supported_backends += ['windows']
511else
512  if host_os != 'darwin' and cc.links(ucontext_probe)
513    supported_backends += ['ucontext']
514  endif
515  supported_backends += ['sigaltstack']
516endif
517
518if coroutine_backend == 'auto'
519  coroutine_backend = supported_backends[0]
520elif coroutine_backend not in supported_backends
521  error('"@0@" backend requested but not available.  Available backends: @1@' \
522        .format(coroutine_backend, ', '.join(supported_backends)))
523endif
524
525# Compiles if SafeStack *not* enabled
526safe_stack_probe = '''
527  int main(void)
528  {
529  #if defined(__has_feature)
530  #if __has_feature(safe_stack)
531  #error SafeStack Enabled
532  #endif
533  #endif
534      return 0;
535  }'''
536if get_option('safe_stack') != not cc.compiles(safe_stack_probe)
537  safe_stack_arg = get_option('safe_stack') ? '-fsanitize=safe-stack' : '-fno-sanitize=safe-stack'
538  if get_option('safe_stack') != not cc.compiles(safe_stack_probe, args: safe_stack_arg)
539    error(get_option('safe_stack') \
540          ? 'SafeStack not supported by your compiler' \
541          : 'Cannot disable SafeStack')
542  endif
543  qemu_cflags += safe_stack_arg
544  qemu_ldflags += safe_stack_arg
545endif
546if get_option('safe_stack') and coroutine_backend != 'ucontext'
547  error('SafeStack is only supported with the ucontext coroutine backend')
548endif
549
550if get_option('asan')
551  if cc.has_argument('-fsanitize=address')
552    qemu_cflags = ['-fsanitize=address'] + qemu_cflags
553    qemu_ldflags = ['-fsanitize=address'] + qemu_ldflags
554  else
555    error('Your compiler does not support -fsanitize=address')
556  endif
557endif
558
559if get_option('ubsan')
560  # Detect static linking issue with ubsan:
561  # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84285
562  if cc.links('int main(int argc, char **argv) { return argc + 1; }',
563              args: [qemu_ldflags, '-fsanitize=undefined'])
564    qemu_cflags += ['-fsanitize=undefined']
565    qemu_ldflags += ['-fsanitize=undefined']
566
567    # Suppress undefined behaviour from function call to mismatched type.
568    # In addition, tcg prologue does not emit function type prefix
569    # required by function call sanitizer.
570    if cc.has_argument('-fno-sanitize=function')
571      qemu_cflags += ['-fno-sanitize=function']
572    endif
573  else
574    error('Your compiler does not support -fsanitize=undefined')
575  endif
576endif
577
578# Thread sanitizer is, for now, much noisier than the other sanitizers;
579# keep it separate until that is not the case.
580if get_option('tsan')
581  if get_option('asan') or get_option('ubsan')
582    error('TSAN is not supported with other sanitizers')
583  endif
584  if not cc.has_function('__tsan_create_fiber',
585                         args: '-fsanitize=thread',
586                         prefix: '#include <sanitizer/tsan_interface.h>')
587    error('Cannot enable TSAN due to missing fiber annotation interface')
588  endif
589  tsan_warn_suppress = []
590  # gcc (>=11) will report constructions not supported by tsan:
591  # "error: ‘atomic_thread_fence’ is not supported with ‘-fsanitize=thread’"
592  # https://gcc.gnu.org/gcc-11/changes.html
593  # However, clang does not support this warning and this triggers an error.
594  if cc.has_argument('-Wno-tsan')
595    tsan_warn_suppress = ['-Wno-tsan']
596  endif
597  qemu_cflags = ['-fsanitize=thread'] + tsan_warn_suppress + qemu_cflags
598  qemu_ldflags = ['-fsanitize=thread'] + qemu_ldflags
599endif
600
601# Detect support for PT_GNU_RELRO + DT_BIND_NOW.
602# The combination is known as "full relro", because .got.plt is read-only too.
603qemu_ldflags += cc.get_supported_link_arguments('-Wl,-z,relro', '-Wl,-z,now')
604
605if host_os == 'windows'
606  qemu_ldflags += cc.get_supported_link_arguments('-Wl,--no-seh', '-Wl,--nxcompat')
607  qemu_ldflags += cc.get_supported_link_arguments('-Wl,--dynamicbase', '-Wl,--high-entropy-va')
608endif
609
610if get_option('fuzzing')
611  # Specify a filter to only instrument code that is directly related to
612  # virtual-devices.
613  configure_file(output: 'instrumentation-filter',
614                 input: 'scripts/oss-fuzz/instrumentation-filter-template',
615                 copy: true)
616
617  if cc.compiles('int main () { return 0; }',
618                  name: '-fsanitize-coverage-allowlist=/dev/null',
619                 args: ['-fsanitize-coverage-allowlist=/dev/null',
620                        '-fsanitize-coverage=trace-pc'] )
621    qemu_common_flags += ['-fsanitize-coverage-allowlist=instrumentation-filter']
622  endif
623
624  if get_option('fuzzing_engine') == ''
625    # Add CFLAGS to tell clang to add fuzzer-related instrumentation to all the
626    # compiled code.  To build non-fuzzer binaries with --enable-fuzzing, link
627    # everything with fsanitize=fuzzer-no-link. Otherwise, the linker will be
628    # unable to bind the fuzzer-related callbacks added by instrumentation.
629    qemu_common_flags += ['-fsanitize=fuzzer-no-link']
630    qemu_ldflags += ['-fsanitize=fuzzer-no-link']
631    # For the actual fuzzer binaries, we need to link against the libfuzzer
632    # library. They need to be configurable, to support OSS-Fuzz
633    fuzz_exe_ldflags = ['-fsanitize=fuzzer']
634  else
635    # LIB_FUZZING_ENGINE was set; assume we are running on OSS-Fuzz, and
636    # the needed CFLAGS have already been provided
637    fuzz_exe_ldflags = get_option('fuzzing_engine').split()
638  endif
639endif
640
641if get_option('cfi')
642  cfi_flags=[]
643  # Check for dependency on LTO
644  if not get_option('b_lto')
645    error('Selected Control-Flow Integrity but LTO is disabled')
646  endif
647  if enable_modules
648    error('Selected Control-Flow Integrity is not compatible with modules')
649  endif
650  # Check for cfi flags. CFI requires LTO so we can't use
651  # get_supported_arguments, but need a more complex "compiles" which allows
652  # custom arguments
653  if cc.compiles('int main () { return 0; }', name: '-fsanitize=cfi-icall',
654                 args: ['-flto', '-fsanitize=cfi-icall'] )
655    cfi_flags += '-fsanitize=cfi-icall'
656  else
657    error('-fsanitize=cfi-icall is not supported by the compiler')
658  endif
659  if cc.compiles('int main () { return 0; }',
660                 name: '-fsanitize-cfi-icall-generalize-pointers',
661                 args: ['-flto', '-fsanitize=cfi-icall',
662                        '-fsanitize-cfi-icall-generalize-pointers'] )
663    cfi_flags += '-fsanitize-cfi-icall-generalize-pointers'
664  else
665    error('-fsanitize-cfi-icall-generalize-pointers is not supported by the compiler')
666  endif
667  if get_option('cfi_debug')
668    if cc.compiles('int main () { return 0; }',
669                   name: '-fno-sanitize-trap=cfi-icall',
670                   args: ['-flto', '-fsanitize=cfi-icall',
671                          '-fno-sanitize-trap=cfi-icall'] )
672      cfi_flags += '-fno-sanitize-trap=cfi-icall'
673    else
674      error('-fno-sanitize-trap=cfi-icall is not supported by the compiler')
675    endif
676  endif
677  add_global_arguments(cfi_flags, native: false, language: all_languages)
678  add_global_link_arguments(cfi_flags, native: false, language: all_languages)
679endif
680
681# Check further flags that make QEMU more robust against malicious parties
682
683hardening_flags = [
684    # Initialize all stack variables to zero. This makes
685    # it harder to take advantage of uninitialized stack
686    # data to drive exploits
687    '-ftrivial-auto-var-init=zero',
688]
689
690# Zero out registers used during a function call
691# upon its return. This makes it harder to assemble
692# ROP gadgets into something usable
693#
694# NB: Clang 17 is broken and SEGVs
695# https://github.com/llvm/llvm-project/issues/75168
696#
697# NB2: This clashes with the "retguard" extension of OpenBSD's Clang
698# https://gitlab.com/qemu-project/qemu/-/issues/2278
699if host_os != 'openbsd' and \
700   cc.compiles('extern struct { void (*cb)(void); } s; void f(void) { s.cb(); }',
701               name: '-fzero-call-used-regs=used-gpr',
702               args: ['-O2', '-fzero-call-used-regs=used-gpr'])
703    hardening_flags += '-fzero-call-used-regs=used-gpr'
704endif
705
706qemu_common_flags += cc.get_supported_arguments(hardening_flags)
707
708add_global_arguments(qemu_common_flags, native: false, language: all_languages)
709add_global_link_arguments(qemu_ldflags, native: false, language: all_languages)
710
711# Collect warning flags we want to set, sorted alphabetically
712warn_flags = [
713  # First enable interesting warnings
714  '-Wempty-body',
715  '-Wendif-labels',
716  '-Wexpansion-to-defined',
717  '-Wformat-security',
718  '-Wformat-y2k',
719  '-Wignored-qualifiers',
720  '-Wimplicit-fallthrough=2',
721  '-Winit-self',
722  '-Wmissing-format-attribute',
723  '-Wmissing-prototypes',
724  '-Wnested-externs',
725  '-Wold-style-declaration',
726  '-Wold-style-definition',
727  '-Wredundant-decls',
728  '-Wshadow=local',
729  '-Wstrict-prototypes',
730  '-Wtype-limits',
731  '-Wundef',
732  '-Wvla',
733  '-Wwrite-strings',
734
735  # Then disable some undesirable warnings
736  '-Wno-gnu-variable-sized-type-not-at-end',
737  '-Wno-initializer-overrides',
738  '-Wno-missing-include-dirs',
739  '-Wno-psabi',
740  '-Wno-shift-negative-value',
741  '-Wno-string-plus-int',
742  '-Wno-tautological-type-limit-compare',
743  '-Wno-typedef-redefinition',
744]
745
746if host_os != 'darwin'
747  tsa_has_cleanup = cc.compiles('''
748    struct __attribute__((capability("mutex"))) mutex {};
749    void lock(struct mutex *m) __attribute__((acquire_capability(m)));
750    void unlock(struct mutex *m) __attribute__((release_capability(m)));
751
752    void test(void) {
753      struct mutex __attribute__((cleanup(unlock))) m;
754      lock(&m);
755    }
756  ''', args: ['-Wthread-safety', '-Werror'])
757  if tsa_has_cleanup
758    warn_flags += ['-Wthread-safety']
759  endif
760endif
761
762# Set up C++ compiler flags
763qemu_cxxflags = []
764if 'cpp' in all_languages
765  qemu_cxxflags = ['-D__STDC_LIMIT_MACROS', '-D__STDC_CONSTANT_MACROS', '-D__STDC_FORMAT_MACROS'] + qemu_cflags
766endif
767
768add_project_arguments(qemu_cflags, native: false, language: 'c')
769add_project_arguments(cc.get_supported_arguments(warn_flags), native: false, language: 'c')
770if 'cpp' in all_languages
771  add_project_arguments(qemu_cxxflags, native: false, language: 'cpp')
772  add_project_arguments(cxx.get_supported_arguments(warn_flags), native: false, language: 'cpp')
773endif
774if 'objc' in all_languages
775  # Note sanitizer flags are not applied to Objective-C sources!
776  add_project_arguments(objc.get_supported_arguments(warn_flags), native: false, language: 'objc')
777endif
778if host_os == 'linux'
779  add_project_arguments('-isystem', meson.current_source_dir() / 'linux-headers',
780                        '-isystem', 'linux-headers',
781                        language: all_languages)
782endif
783
784add_project_arguments('-iquote', '.',
785                      '-iquote', meson.current_source_dir(),
786                      '-iquote', meson.current_source_dir() / 'include',
787                      language: all_languages)
788
789# If a host-specific include directory exists, list that first...
790host_include = meson.current_source_dir() / 'host/include/'
791if fs.is_dir(host_include / host_arch)
792  add_project_arguments('-iquote', host_include / host_arch,
793                        language: all_languages)
794endif
795# ... followed by the generic fallback.
796add_project_arguments('-iquote', host_include / 'generic',
797                      language: all_languages)
798
799sparse = find_program('cgcc', required: get_option('sparse'))
800if sparse.found()
801  run_target('sparse',
802             command: [find_program('scripts/check_sparse.py'),
803                       'compile_commands.json', sparse.full_path(), '-Wbitwise',
804                       '-Wno-transparent-union', '-Wno-old-initializer',
805                       '-Wno-non-pointer-null'])
806endif
807
808#####################################
809# Host-specific libraries and flags #
810#####################################
811
812libm = cc.find_library('m', required: false)
813threads = dependency('threads')
814util = cc.find_library('util', required: false)
815winmm = []
816socket = []
817version_res = []
818coref = []
819iokit = []
820pvg = not_found
821metal = []
822emulator_link_args = []
823midl = not_found
824widl = not_found
825pathcch = not_found
826host_dsosuf = '.so'
827if host_os == 'windows'
828  midl = find_program('midl', required: false)
829  widl = find_program('widl', required: false)
830  pathcch = cc.find_library('pathcch')
831  socket = cc.find_library('ws2_32')
832  winmm = cc.find_library('winmm')
833
834  win = import('windows')
835  version_res = win.compile_resources('version.rc',
836                                      depend_files: files('pc-bios/qemu-nsis.ico'),
837                                      include_directories: include_directories('.'))
838  host_dsosuf = '.dll'
839elif host_os == 'darwin'
840  coref = dependency('appleframeworks', modules: 'CoreFoundation')
841  iokit = dependency('appleframeworks', modules: 'IOKit', required: false)
842  host_dsosuf = '.dylib'
843  pvg = dependency('appleframeworks', modules: 'ParavirtualizedGraphics')
844  metal = dependency('appleframeworks', modules: 'Metal')
845elif host_os == 'sunos'
846  socket = [cc.find_library('socket'),
847            cc.find_library('nsl'),
848            cc.find_library('resolv')]
849elif host_os == 'haiku'
850  socket = [cc.find_library('posix_error_mapper'),
851            cc.find_library('network'),
852            cc.find_library('bsd')]
853elif host_os == 'openbsd'
854  if get_option('tcg').allowed() and target_dirs.length() > 0
855    # Disable OpenBSD W^X if available
856    emulator_link_args = cc.get_supported_link_arguments('-Wl,-z,wxneeded')
857  endif
858endif
859
860###############################################
861# Host-specific configuration of accelerators #
862###############################################
863
864accelerators = []
865if get_option('kvm').allowed() and host_os == 'linux'
866  accelerators += 'CONFIG_KVM'
867endif
868if get_option('whpx').allowed() and host_os == 'windows'
869  if get_option('whpx').enabled() and host_machine.cpu() != 'x86_64'
870    error('WHPX requires 64-bit host')
871  elif cc.has_header('winhvplatform.h', required: get_option('whpx')) and \
872       cc.has_header('winhvemulation.h', required: get_option('whpx'))
873    accelerators += 'CONFIG_WHPX'
874  endif
875endif
876
877hvf = not_found
878if get_option('hvf').allowed()
879  hvf = dependency('appleframeworks', modules: 'Hypervisor',
880                   required: get_option('hvf'))
881  if hvf.found()
882    accelerators += 'CONFIG_HVF'
883  endif
884endif
885
886nvmm = not_found
887if host_os == 'netbsd'
888  nvmm = cc.find_library('nvmm', required: get_option('nvmm'))
889  if nvmm.found()
890    accelerators += 'CONFIG_NVMM'
891  endif
892endif
893
894tcg_arch = host_arch
895if get_option('tcg').allowed()
896  if host_arch == 'unknown'
897    if not get_option('tcg_interpreter')
898      error('Unsupported CPU @0@, try --enable-tcg-interpreter'.format(cpu))
899    endif
900  elif get_option('tcg_interpreter')
901    warning('Use of the TCG interpreter is not recommended on this host')
902    warning('architecture. There is a native TCG execution backend available')
903    warning('which provides substantially better performance and reliability.')
904    warning('It is strongly recommended to remove the --enable-tcg-interpreter')
905    warning('configuration option on this architecture to use the native')
906    warning('backend.')
907  endif
908  if get_option('tcg_interpreter')
909    tcg_arch = 'tci'
910  elif host_arch == 'x86_64'
911    tcg_arch = 'i386'
912  elif host_arch == 'ppc64'
913    tcg_arch = 'ppc'
914  endif
915  add_project_arguments('-iquote', meson.current_source_dir() / 'tcg' / tcg_arch,
916                        language: all_languages)
917
918  accelerators += 'CONFIG_TCG'
919endif
920
921if 'CONFIG_KVM' not in accelerators and get_option('kvm').enabled()
922  error('KVM not available on this platform')
923endif
924if 'CONFIG_HVF' not in accelerators and get_option('hvf').enabled()
925  error('HVF not available on this platform')
926endif
927if 'CONFIG_NVMM' not in accelerators and get_option('nvmm').enabled()
928  error('NVMM not available on this platform')
929endif
930if 'CONFIG_WHPX' not in accelerators and get_option('whpx').enabled()
931  error('WHPX not available on this platform')
932endif
933
934xen = not_found
935if get_option('xen').enabled() or (get_option('xen').auto() and have_system)
936  xencontrol = dependency('xencontrol', required: false,
937                          method: 'pkg-config')
938  if xencontrol.found()
939    xen_pc = declare_dependency(version: xencontrol.version(),
940      dependencies: [
941        xencontrol,
942        # disabler: true makes xen_pc.found() return false if any is not found
943        dependency('xenstore', required: false,
944                   method: 'pkg-config',
945                   disabler: true),
946        dependency('xenforeignmemory', required: false,
947                   method: 'pkg-config',
948                   disabler: true),
949        dependency('xengnttab', required: false,
950                   method: 'pkg-config',
951                   disabler: true),
952        dependency('xenevtchn', required: false,
953                   method: 'pkg-config',
954                   disabler: true),
955        dependency('xendevicemodel', required: false,
956                   method: 'pkg-config',
957                   disabler: true),
958        # optional, no "disabler: true"
959        dependency('xentoolcore', required: false,
960                   method: 'pkg-config')])
961    if xen_pc.found()
962      xen = xen_pc
963    endif
964  endif
965  if not xen.found()
966    xen_tests = [ '4.11.0', '4.10.0', '4.9.0', '4.8.0', '4.7.1' ]
967    xen_libs = {
968      '4.11.0': [ 'xenstore', 'xenctrl', 'xendevicemodel', 'xenforeignmemory', 'xengnttab', 'xenevtchn', 'xentoolcore' ],
969      '4.10.0': [ 'xenstore', 'xenctrl', 'xendevicemodel', 'xenforeignmemory', 'xengnttab', 'xenevtchn', 'xentoolcore' ],
970      '4.9.0': [ 'xenstore', 'xenctrl', 'xendevicemodel', 'xenforeignmemory', 'xengnttab', 'xenevtchn' ],
971      '4.8.0': [ 'xenstore', 'xenctrl', 'xenforeignmemory', 'xengnttab', 'xenevtchn' ],
972      '4.7.1': [ 'xenstore', 'xenctrl', 'xenforeignmemory', 'xengnttab', 'xenevtchn' ],
973    }
974    xen_deps = {}
975    foreach ver: xen_tests
976      # cache the various library tests to avoid polluting the logs
977      xen_test_deps = []
978      foreach l: xen_libs[ver]
979        if l not in xen_deps
980          xen_deps += { l: cc.find_library(l, required: false) }
981        endif
982        xen_test_deps += xen_deps[l]
983      endforeach
984
985      # Use -D to pick just one of the test programs in scripts/xen-detect.c
986      xen_version = ver.split('.')
987      xen_ctrl_version = xen_version[0] + \
988        ('0' + xen_version[1]).substring(-2) + \
989        ('0' + xen_version[2]).substring(-2)
990      if cc.links(files('scripts/xen-detect.c'),
991                  args: '-DCONFIG_XEN_CTRL_INTERFACE_VERSION=' + xen_ctrl_version,
992                  dependencies: xen_test_deps)
993        xen = declare_dependency(version: ver, dependencies: xen_test_deps)
994        break
995      endif
996    endforeach
997  endif
998  if xen.found()
999    accelerators += 'CONFIG_XEN'
1000  elif get_option('xen').enabled()
1001    error('could not compile and link Xen test program')
1002  endif
1003endif
1004have_xen_pci_passthrough = get_option('xen_pci_passthrough') \
1005  .require(xen.found(),
1006           error_message: 'Xen PCI passthrough requested but Xen not enabled') \
1007  .require(host_os == 'linux',
1008           error_message: 'Xen PCI passthrough not available on this platform') \
1009  .require(cpu == 'x86'  or cpu == 'x86_64',
1010           error_message: 'Xen PCI passthrough not available on this platform') \
1011  .allowed()
1012
1013################
1014# Dependencies #
1015################
1016
1017# When bumping glib minimum version, please check also whether to increase
1018# the _WIN32_WINNT setting in osdep.h according to the value from glib.
1019# You should also check if any of the glib.version() checks
1020# below can also be removed.
1021glib_req_ver = '>=2.66.0'
1022glib_pc = dependency('glib-2.0', version: glib_req_ver, required: true,
1023                    method: 'pkg-config')
1024glib_cflags = []
1025if enable_modules
1026  gmodule = dependency('gmodule-export-2.0', version: glib_req_ver, required: true,
1027                       method: 'pkg-config')
1028elif get_option('plugins')
1029  gmodule = dependency('gmodule-no-export-2.0', version: glib_req_ver, required: true,
1030                       method: 'pkg-config')
1031else
1032  gmodule = not_found
1033endif
1034
1035# This workaround is required due to a bug in pkg-config file for glib as it
1036# doesn't define GLIB_STATIC_COMPILATION for pkg-config --static
1037if host_os == 'windows' and get_option('prefer_static')
1038  glib_cflags += ['-DGLIB_STATIC_COMPILATION']
1039endif
1040
1041# Sanity check that the current size_t matches the
1042# size that glib thinks it should be. This catches
1043# problems on multi-arch where people try to build
1044# 32-bit QEMU while pointing at 64-bit glib headers
1045
1046if not cc.compiles('''
1047  #include <glib.h>
1048  #include <unistd.h>
1049
1050  #define QEMU_BUILD_BUG_ON(x) \
1051  typedef char qemu_build_bug_on[(x)?-1:1] __attribute__((unused));
1052
1053  int main(void) {
1054     QEMU_BUILD_BUG_ON(sizeof(size_t) != GLIB_SIZEOF_SIZE_T);
1055     return 0;
1056  }''', dependencies: glib_pc, args: glib_cflags)
1057  error('''sizeof(size_t) doesn't match GLIB_SIZEOF_SIZE_T.
1058        You probably need to set PKG_CONFIG_LIBDIR" to point
1059        to the right pkg-config files for your build target.''')
1060endif
1061
1062glib = declare_dependency(dependencies: [glib_pc, gmodule],
1063                          compile_args: glib_cflags,
1064                          version: glib_pc.version())
1065
1066# Check whether glib has gslice, which we have to avoid for correctness.
1067# TODO: remove this check and the corresponding workaround (qtree) when
1068# the minimum supported glib is >= 2.75.3
1069glib_has_gslice = glib.version().version_compare('<2.75.3')
1070# Check whether glib has the aligned_alloc family of functions.
1071# <https://docs.gtk.org/glib/func.aligned_alloc.html>
1072glib_has_aligned_alloc = glib.version().version_compare('>=2.72.0')
1073
1074# override glib dep to include the above refinements
1075meson.override_dependency('glib-2.0', glib)
1076
1077# The path to glib.h is added to all compilation commands.
1078add_project_dependencies(glib.partial_dependency(compile_args: true, includes: true),
1079                         native: false, language: all_languages)
1080
1081gio = not_found
1082gdbus_codegen = not_found
1083gdbus_codegen_error = '@0@ requires gdbus-codegen, please install libgio'
1084if not get_option('gio').auto() or have_system
1085  gio = dependency('gio-2.0', required: get_option('gio'),
1086                   method: 'pkg-config')
1087  if gio.found() and not cc.links('''
1088    #include <gio/gio.h>
1089    int main(void)
1090    {
1091      g_dbus_proxy_new_sync(0, 0, 0, 0, 0, 0, 0, 0);
1092      return 0;
1093    }''', dependencies: [glib, gio])
1094    if get_option('gio').enabled()
1095      error('The installed libgio is broken for static linking')
1096    endif
1097    gio = not_found
1098  endif
1099  if gio.found()
1100    gdbus_codegen = find_program('gdbus-codegen',
1101                                 required: get_option('gio'))
1102    gio_unix = dependency('gio-unix-2.0', required: get_option('gio'),
1103                          method: 'pkg-config')
1104    gio = declare_dependency(dependencies: [gio, gio_unix],
1105                             version: gio.version())
1106  endif
1107endif
1108if gdbus_codegen.found() and get_option('cfi')
1109  gdbus_codegen = not_found
1110  gdbus_codegen_error = '@0@ uses gdbus-codegen, which does not support control flow integrity'
1111endif
1112
1113xml_pp = find_program('scripts/xml-preprocess.py')
1114
1115lttng = not_found
1116if 'ust' in get_option('trace_backends')
1117  lttng = dependency('lttng-ust', required: true, version: '>= 2.1',
1118                     method: 'pkg-config')
1119endif
1120pixman = not_found
1121if not get_option('pixman').auto() or have_system or have_tools
1122  pixman = dependency('pixman-1', required: get_option('pixman'), version:'>=0.21.8',
1123                      method: 'pkg-config')
1124endif
1125
1126zlib = dependency('zlib', required: true)
1127
1128libaio = not_found
1129if not get_option('linux_aio').auto() or have_block
1130  libaio = cc.find_library('aio', has_headers: ['libaio.h'],
1131                           required: get_option('linux_aio'))
1132endif
1133
1134linux_io_uring_test = '''
1135  #include <liburing.h>
1136  #include <linux/errqueue.h>
1137
1138  int main(void) { return 0; }'''
1139
1140linux_io_uring = not_found
1141if not get_option('linux_io_uring').auto() or have_block
1142  linux_io_uring = dependency('liburing', version: '>=0.3',
1143                              required: get_option('linux_io_uring'),
1144                              method: 'pkg-config')
1145  if not cc.links(linux_io_uring_test)
1146    linux_io_uring = not_found
1147  endif
1148endif
1149
1150libnfs = not_found
1151if not get_option('libnfs').auto() or have_block
1152  libnfs = dependency('libnfs', version: ['>=1.9.3', '<6.0.0'],
1153                      required: get_option('libnfs'),
1154                      method: 'pkg-config')
1155endif
1156
1157libattr_test = '''
1158  #include <stddef.h>
1159  #include <sys/types.h>
1160  #ifdef CONFIG_LIBATTR
1161  #include <attr/xattr.h>
1162  #else
1163  #include <sys/xattr.h>
1164  #endif
1165  int main(void) { getxattr(NULL, NULL, NULL, 0); setxattr(NULL, NULL, NULL, 0, 0); return 0; }'''
1166
1167libattr = not_found
1168have_old_libattr = false
1169if get_option('attr').allowed()
1170  if cc.links(libattr_test)
1171    libattr = declare_dependency()
1172  else
1173    libattr = cc.find_library('attr', has_headers: ['attr/xattr.h'],
1174                              required: get_option('attr'))
1175    if libattr.found() and not \
1176      cc.links(libattr_test, dependencies: libattr, args: '-DCONFIG_LIBATTR')
1177      libattr = not_found
1178      if get_option('attr').enabled()
1179        error('could not link libattr')
1180      else
1181        warning('could not link libattr, disabling')
1182      endif
1183    else
1184      have_old_libattr = libattr.found()
1185    endif
1186  endif
1187endif
1188
1189cocoa = dependency('appleframeworks',
1190                   modules: ['Cocoa', 'CoreVideo', 'QuartzCore'],
1191                   required: get_option('cocoa'))
1192
1193vmnet = dependency('appleframeworks', modules: 'vmnet', required: get_option('vmnet'))
1194if vmnet.found() and not cc.has_header_symbol('vmnet/vmnet.h',
1195                                              'VMNET_BRIDGED_MODE',
1196                                              dependencies: vmnet)
1197  vmnet = not_found
1198  if get_option('vmnet').enabled()
1199    error('vmnet.framework API is outdated')
1200  else
1201    warning('vmnet.framework API is outdated, disabling')
1202  endif
1203endif
1204
1205seccomp = not_found
1206seccomp_has_sysrawrc = false
1207if not get_option('seccomp').auto() or have_system or have_tools
1208  seccomp = dependency('libseccomp', version: '>=2.3.0',
1209                       required: get_option('seccomp'),
1210                       method: 'pkg-config')
1211  if seccomp.found()
1212    seccomp_has_sysrawrc = cc.has_header_symbol('seccomp.h',
1213                                                'SCMP_FLTATR_API_SYSRAWRC',
1214                                                dependencies: seccomp)
1215  endif
1216endif
1217
1218libcap_ng = not_found
1219if not get_option('cap_ng').auto() or have_system or have_tools
1220  libcap_ng = cc.find_library('cap-ng', has_headers: ['cap-ng.h'],
1221                              required: get_option('cap_ng'))
1222endif
1223if libcap_ng.found() and not cc.links('''
1224   #include <cap-ng.h>
1225   int main(void)
1226   {
1227     capng_capability_to_name(CAPNG_EFFECTIVE);
1228     return 0;
1229   }''', dependencies: libcap_ng)
1230  libcap_ng = not_found
1231  if get_option('cap_ng').enabled()
1232    error('could not link libcap-ng')
1233  else
1234    warning('could not link libcap-ng, disabling')
1235  endif
1236endif
1237
1238if get_option('xkbcommon').auto() and not have_system and not have_tools
1239  xkbcommon = not_found
1240else
1241  xkbcommon = dependency('xkbcommon', required: get_option('xkbcommon'),
1242                         method: 'pkg-config')
1243endif
1244
1245slirp = not_found
1246if not get_option('slirp').auto() or have_system
1247  slirp = dependency('slirp', required: get_option('slirp'),
1248                     method: 'pkg-config')
1249  # slirp < 4.7 is incompatible with CFI support in QEMU.  This is because
1250  # it passes function pointers within libslirp as callbacks for timers.
1251  # When using a system-wide shared libslirp, the type information for the
1252  # callback is missing and the timer call produces a false positive with CFI.
1253  # Do not use the "version" keyword argument to produce a better error.
1254  # with control-flow integrity.
1255  if get_option('cfi') and slirp.found() and slirp.version().version_compare('<4.7')
1256    if get_option('slirp').enabled()
1257      error('Control-Flow Integrity requires libslirp 4.7.')
1258    else
1259      warning('Cannot use libslirp since Control-Flow Integrity requires libslirp >= 4.7.')
1260      slirp = not_found
1261    endif
1262  endif
1263endif
1264
1265vde = not_found
1266if not get_option('vde').auto() or have_system or have_tools
1267  vde = cc.find_library('vdeplug', has_headers: ['libvdeplug.h'],
1268                           required: get_option('vde'))
1269endif
1270if vde.found() and not cc.links('''
1271   #include <libvdeplug.h>
1272   int main(void)
1273   {
1274     struct vde_open_args a = {0, 0, 0};
1275     char s[] = "";
1276     vde_open(s, s, &a);
1277     return 0;
1278   }''', dependencies: vde)
1279  vde = not_found
1280  if get_option('cap_ng').enabled()
1281    error('could not link libvdeplug')
1282  else
1283    warning('could not link libvdeplug, disabling')
1284  endif
1285endif
1286
1287pulse = not_found
1288if not get_option('pa').auto() or (host_os == 'linux' and have_system)
1289  pulse = dependency('libpulse', required: get_option('pa'),
1290                     method: 'pkg-config')
1291endif
1292alsa = not_found
1293if not get_option('alsa').auto() or (host_os == 'linux' and have_system)
1294  alsa = dependency('alsa', required: get_option('alsa'),
1295                    method: 'pkg-config')
1296endif
1297jack = not_found
1298if not get_option('jack').auto() or have_system
1299  jack = dependency('jack', required: get_option('jack'),
1300                    method: 'pkg-config')
1301endif
1302pipewire = not_found
1303if not get_option('pipewire').auto() or (host_os == 'linux' and have_system)
1304  pipewire = dependency('libpipewire-0.3', version: '>=0.3.60',
1305                    required: get_option('pipewire'),
1306                    method: 'pkg-config')
1307endif
1308sndio = not_found
1309if not get_option('sndio').auto() or have_system
1310  sndio = dependency('sndio', required: get_option('sndio'),
1311                    method: 'pkg-config')
1312endif
1313
1314spice_protocol = not_found
1315if not get_option('spice_protocol').auto() or have_system
1316  spice_protocol = dependency('spice-protocol', version: '>=0.14.0',
1317                              required: get_option('spice_protocol'),
1318                              method: 'pkg-config')
1319endif
1320spice = not_found
1321if get_option('spice') \
1322             .disable_auto_if(not have_system) \
1323             .require(pixman.found(),
1324                      error_message: 'cannot enable SPICE if pixman is not available') \
1325             .allowed()
1326  spice = dependency('spice-server', version: '>=0.14.0',
1327                     required: get_option('spice'),
1328                     method: 'pkg-config')
1329endif
1330spice_headers = spice.partial_dependency(compile_args: true, includes: true)
1331
1332rt = cc.find_library('rt', required: false)
1333
1334libiscsi = not_found
1335if not get_option('libiscsi').auto() or have_block
1336  libiscsi = dependency('libiscsi', version: '>=1.9.0',
1337                         required: get_option('libiscsi'),
1338                         method: 'pkg-config')
1339endif
1340zstd = not_found
1341if not get_option('zstd').auto() or have_block
1342  zstd = dependency('libzstd', version: '>=1.4.0',
1343                    required: get_option('zstd'),
1344                    method: 'pkg-config')
1345endif
1346qpl = not_found
1347if not get_option('qpl').auto() or have_system
1348  qpl = dependency('qpl', version: '>=1.5.0',
1349                    required: get_option('qpl'),
1350                    method: 'pkg-config')
1351endif
1352uadk = not_found
1353if not get_option('uadk').auto() or have_system
1354  libwd = dependency('libwd', version: '>=2.6',
1355                      required: get_option('uadk'),
1356                      method: 'pkg-config')
1357  libwd_comp = dependency('libwd_comp', version: '>=2.6',
1358                           required: get_option('uadk'),
1359                           method: 'pkg-config')
1360  if libwd.found() and libwd_comp.found()
1361     uadk = declare_dependency(dependencies: [libwd, libwd_comp])
1362  endif
1363endif
1364
1365qatzip = not_found
1366if not get_option('qatzip').auto() or have_system
1367  qatzip = dependency('qatzip', version: '>=1.1.2',
1368                      required: get_option('qatzip'),
1369                      method: 'pkg-config')
1370endif
1371
1372virgl = not_found
1373
1374have_vhost_user_gpu = have_tools and host_os == 'linux' and pixman.found()
1375if not get_option('virglrenderer').auto() or have_system or have_vhost_user_gpu
1376  virgl = dependency('virglrenderer',
1377                     method: 'pkg-config',
1378                     required: get_option('virglrenderer'))
1379endif
1380rutabaga = not_found
1381if not get_option('rutabaga_gfx').auto() or have_system or have_vhost_user_gpu
1382  rutabaga = dependency('rutabaga_gfx_ffi',
1383                         method: 'pkg-config',
1384                         required: get_option('rutabaga_gfx'))
1385endif
1386blkio = not_found
1387if not get_option('blkio').auto() or have_block
1388  blkio = dependency('blkio',
1389                     method: 'pkg-config',
1390                     required: get_option('blkio'))
1391endif
1392curl = not_found
1393if not get_option('curl').auto() or have_block
1394  curl = dependency('libcurl', version: '>=7.29.0',
1395                    method: 'pkg-config',
1396                    required: get_option('curl'))
1397endif
1398libudev = not_found
1399if host_os == 'linux' and (have_system or have_tools)
1400  libudev = dependency('libudev',
1401                       method: 'pkg-config',
1402                       required: get_option('libudev'))
1403endif
1404
1405mpathlibs = [libudev]
1406mpathpersist = not_found
1407if host_os == 'linux' and have_tools and get_option('mpath').allowed()
1408  mpath_test_source = '''
1409    #include <libudev.h>
1410    #include <mpath_persist.h>
1411    unsigned mpath_mx_alloc_len = 1024;
1412    int logsink;
1413    static struct config *multipath_conf;
1414    extern struct udev *udev;
1415    extern struct config *get_multipath_config(void);
1416    extern void put_multipath_config(struct config *conf);
1417    struct udev *udev;
1418    struct config *get_multipath_config(void) { return multipath_conf; }
1419    void put_multipath_config(struct config *conf) { }
1420    int main(void) {
1421        udev = udev_new();
1422        multipath_conf = mpath_lib_init();
1423        return 0;
1424    }'''
1425  libmpathpersist = cc.find_library('mpathpersist',
1426                                    required: get_option('mpath'))
1427  if libmpathpersist.found()
1428    mpathlibs += libmpathpersist
1429    if get_option('prefer_static')
1430      mpathlibs += cc.find_library('devmapper',
1431                                     required: get_option('mpath'))
1432    endif
1433    mpathlibs += cc.find_library('multipath',
1434                                 required: get_option('mpath'))
1435    foreach lib: mpathlibs
1436      if not lib.found()
1437        mpathlibs = []
1438        break
1439      endif
1440    endforeach
1441    if mpathlibs.length() == 0
1442      msg = 'Dependencies missing for libmpathpersist'
1443    elif cc.links(mpath_test_source, dependencies: mpathlibs)
1444      mpathpersist = declare_dependency(dependencies: mpathlibs)
1445    else
1446      msg = 'Cannot detect libmpathpersist API'
1447    endif
1448    if not mpathpersist.found()
1449      if get_option('mpath').enabled()
1450        error(msg)
1451      else
1452        warning(msg + ', disabling')
1453      endif
1454    endif
1455  endif
1456endif
1457
1458iconv = not_found
1459curses = not_found
1460if have_system and get_option('curses').allowed()
1461  curses_test = '''
1462    #ifdef __APPLE__
1463    #define _XOPEN_SOURCE_EXTENDED 1
1464    #endif
1465    #include <locale.h>
1466    #include <curses.h>
1467    #include <wchar.h>
1468    int main(void) {
1469      wchar_t wch = L'w';
1470      setlocale(LC_ALL, "");
1471      resize_term(0, 0);
1472      addwstr(L"wide chars\n");
1473      addnwstr(&wch, 1);
1474      add_wch(WACS_DEGREE);
1475      return 0;
1476    }'''
1477
1478  curses_dep_list = host_os == 'windows' ? ['ncurses', 'ncursesw'] : ['ncursesw']
1479  curses = dependency(curses_dep_list,
1480                      required: false,
1481                      method: 'pkg-config')
1482  msg = get_option('curses').enabled() ? 'curses library not found' : ''
1483  curses_compile_args = ['-DNCURSES_WIDECHAR=1']
1484  if curses.found()
1485    if cc.links(curses_test, args: curses_compile_args, dependencies: [curses])
1486      curses = declare_dependency(compile_args: curses_compile_args, dependencies: [curses],
1487                                  version: curses.version())
1488    else
1489      msg = 'curses package not usable'
1490      curses = not_found
1491    endif
1492  endif
1493  if not curses.found()
1494    has_curses_h = cc.has_header('curses.h', args: curses_compile_args)
1495    if host_os != 'windows' and not has_curses_h
1496      message('Trying with /usr/include/ncursesw')
1497      curses_compile_args += ['-I/usr/include/ncursesw']
1498      has_curses_h = cc.has_header('curses.h', args: curses_compile_args)
1499    endif
1500    if has_curses_h
1501      curses_libname_list = (host_os == 'windows' ? ['pdcurses'] : ['ncursesw', 'cursesw'])
1502      foreach curses_libname : curses_libname_list
1503        libcurses = cc.find_library(curses_libname,
1504                                    required: false)
1505        if libcurses.found()
1506          if cc.links(curses_test, args: curses_compile_args, dependencies: libcurses)
1507            curses = declare_dependency(compile_args: curses_compile_args,
1508                                        dependencies: [libcurses])
1509            break
1510          else
1511            msg = 'curses library not usable'
1512          endif
1513        endif
1514      endforeach
1515    endif
1516  endif
1517  if get_option('iconv').allowed()
1518    foreach link_args : [ ['-liconv'], [] ]
1519      # Programs will be linked with glib and this will bring in libiconv on FreeBSD.
1520      # We need to use libiconv if available because mixing libiconv's headers with
1521      # the system libc does not work.
1522      # However, without adding glib to the dependencies -L/usr/local/lib will not be
1523      # included in the command line and libiconv will not be found.
1524      if cc.links('''
1525        #include <iconv.h>
1526        int main(void) {
1527          iconv_t conv = iconv_open("WCHAR_T", "UCS-2");
1528          return conv != (iconv_t) -1;
1529        }''', args: link_args, dependencies: glib)
1530        iconv = declare_dependency(link_args: link_args, dependencies: glib)
1531        break
1532      endif
1533    endforeach
1534  endif
1535  if curses.found() and not iconv.found()
1536    if get_option('iconv').enabled()
1537      error('iconv not available')
1538    endif
1539    msg = 'iconv required for curses UI but not available'
1540    curses = not_found
1541  endif
1542  if not curses.found() and msg != ''
1543    if get_option('curses').enabled()
1544      error(msg)
1545    else
1546      warning(msg + ', disabling')
1547    endif
1548  endif
1549endif
1550
1551brlapi = not_found
1552if not get_option('brlapi').auto() or have_system
1553  brlapi = cc.find_library('brlapi', has_headers: ['brlapi.h'],
1554                         required: get_option('brlapi'))
1555  if brlapi.found() and not cc.links('''
1556     #include <brlapi.h>
1557     #include <stddef.h>
1558     int main(void) { return brlapi__openConnection (NULL, NULL, NULL); }''', dependencies: brlapi)
1559    brlapi = not_found
1560    if get_option('brlapi').enabled()
1561      error('could not link brlapi')
1562    else
1563      warning('could not link brlapi, disabling')
1564    endif
1565  endif
1566endif
1567
1568sdl = not_found
1569if not get_option('sdl').auto() or have_system
1570  sdl = dependency('sdl2', required: get_option('sdl'))
1571  sdl_image = not_found
1572endif
1573if sdl.found()
1574  # Some versions of SDL have problems with -Wundef
1575  if not cc.compiles('''
1576                     #include <SDL.h>
1577                     #include <SDL_syswm.h>
1578                     int main(int argc, char *argv[]) { return 0; }
1579                     ''', dependencies: sdl, args: '-Werror=undef')
1580    sdl = declare_dependency(compile_args: '-Wno-undef',
1581                             dependencies: sdl,
1582                             version: sdl.version())
1583  endif
1584  sdl_image = dependency('SDL2_image', required: get_option('sdl_image'),
1585                         method: 'pkg-config')
1586else
1587  if get_option('sdl_image').enabled()
1588    error('sdl-image required, but SDL was @0@'.format(
1589          get_option('sdl').disabled() ? 'disabled' : 'not found'))
1590  endif
1591  sdl_image = not_found
1592endif
1593
1594rbd = not_found
1595if not get_option('rbd').auto() or have_block
1596  librados = cc.find_library('rados', required: get_option('rbd'))
1597  librbd = cc.find_library('rbd', has_headers: ['rbd/librbd.h'],
1598                           required: get_option('rbd'))
1599  if librados.found() and librbd.found()
1600    if cc.links('''
1601      #include <stdio.h>
1602      #include <rbd/librbd.h>
1603      int main(void) {
1604        rados_t cluster;
1605        rados_create(&cluster, NULL);
1606        #if LIBRBD_VERSION_CODE < LIBRBD_VERSION(1, 12, 0)
1607        #error
1608        #endif
1609        return 0;
1610      }''', dependencies: [librbd, librados])
1611      rbd = declare_dependency(dependencies: [librbd, librados])
1612    elif get_option('rbd').enabled()
1613      error('librbd >= 1.12.0 required')
1614    else
1615      warning('librbd >= 1.12.0 not found, disabling')
1616    endif
1617  endif
1618endif
1619
1620glusterfs = not_found
1621glusterfs_ftruncate_has_stat = false
1622glusterfs_iocb_has_stat = false
1623if not get_option('glusterfs').auto() or have_block
1624  glusterfs = dependency('glusterfs-api', version: '>=3',
1625                         required: get_option('glusterfs'),
1626                         method: 'pkg-config')
1627  if glusterfs.found()
1628    glusterfs_ftruncate_has_stat = cc.links('''
1629      #include <glusterfs/api/glfs.h>
1630
1631      int
1632      main(void)
1633      {
1634          /* new glfs_ftruncate() passes two additional args */
1635          return glfs_ftruncate(NULL, 0, NULL, NULL);
1636      }
1637    ''', dependencies: glusterfs)
1638    glusterfs_iocb_has_stat = cc.links('''
1639      #include <glusterfs/api/glfs.h>
1640
1641      /* new glfs_io_cbk() passes two additional glfs_stat structs */
1642      static void
1643      glusterfs_iocb(glfs_fd_t *fd, ssize_t ret, struct glfs_stat *prestat, struct glfs_stat *poststat, void *data)
1644      {}
1645
1646      int
1647      main(void)
1648      {
1649          glfs_io_cbk iocb = &glusterfs_iocb;
1650          iocb(NULL, 0 , NULL, NULL, NULL);
1651          return 0;
1652      }
1653    ''', dependencies: glusterfs)
1654  endif
1655endif
1656
1657hv_balloon = false
1658if get_option('hv_balloon').allowed() and have_system
1659  if cc.links('''
1660    #include <string.h>
1661    #include <gmodule.h>
1662    int main(void) {
1663        GTree *tree;
1664
1665        tree = g_tree_new((GCompareFunc)strcmp);
1666        (void)g_tree_node_first(tree);
1667        g_tree_destroy(tree);
1668        return 0;
1669    }
1670  ''', dependencies: glib)
1671    hv_balloon = true
1672  else
1673    if get_option('hv_balloon').enabled()
1674      error('could not enable hv-balloon, update your glib')
1675    else
1676      warning('could not find glib support for hv-balloon, disabling')
1677    endif
1678  endif
1679endif
1680
1681libssh = not_found
1682if not get_option('libssh').auto() or have_block
1683  libssh = dependency('libssh', version: '>=0.8.7',
1684                    method: 'pkg-config',
1685                    required: get_option('libssh'))
1686endif
1687
1688libbzip2 = not_found
1689if not get_option('bzip2').auto() or have_block
1690  libbzip2 = cc.find_library('bz2', has_headers: ['bzlib.h'],
1691                             required: get_option('bzip2'))
1692  if libbzip2.found() and not cc.links('''
1693     #include <bzlib.h>
1694     int main(void) { BZ2_bzlibVersion(); return 0; }''', dependencies: libbzip2)
1695    libbzip2 = not_found
1696    if get_option('bzip2').enabled()
1697      error('could not link libbzip2')
1698    else
1699      warning('could not link libbzip2, disabling')
1700    endif
1701  endif
1702endif
1703
1704liblzfse = not_found
1705if not get_option('lzfse').auto() or have_block
1706  liblzfse = cc.find_library('lzfse', has_headers: ['lzfse.h'],
1707                             required: get_option('lzfse'))
1708endif
1709if liblzfse.found() and not cc.links('''
1710   #include <lzfse.h>
1711   int main(void) { lzfse_decode_scratch_size(); return 0; }''', dependencies: liblzfse)
1712  liblzfse = not_found
1713  if get_option('lzfse').enabled()
1714    error('could not link liblzfse')
1715  else
1716    warning('could not link liblzfse, disabling')
1717  endif
1718endif
1719
1720oss = not_found
1721if get_option('oss').allowed() and have_system
1722  if not cc.has_header('sys/soundcard.h')
1723    # not found
1724  elif host_os == 'netbsd'
1725    oss = cc.find_library('ossaudio', required: get_option('oss'))
1726  else
1727    oss = declare_dependency()
1728  endif
1729
1730  if not oss.found()
1731    if get_option('oss').enabled()
1732      error('OSS not found')
1733    endif
1734  endif
1735endif
1736dsound = not_found
1737if not get_option('dsound').auto() or (host_os == 'windows' and have_system)
1738  if cc.has_header('dsound.h')
1739    dsound = declare_dependency(link_args: ['-lole32', '-ldxguid'])
1740  endif
1741
1742  if not dsound.found()
1743    if get_option('dsound').enabled()
1744      error('DirectSound not found')
1745    endif
1746  endif
1747endif
1748
1749coreaudio = not_found
1750if not get_option('coreaudio').auto() or (host_os == 'darwin' and have_system)
1751  coreaudio = dependency('appleframeworks', modules: 'CoreAudio',
1752                         required: get_option('coreaudio'))
1753endif
1754
1755opengl = not_found
1756if not get_option('opengl').auto() or have_system or have_vhost_user_gpu
1757  epoxy = dependency('epoxy', method: 'pkg-config',
1758                      required: get_option('opengl'))
1759  if cc.has_header('epoxy/egl.h', dependencies: epoxy)
1760    opengl = epoxy
1761  elif get_option('opengl').enabled()
1762    error('epoxy/egl.h not found')
1763  endif
1764endif
1765gbm = not_found
1766if (have_system or have_tools) and (virgl.found() or opengl.found())
1767  gbm = dependency('gbm', method: 'pkg-config', required: false)
1768endif
1769have_vhost_user_gpu = have_vhost_user_gpu and virgl.found() and opengl.found() and gbm.found()
1770
1771libcbor = not_found
1772if not get_option('libcbor').auto() or have_system
1773  libcbor = dependency('libcbor', version: '>=0.7.0',
1774                       required: get_option('libcbor'))
1775endif
1776
1777gnutls = not_found
1778gnutls_crypto = not_found
1779if get_option('gnutls').enabled() or (get_option('gnutls').auto() and have_system)
1780  # For general TLS support our min gnutls matches
1781  # that implied by our platform support matrix
1782  #
1783  # For the crypto backends, we look for a newer
1784  # gnutls:
1785  #
1786  #   Version 3.6.8  is needed to get XTS
1787  #   Version 3.6.13 is needed to get PBKDF
1788  #   Version 3.6.14 is needed to get HW accelerated XTS
1789  #
1790  # If newer enough gnutls isn't available, we can
1791  # still use a different crypto backend to satisfy
1792  # the platform support requirements
1793  gnutls_crypto = dependency('gnutls', version: '>=3.6.14',
1794                             method: 'pkg-config',
1795                             required: false)
1796  if gnutls_crypto.found()
1797    gnutls = gnutls_crypto
1798  else
1799    # Our min version if all we need is TLS
1800    gnutls = dependency('gnutls', version: '>=3.5.18',
1801                        method: 'pkg-config',
1802                        required: get_option('gnutls'))
1803  endif
1804endif
1805
1806# We prefer use of gnutls for crypto, unless the options
1807# explicitly asked for nettle or gcrypt.
1808#
1809# If gnutls isn't available for crypto, then we'll prefer
1810# gcrypt over nettle for performance reasons.
1811gcrypt = not_found
1812nettle = not_found
1813hogweed = not_found
1814crypto_sm4 = not_found
1815crypto_sm3 = not_found
1816xts = 'none'
1817
1818if get_option('nettle').enabled() and get_option('gcrypt').enabled()
1819  error('Only one of gcrypt & nettle can be enabled')
1820endif
1821
1822# Explicit nettle/gcrypt request, so ignore gnutls for crypto
1823if get_option('nettle').enabled() or get_option('gcrypt').enabled()
1824  gnutls_crypto = not_found
1825endif
1826
1827if not gnutls_crypto.found()
1828  if (not get_option('gcrypt').auto() or have_system) and not get_option('nettle').enabled()
1829    gcrypt = dependency('libgcrypt', version: '>=1.8',
1830                        required: get_option('gcrypt'))
1831    # Debian has removed -lgpg-error from libgcrypt-config
1832    # as it "spreads unnecessary dependencies" which in
1833    # turn breaks static builds...
1834    if gcrypt.found() and get_option('prefer_static')
1835      gcrypt = declare_dependency(dependencies:
1836        [gcrypt,
1837         cc.find_library('gpg-error', required: true)],
1838        version: gcrypt.version())
1839    endif
1840    crypto_sm4 = gcrypt
1841    # SM4 ALG is available in libgcrypt >= 1.9
1842    if gcrypt.found() and not cc.links('''
1843      #include <gcrypt.h>
1844      int main(void) {
1845        gcry_cipher_hd_t handler;
1846        gcry_cipher_open(&handler, GCRY_CIPHER_SM4, GCRY_CIPHER_MODE_ECB, 0);
1847        return 0;
1848      }''', dependencies: gcrypt)
1849      crypto_sm4 = not_found
1850    endif
1851    crypto_sm3 = gcrypt
1852    # SM3 ALG is available in libgcrypt >= 1.9
1853    if gcrypt.found() and not cc.links('''
1854      #include <gcrypt.h>
1855      int main(void) {
1856        gcry_md_hd_t handler;
1857        gcry_md_open(&handler, GCRY_MD_SM3, 0);
1858        return 0;
1859      }''', dependencies: gcrypt)
1860      crypto_sm3 = not_found
1861    endif
1862  endif
1863  if (not get_option('nettle').auto() or have_system) and not gcrypt.found()
1864    nettle = dependency('nettle', version: '>=3.4',
1865                        method: 'pkg-config',
1866                        required: get_option('nettle'))
1867    if nettle.found() and not cc.has_header('nettle/xts.h', dependencies: nettle)
1868      xts = 'private'
1869    endif
1870    crypto_sm4 = nettle
1871    # SM4 ALG is available in nettle >= 3.9
1872    if nettle.found() and not cc.links('''
1873      #include <nettle/sm4.h>
1874      int main(void) {
1875        struct sm4_ctx ctx;
1876        unsigned char key[16] = {0};
1877        sm4_set_encrypt_key(&ctx, key);
1878        return 0;
1879      }''', dependencies: nettle)
1880      crypto_sm4 = not_found
1881    endif
1882    crypto_sm3 = nettle
1883    # SM3 ALG is available in nettle >= 3.8
1884    if nettle.found() and not cc.links('''
1885      #include <nettle/sm3.h>
1886      #include <nettle/hmac.h>
1887      int main(void) {
1888      struct sm3_ctx ctx;
1889      struct hmac_sm3_ctx hmac_ctx;
1890      unsigned char data[64] = {0};
1891      unsigned char output[32];
1892
1893      // SM3 hash function test
1894      sm3_init(&ctx);
1895      sm3_update(&ctx, 64, data);
1896      sm3_digest(&ctx, 32, data);
1897
1898      // HMAC-SM3 test
1899      hmac_sm3_set_key(&hmac_ctx, 32, data);
1900      hmac_sm3_update(&hmac_ctx, 64, data);
1901      hmac_sm3_digest(&hmac_ctx, 32, output);
1902
1903      return 0;
1904      }''', dependencies: nettle)
1905      crypto_sm3 = not_found
1906    endif
1907  endif
1908endif
1909
1910capstone = not_found
1911if not get_option('capstone').auto() or have_system or have_user
1912  capstone = dependency('capstone', version: '>=3.0.5',
1913                        method: 'pkg-config',
1914                        required: get_option('capstone'))
1915
1916  # Some versions of capstone have broken pkg-config file
1917  # that reports a wrong -I path, causing the #include to
1918  # fail later. If the system has such a broken version
1919  # do not use it.
1920  if capstone.found() and not cc.compiles('#include <capstone.h>',
1921                                          dependencies: [capstone])
1922    capstone = not_found
1923    if get_option('capstone').enabled()
1924      error('capstone requested, but it does not appear to work')
1925    endif
1926  endif
1927endif
1928
1929gmp = dependency('gmp', required: false, method: 'pkg-config')
1930if nettle.found() and gmp.found()
1931  hogweed = dependency('hogweed', version: '>=3.4',
1932                       method: 'pkg-config',
1933                       required: get_option('nettle'))
1934endif
1935
1936
1937gtk = not_found
1938gtkx11 = not_found
1939vte = not_found
1940have_gtk_clipboard = get_option('gtk_clipboard').enabled()
1941
1942if get_option('gtk') \
1943             .disable_auto_if(not have_system) \
1944             .require(pixman.found(),
1945                      error_message: 'cannot enable GTK if pixman is not available') \
1946             .allowed()
1947  gtk = dependency('gtk+-3.0', version: '>=3.22.0',
1948                   method: 'pkg-config',
1949                   required: get_option('gtk'))
1950  if gtk.found()
1951    gtkx11 = dependency('gtk+-x11-3.0', version: '>=3.22.0',
1952                        method: 'pkg-config',
1953                        required: false)
1954    gtk = declare_dependency(dependencies: [gtk, gtkx11],
1955                             version: gtk.version())
1956
1957    if not get_option('vte').auto() or have_system
1958      vte = dependency('vte-2.91',
1959                       method: 'pkg-config',
1960                       required: get_option('vte'))
1961    endif
1962  elif have_gtk_clipboard
1963    error('GTK clipboard requested, but GTK not found')
1964  endif
1965endif
1966
1967x11 = not_found
1968if gtkx11.found()
1969  x11 = dependency('x11', method: 'pkg-config', required: gtkx11.found())
1970endif
1971png = not_found
1972if get_option('png').allowed() and have_system
1973   png = dependency('libpng', version: '>=1.6.34', required: get_option('png'),
1974                    method: 'pkg-config')
1975endif
1976vnc = not_found
1977jpeg = not_found
1978sasl = not_found
1979if get_option('vnc') \
1980             .disable_auto_if(not have_system) \
1981             .require(pixman.found(),
1982                      error_message: 'cannot enable VNC if pixman is not available') \
1983             .allowed()
1984  vnc = declare_dependency() # dummy dependency
1985  jpeg = dependency('libjpeg', required: get_option('vnc_jpeg'),
1986                    method: 'pkg-config')
1987  sasl = cc.find_library('sasl2', has_headers: ['sasl/sasl.h'],
1988                         required: get_option('vnc_sasl'))
1989  if sasl.found()
1990    sasl = declare_dependency(dependencies: sasl,
1991                              compile_args: '-DSTRUCT_IOVEC_DEFINED')
1992  endif
1993endif
1994
1995pam = not_found
1996if not get_option('auth_pam').auto() or have_system
1997  pam = cc.find_library('pam', has_headers: ['security/pam_appl.h'],
1998                        required: get_option('auth_pam'))
1999endif
2000if pam.found() and not cc.links('''
2001   #include <stddef.h>
2002   #include <security/pam_appl.h>
2003   int main(void) {
2004     const char *service_name = "qemu";
2005     const char *user = "frank";
2006     const struct pam_conv pam_conv = { 0 };
2007     pam_handle_t *pamh = NULL;
2008     pam_start(service_name, user, &pam_conv, &pamh);
2009     return 0;
2010   }''', dependencies: pam)
2011  pam = not_found
2012  if get_option('auth_pam').enabled()
2013    error('could not link libpam')
2014  else
2015    warning('could not link libpam, disabling')
2016  endif
2017endif
2018
2019snappy = not_found
2020if not get_option('snappy').auto() or have_system
2021  snappy = cc.find_library('snappy', has_headers: ['snappy-c.h'],
2022                           required: get_option('snappy'))
2023endif
2024if snappy.found() and not cc.links('''
2025   #include <snappy-c.h>
2026   int main(void) { snappy_max_compressed_length(4096); return 0; }''', dependencies: snappy)
2027  snappy = not_found
2028  if get_option('snappy').enabled()
2029    error('could not link libsnappy')
2030  else
2031    warning('could not link libsnappy, disabling')
2032  endif
2033endif
2034
2035lzo = not_found
2036if not get_option('lzo').auto() or have_system
2037  lzo = cc.find_library('lzo2', has_headers: ['lzo/lzo1x.h'],
2038                        required: get_option('lzo'))
2039endif
2040if lzo.found() and not cc.links('''
2041   #include <lzo/lzo1x.h>
2042   int main(void) { lzo_version(); return 0; }''', dependencies: lzo)
2043  lzo = not_found
2044  if get_option('lzo').enabled()
2045    error('could not link liblzo2')
2046  else
2047    warning('could not link liblzo2, disabling')
2048  endif
2049endif
2050
2051numa = not_found
2052if not get_option('numa').auto() or have_system or have_tools
2053  numa = cc.find_library('numa', has_headers: ['numa.h'],
2054                              required: get_option('numa'))
2055endif
2056if numa.found() and not cc.links('''
2057   #include <numa.h>
2058   int main(void) { return numa_available(); }
2059   ''', dependencies: numa)
2060  numa = not_found
2061  if get_option('numa').enabled()
2062    error('could not link numa')
2063  else
2064    warning('could not link numa, disabling')
2065  endif
2066endif
2067
2068fdt = not_found
2069fdt_opt = get_option('fdt')
2070if fdt_opt == 'enabled' and get_option('wrap_mode') == 'nodownload'
2071  fdt_opt = 'system'
2072endif
2073if fdt_opt in ['enabled', 'system'] or (fdt_opt == 'auto' and have_system)
2074  fdt = cc.find_library('fdt', required: fdt_opt == 'system')
2075  if fdt.found() and cc.links('''
2076     #include <libfdt.h>
2077     #include <libfdt_env.h>
2078     int main(void) { fdt_find_max_phandle(NULL, NULL); return 0; }''',
2079       dependencies: fdt)
2080    fdt_opt = 'system'
2081  elif fdt_opt != 'system'
2082    fdt_opt = get_option('wrap_mode') == 'nodownload' ? 'disabled' : 'internal'
2083    fdt = not_found
2084  else
2085    error('system libfdt is too old (1.5.1 or newer required)')
2086  endif
2087endif
2088if fdt_opt == 'internal'
2089  assert(not fdt.found())
2090  libfdt_proj = subproject('dtc', required: true,
2091                           default_options: ['tools=false',  'yaml=disabled',
2092                                             'python=disabled', 'default_library=static'])
2093  fdt = libfdt_proj.get_variable('libfdt_dep')
2094endif
2095
2096rdma = not_found
2097if not get_option('rdma').auto() or have_system
2098  rdma_libs = [cc.find_library('rdmacm', has_headers: ['rdma/rdma_cma.h'],
2099                               required: get_option('rdma')),
2100               cc.find_library('ibverbs', required: get_option('rdma'))]
2101  rdma = declare_dependency(dependencies: rdma_libs)
2102  foreach lib: rdma_libs
2103    if not lib.found()
2104      rdma = not_found
2105    endif
2106  endforeach
2107endif
2108
2109cacard = not_found
2110if not get_option('smartcard').auto() or have_system
2111  cacard = dependency('libcacard', required: get_option('smartcard'),
2112                      version: '>=2.5.1', method: 'pkg-config')
2113endif
2114u2f = not_found
2115if not get_option('u2f').auto() or have_system
2116  u2f = dependency('u2f-emu', required: get_option('u2f'),
2117                   method: 'pkg-config')
2118endif
2119canokey = not_found
2120if not get_option('canokey').auto() or have_system
2121  canokey = dependency('canokey-qemu', required: get_option('canokey'),
2122                   method: 'pkg-config')
2123endif
2124usbredir = not_found
2125if not get_option('usb_redir').auto() or have_system
2126  usbredir = dependency('libusbredirparser-0.5', required: get_option('usb_redir'),
2127                        version: '>=0.6', method: 'pkg-config')
2128endif
2129libusb = not_found
2130if not get_option('libusb').auto() or have_system
2131  libusb = dependency('libusb-1.0', required: get_option('libusb'),
2132                      version: '>=1.0.13', method: 'pkg-config')
2133endif
2134
2135libpmem = not_found
2136if not get_option('libpmem').auto() or have_system
2137  libpmem = dependency('libpmem', required: get_option('libpmem'),
2138                       method: 'pkg-config')
2139endif
2140libdaxctl = not_found
2141if not get_option('libdaxctl').auto() or have_system
2142  libdaxctl = dependency('libdaxctl', required: get_option('libdaxctl'),
2143                         version: '>=57', method: 'pkg-config')
2144endif
2145tasn1 = not_found
2146if gnutls.found()
2147  tasn1 = dependency('libtasn1',
2148                     required: false,
2149                     method: 'pkg-config')
2150endif
2151keyutils = not_found
2152if not get_option('libkeyutils').auto() or have_block
2153  keyutils = dependency('libkeyutils', required: get_option('libkeyutils'),
2154                        method: 'pkg-config')
2155endif
2156
2157has_gettid = cc.has_function('gettid')
2158
2159# libselinux
2160selinux = dependency('libselinux',
2161                     required: get_option('selinux'),
2162                     method: 'pkg-config')
2163
2164# Malloc tests
2165
2166malloc = []
2167if get_option('malloc') == 'system'
2168  has_malloc_trim = \
2169    get_option('malloc_trim').allowed() and \
2170    cc.has_function('malloc_trim', prefix: '#include <malloc.h>')
2171else
2172  has_malloc_trim = false
2173  malloc = cc.find_library(get_option('malloc'), required: true)
2174endif
2175if not has_malloc_trim and get_option('malloc_trim').enabled()
2176  if get_option('malloc') == 'system'
2177    error('malloc_trim not available on this platform.')
2178  else
2179    error('malloc_trim not available with non-libc memory allocator')
2180  endif
2181endif
2182
2183gnu_source_prefix = '''
2184  #ifndef _GNU_SOURCE
2185  #define _GNU_SOURCE
2186  #endif
2187'''
2188
2189# Check whether the glibc provides STATX_BASIC_STATS
2190
2191has_statx = cc.has_header_symbol('sys/stat.h', 'STATX_BASIC_STATS', prefix: gnu_source_prefix)
2192
2193# Check whether statx() provides mount ID information
2194
2195has_statx_mnt_id = cc.has_header_symbol('sys/stat.h', 'STATX_MNT_ID', prefix: gnu_source_prefix)
2196
2197have_vhost_user_blk_server = get_option('vhost_user_blk_server') \
2198  .require(host_os == 'linux',
2199           error_message: 'vhost_user_blk_server requires linux') \
2200  .require(have_vhost_user,
2201           error_message: 'vhost_user_blk_server requires vhost-user support') \
2202  .disable_auto_if(not have_tools and not have_system) \
2203  .allowed()
2204
2205if get_option('fuse').disabled() and get_option('fuse_lseek').enabled()
2206  error('Cannot enable fuse-lseek while fuse is disabled')
2207endif
2208
2209fuse = dependency('fuse3', required: get_option('fuse'),
2210                  version: '>=3.1', method: 'pkg-config')
2211
2212fuse_lseek = not_found
2213if get_option('fuse_lseek').allowed()
2214  if fuse.version().version_compare('>=3.8')
2215    # Dummy dependency
2216    fuse_lseek = declare_dependency()
2217  elif get_option('fuse_lseek').enabled()
2218    if fuse.found()
2219      error('fuse-lseek requires libfuse >=3.8, found ' + fuse.version())
2220    else
2221      error('fuse-lseek requires libfuse, which was not found')
2222    endif
2223  endif
2224endif
2225
2226have_libvduse = (host_os == 'linux')
2227if get_option('libvduse').enabled()
2228    if host_os != 'linux'
2229        error('libvduse requires linux')
2230    endif
2231elif get_option('libvduse').disabled()
2232    have_libvduse = false
2233endif
2234
2235have_vduse_blk_export = (have_libvduse and host_os == 'linux')
2236if get_option('vduse_blk_export').enabled()
2237    if host_os != 'linux'
2238        error('vduse_blk_export requires linux')
2239    elif not have_libvduse
2240        error('vduse_blk_export requires libvduse support')
2241    endif
2242elif get_option('vduse_blk_export').disabled()
2243    have_vduse_blk_export = false
2244endif
2245
2246# libbpf
2247bpf_version = '1.1.0'
2248libbpf = dependency('libbpf', version: '>=' + bpf_version, required: get_option('bpf'), method: 'pkg-config')
2249if libbpf.found() and not cc.links('''
2250   #include <bpf/libbpf.h>
2251   #include <linux/bpf.h>
2252   int main(void)
2253   {
2254     // check flag availability
2255     int flag = BPF_F_MMAPABLE;
2256     bpf_object__destroy_skeleton(NULL);
2257     return 0;
2258   }''', dependencies: libbpf)
2259  libbpf = not_found
2260  if get_option('bpf').enabled()
2261    error('libbpf skeleton/mmaping test failed')
2262  else
2263    warning('libbpf skeleton/mmaping test failed, disabling')
2264  endif
2265endif
2266
2267# libxdp
2268libxdp = not_found
2269if not get_option('af_xdp').auto() or have_system
2270    if libbpf.found()
2271        libxdp = dependency('libxdp', required: get_option('af_xdp'),
2272                            version: '>=1.4.0', method: 'pkg-config')
2273    else
2274        if get_option('af_xdp').enabled()
2275            error('libxdp requested, but libbpf is not available')
2276        endif
2277    endif
2278endif
2279
2280# libdw
2281libdw = not_found
2282if not get_option('libdw').auto() or \
2283        (not get_option('prefer_static') and (have_system or have_user))
2284    libdw = dependency('libdw',
2285                       method: 'pkg-config',
2286                       required: get_option('libdw'))
2287endif
2288
2289#################
2290# config-host.h #
2291#################
2292
2293config_host_data = configuration_data()
2294
2295config_host_data.set('CONFIG_HAVE_RUST', have_rust)
2296audio_drivers_selected = []
2297if have_system
2298  audio_drivers_available = {
2299    'alsa': alsa.found(),
2300    'coreaudio': coreaudio.found(),
2301    'dsound': dsound.found(),
2302    'jack': jack.found(),
2303    'oss': oss.found(),
2304    'pa': pulse.found(),
2305    'pipewire': pipewire.found(),
2306    'sdl': sdl.found(),
2307    'sndio': sndio.found(),
2308  }
2309  foreach k, v: audio_drivers_available
2310    config_host_data.set('CONFIG_AUDIO_' + k.to_upper(), v)
2311  endforeach
2312
2313  # Default to native drivers first, OSS second, SDL third
2314  audio_drivers_priority = \
2315    [ 'pa', 'coreaudio', 'dsound', 'sndio', 'oss' ] + \
2316    (host_os == 'linux' ? [] : [ 'sdl' ])
2317  audio_drivers_default = []
2318  foreach k: audio_drivers_priority
2319    if audio_drivers_available[k]
2320      audio_drivers_default += k
2321    endif
2322  endforeach
2323
2324  foreach k: get_option('audio_drv_list')
2325    if k == 'default'
2326      audio_drivers_selected += audio_drivers_default
2327    elif not audio_drivers_available[k]
2328      error('Audio driver "@0@" not available.'.format(k))
2329    else
2330      audio_drivers_selected += k
2331    endif
2332  endforeach
2333endif
2334config_host_data.set('CONFIG_AUDIO_DRIVERS',
2335                     '"' + '", "'.join(audio_drivers_selected) + '", ')
2336
2337have_host_block_device = (host_os != 'darwin' or
2338    cc.has_header('IOKit/storage/IOMedia.h'))
2339
2340dbus_display = get_option('dbus_display') \
2341  .require(gio.version().version_compare('>=2.64'),
2342           error_message: '-display dbus requires glib>=2.64') \
2343  .require(gdbus_codegen.found(),
2344           error_message: gdbus_codegen_error.format('-display dbus')) \
2345  .allowed()
2346
2347have_virtfs = get_option('virtfs') \
2348    .require(host_os == 'linux' or host_os == 'darwin',
2349             error_message: 'virtio-9p (virtfs) requires Linux or macOS') \
2350    .require(host_os == 'linux' or cc.has_function('pthread_fchdir_np'),
2351             error_message: 'virtio-9p (virtfs) on macOS requires the presence of pthread_fchdir_np') \
2352    .require(host_os == 'darwin' or libattr.found(),
2353             error_message: 'virtio-9p (virtfs) on Linux requires libattr-devel') \
2354    .disable_auto_if(not have_tools and not have_system) \
2355    .allowed()
2356
2357qga_fsfreeze = false
2358qga_fstrim = false
2359if host_os == 'linux'
2360    if cc.has_header_symbol('linux/fs.h', 'FIFREEZE')
2361        qga_fsfreeze = true
2362    endif
2363    if cc.has_header_symbol('linux/fs.h', 'FITRIM')
2364        qga_fstrim = true
2365    endif
2366elif host_os == 'freebsd' and cc.has_header_symbol('ufs/ffs/fs.h', 'UFSSUSPEND')
2367    qga_fsfreeze = true
2368endif
2369
2370if get_option('block_drv_ro_whitelist') == ''
2371  config_host_data.set('CONFIG_BDRV_RO_WHITELIST', '')
2372else
2373  config_host_data.set('CONFIG_BDRV_RO_WHITELIST',
2374        '"' + get_option('block_drv_ro_whitelist').replace(',', '", "') + '", ')
2375endif
2376if get_option('block_drv_rw_whitelist') == ''
2377  config_host_data.set('CONFIG_BDRV_RW_WHITELIST', '')
2378else
2379  config_host_data.set('CONFIG_BDRV_RW_WHITELIST',
2380        '"' + get_option('block_drv_rw_whitelist').replace(',', '", "') + '", ')
2381endif
2382
2383foreach k : get_option('trace_backends')
2384  config_host_data.set('CONFIG_TRACE_' + k.to_upper(), true)
2385endforeach
2386config_host_data.set_quoted('CONFIG_TRACE_FILE', get_option('trace_file'))
2387config_host_data.set_quoted('CONFIG_TLS_PRIORITY', get_option('tls_priority'))
2388if iasl.found()
2389  config_host_data.set_quoted('CONFIG_IASL', iasl.full_path())
2390endif
2391config_host_data.set_quoted('CONFIG_BINDIR', get_option('prefix') / get_option('bindir'))
2392config_host_data.set_quoted('CONFIG_PREFIX', get_option('prefix'))
2393config_host_data.set_quoted('CONFIG_QEMU_CONFDIR', get_option('prefix') / qemu_confdir)
2394config_host_data.set_quoted('CONFIG_QEMU_DATADIR', get_option('prefix') / qemu_datadir)
2395config_host_data.set_quoted('CONFIG_QEMU_DESKTOPDIR', get_option('prefix') / qemu_desktopdir)
2396
2397qemu_firmwarepath = ''
2398foreach k : get_option('qemu_firmwarepath')
2399  qemu_firmwarepath += '"' + get_option('prefix') / k + '", '
2400endforeach
2401config_host_data.set('CONFIG_QEMU_FIRMWAREPATH', qemu_firmwarepath)
2402
2403config_host_data.set_quoted('CONFIG_QEMU_HELPERDIR', get_option('prefix') / get_option('libexecdir'))
2404config_host_data.set_quoted('CONFIG_QEMU_ICONDIR', get_option('prefix') / qemu_icondir)
2405config_host_data.set_quoted('CONFIG_QEMU_LOCALEDIR', get_option('prefix') / get_option('localedir'))
2406config_host_data.set_quoted('CONFIG_QEMU_LOCALSTATEDIR', get_option('prefix') / get_option('localstatedir'))
2407config_host_data.set_quoted('CONFIG_QEMU_MODDIR', get_option('prefix') / qemu_moddir)
2408config_host_data.set_quoted('CONFIG_SYSCONFDIR', get_option('prefix') / get_option('sysconfdir'))
2409
2410if enable_modules
2411  config_host_data.set('CONFIG_STAMP', run_command(
2412      meson.current_source_dir() / 'scripts/qemu-stamp.py',
2413      meson.project_version(), get_option('pkgversion'), '--',
2414      meson.current_source_dir() / 'configure',
2415      capture: true, check: true).stdout().strip())
2416endif
2417
2418have_slirp_smbd = get_option('slirp_smbd') \
2419  .require(host_os != 'windows', error_message: 'Host smbd not supported on this platform.') \
2420  .allowed()
2421if have_slirp_smbd
2422  smbd_path = get_option('smbd')
2423  if smbd_path == ''
2424    smbd_path = (host_os == 'sunos' ? '/usr/sfw/sbin/smbd' : '/usr/sbin/smbd')
2425  endif
2426  config_host_data.set_quoted('CONFIG_SMBD_COMMAND', smbd_path)
2427endif
2428
2429config_host_data.set('HOST_' + host_arch.to_upper(), 1)
2430
2431kvm_targets_c = '""'
2432if get_option('kvm').allowed() and host_os == 'linux'
2433  kvm_targets_c = '"' + '" ,"'.join(kvm_targets) + '"'
2434endif
2435config_host_data.set('CONFIG_KVM_TARGETS', kvm_targets_c)
2436
2437if get_option('module_upgrades') and not enable_modules
2438  error('Cannot enable module-upgrades as modules are not enabled')
2439endif
2440config_host_data.set('CONFIG_MODULE_UPGRADES', get_option('module_upgrades'))
2441
2442config_host_data.set('CONFIG_ATTR', libattr.found())
2443config_host_data.set('CONFIG_BDRV_WHITELIST_TOOLS', get_option('block_drv_whitelist_in_tools'))
2444config_host_data.set('CONFIG_BRLAPI', brlapi.found())
2445config_host_data.set('CONFIG_BSD', host_os in bsd_oses)
2446config_host_data.set('CONFIG_FREEBSD', host_os == 'freebsd')
2447config_host_data.set('CONFIG_CAPSTONE', capstone.found())
2448config_host_data.set('CONFIG_COCOA', cocoa.found())
2449config_host_data.set('CONFIG_DARWIN', host_os == 'darwin')
2450config_host_data.set('CONFIG_FDT', fdt.found())
2451config_host_data.set('CONFIG_FUZZ', get_option('fuzzing'))
2452config_host_data.set('CONFIG_GCOV', get_option('b_coverage'))
2453config_host_data.set('CONFIG_LIBUDEV', libudev.found())
2454config_host_data.set('CONFIG_LINUX', host_os == 'linux')
2455config_host_data.set('CONFIG_POSIX', host_os != 'windows')
2456config_host_data.set('CONFIG_WIN32', host_os == 'windows')
2457config_host_data.set('CONFIG_LZO', lzo.found())
2458config_host_data.set('CONFIG_MPATH', mpathpersist.found())
2459config_host_data.set('CONFIG_BLKIO', blkio.found())
2460if blkio.found()
2461  config_host_data.set('CONFIG_BLKIO_VHOST_VDPA_FD',
2462                       blkio.version().version_compare('>=1.3.0'))
2463  config_host_data.set('CONFIG_BLKIO_WRITE_ZEROS_FUA',
2464                       blkio.version().version_compare('>=1.4.0'))
2465endif
2466config_host_data.set('CONFIG_CURL', curl.found())
2467config_host_data.set('CONFIG_CURSES', curses.found())
2468config_host_data.set('CONFIG_GBM', gbm.found())
2469config_host_data.set('CONFIG_GIO', gio.found())
2470config_host_data.set('CONFIG_GLUSTERFS', glusterfs.found())
2471if glusterfs.found()
2472  config_host_data.set('CONFIG_GLUSTERFS_XLATOR_OPT', glusterfs.version().version_compare('>=4'))
2473  config_host_data.set('CONFIG_GLUSTERFS_DISCARD', glusterfs.version().version_compare('>=5'))
2474  config_host_data.set('CONFIG_GLUSTERFS_FALLOCATE', glusterfs.version().version_compare('>=6'))
2475  config_host_data.set('CONFIG_GLUSTERFS_ZEROFILL', glusterfs.version().version_compare('>=6'))
2476  config_host_data.set('CONFIG_GLUSTERFS_FTRUNCATE_HAS_STAT', glusterfs_ftruncate_has_stat)
2477  config_host_data.set('CONFIG_GLUSTERFS_IOCB_HAS_STAT', glusterfs_iocb_has_stat)
2478endif
2479config_host_data.set('CONFIG_GTK', gtk.found())
2480config_host_data.set('CONFIG_VTE', vte.found())
2481config_host_data.set('CONFIG_GTK_CLIPBOARD', have_gtk_clipboard)
2482config_host_data.set('CONFIG_HEXAGON_IDEF_PARSER', get_option('hexagon_idef_parser'))
2483config_host_data.set('CONFIG_LIBATTR', have_old_libattr)
2484config_host_data.set('CONFIG_LIBCAP_NG', libcap_ng.found())
2485config_host_data.set('CONFIG_EBPF', libbpf.found())
2486config_host_data.set('CONFIG_AF_XDP', libxdp.found())
2487config_host_data.set('CONFIG_LIBDAXCTL', libdaxctl.found())
2488config_host_data.set('CONFIG_LIBISCSI', libiscsi.found())
2489config_host_data.set('CONFIG_LIBNFS', libnfs.found())
2490config_host_data.set('CONFIG_LIBSSH', libssh.found())
2491config_host_data.set('CONFIG_LINUX_AIO', libaio.found())
2492config_host_data.set('CONFIG_LINUX_IO_URING', linux_io_uring.found())
2493config_host_data.set('CONFIG_LIBPMEM', libpmem.found())
2494config_host_data.set('CONFIG_MODULES', enable_modules)
2495config_host_data.set('CONFIG_NUMA', numa.found())
2496if numa.found()
2497  config_host_data.set('HAVE_NUMA_HAS_PREFERRED_MANY',
2498                       cc.has_function('numa_has_preferred_many',
2499                                       dependencies: numa))
2500endif
2501config_host_data.set('CONFIG_OPENGL', opengl.found())
2502config_host_data.set('CONFIG_PLUGIN', get_option('plugins'))
2503config_host_data.set('CONFIG_RBD', rbd.found())
2504config_host_data.set('CONFIG_RDMA', rdma.found())
2505config_host_data.set('CONFIG_RELOCATABLE', get_option('relocatable'))
2506config_host_data.set('CONFIG_SAFESTACK', get_option('safe_stack'))
2507config_host_data.set('CONFIG_SDL', sdl.found())
2508config_host_data.set('CONFIG_SDL_IMAGE', sdl_image.found())
2509config_host_data.set('CONFIG_SECCOMP', seccomp.found())
2510if seccomp.found()
2511  config_host_data.set('CONFIG_SECCOMP_SYSRAWRC', seccomp_has_sysrawrc)
2512endif
2513config_host_data.set('CONFIG_PIXMAN', pixman.found())
2514config_host_data.set('CONFIG_SLIRP', slirp.found())
2515config_host_data.set('CONFIG_SNAPPY', snappy.found())
2516config_host_data.set('CONFIG_SOLARIS', host_os == 'sunos')
2517if get_option('tcg').allowed()
2518  config_host_data.set('CONFIG_TCG', 1)
2519  config_host_data.set('CONFIG_TCG_INTERPRETER', tcg_arch == 'tci')
2520endif
2521config_host_data.set('CONFIG_TPM', have_tpm)
2522config_host_data.set('CONFIG_TSAN', get_option('tsan'))
2523config_host_data.set('CONFIG_USB_LIBUSB', libusb.found())
2524config_host_data.set('CONFIG_VDE', vde.found())
2525config_host_data.set('CONFIG_VHOST', have_vhost)
2526config_host_data.set('CONFIG_VHOST_NET', have_vhost_net)
2527config_host_data.set('CONFIG_VHOST_NET_USER', have_vhost_net_user)
2528config_host_data.set('CONFIG_VHOST_NET_VDPA', have_vhost_net_vdpa)
2529config_host_data.set('CONFIG_VHOST_KERNEL', have_vhost_kernel)
2530config_host_data.set('CONFIG_VHOST_USER', have_vhost_user)
2531config_host_data.set('CONFIG_VHOST_CRYPTO', have_vhost_user_crypto)
2532config_host_data.set('CONFIG_VHOST_VDPA', have_vhost_vdpa)
2533config_host_data.set('CONFIG_VMNET', vmnet.found())
2534config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', have_vhost_user_blk_server)
2535config_host_data.set('CONFIG_VDUSE_BLK_EXPORT', have_vduse_blk_export)
2536config_host_data.set('CONFIG_PNG', png.found())
2537config_host_data.set('CONFIG_VNC', vnc.found())
2538config_host_data.set('CONFIG_VNC_JPEG', jpeg.found())
2539config_host_data.set('CONFIG_VNC_SASL', sasl.found())
2540if virgl.found()
2541  config_host_data.set('VIRGL_VERSION_MAJOR', virgl.version().split('.')[0])
2542endif
2543config_host_data.set('CONFIG_VIRTFS', have_virtfs)
2544config_host_data.set('CONFIG_VTE', vte.found())
2545config_host_data.set('CONFIG_XKBCOMMON', xkbcommon.found())
2546config_host_data.set('CONFIG_KEYUTILS', keyutils.found())
2547config_host_data.set('CONFIG_GETTID', has_gettid)
2548config_host_data.set('CONFIG_GNUTLS', gnutls.found())
2549config_host_data.set('CONFIG_GNUTLS_CRYPTO', gnutls_crypto.found())
2550config_host_data.set('CONFIG_TASN1', tasn1.found())
2551config_host_data.set('CONFIG_GCRYPT', gcrypt.found())
2552config_host_data.set('CONFIG_NETTLE', nettle.found())
2553config_host_data.set('CONFIG_CRYPTO_SM4', crypto_sm4.found())
2554config_host_data.set('CONFIG_CRYPTO_SM3', crypto_sm3.found())
2555config_host_data.set('CONFIG_HOGWEED', hogweed.found())
2556config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private')
2557config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim)
2558config_host_data.set('CONFIG_STATX', has_statx)
2559config_host_data.set('CONFIG_STATX_MNT_ID', has_statx_mnt_id)
2560config_host_data.set('CONFIG_ZSTD', zstd.found())
2561config_host_data.set('CONFIG_QPL', qpl.found())
2562config_host_data.set('CONFIG_UADK', uadk.found())
2563config_host_data.set('CONFIG_QATZIP', qatzip.found())
2564config_host_data.set('CONFIG_FUSE', fuse.found())
2565config_host_data.set('CONFIG_FUSE_LSEEK', fuse_lseek.found())
2566config_host_data.set('CONFIG_SPICE_PROTOCOL', spice_protocol.found())
2567if spice_protocol.found()
2568config_host_data.set('CONFIG_SPICE_PROTOCOL_MAJOR', spice_protocol.version().split('.')[0])
2569config_host_data.set('CONFIG_SPICE_PROTOCOL_MINOR', spice_protocol.version().split('.')[1])
2570config_host_data.set('CONFIG_SPICE_PROTOCOL_MICRO', spice_protocol.version().split('.')[2])
2571endif
2572config_host_data.set('CONFIG_SPICE', spice.found())
2573config_host_data.set('CONFIG_X11', x11.found())
2574config_host_data.set('CONFIG_DBUS_DISPLAY', dbus_display)
2575config_host_data.set('CONFIG_CFI', get_option('cfi'))
2576config_host_data.set('CONFIG_SELINUX', selinux.found())
2577config_host_data.set('CONFIG_XEN_BACKEND', xen.found())
2578config_host_data.set('CONFIG_LIBDW', libdw.found())
2579if xen.found()
2580  # protect from xen.version() having less than three components
2581  xen_version = xen.version().split('.') + ['0', '0']
2582  xen_ctrl_version = xen_version[0] + \
2583    ('0' + xen_version[1]).substring(-2) + \
2584    ('0' + xen_version[2]).substring(-2)
2585  config_host_data.set('CONFIG_XEN_CTRL_INTERFACE_VERSION', xen_ctrl_version)
2586endif
2587config_host_data.set('QEMU_VERSION', '"@0@"'.format(meson.project_version()))
2588config_host_data.set('QEMU_VERSION_MAJOR', meson.project_version().split('.')[0])
2589config_host_data.set('QEMU_VERSION_MINOR', meson.project_version().split('.')[1])
2590config_host_data.set('QEMU_VERSION_MICRO', meson.project_version().split('.')[2])
2591
2592config_host_data.set_quoted('CONFIG_HOST_DSOSUF', host_dsosuf)
2593config_host_data.set('HAVE_HOST_BLOCK_DEVICE', have_host_block_device)
2594
2595have_coroutine_pool = get_option('coroutine_pool')
2596if get_option('debug_stack_usage') and have_coroutine_pool
2597  message('Disabling coroutine pool to measure stack usage')
2598  have_coroutine_pool = false
2599endif
2600config_host_data.set('CONFIG_COROUTINE_POOL', have_coroutine_pool)
2601config_host_data.set('CONFIG_DEBUG_GRAPH_LOCK', get_option('debug_graph_lock'))
2602config_host_data.set('CONFIG_DEBUG_MUTEX', get_option('debug_mutex'))
2603config_host_data.set('CONFIG_DEBUG_STACK_USAGE', get_option('debug_stack_usage'))
2604config_host_data.set('CONFIG_DEBUG_TCG', get_option('debug_tcg'))
2605config_host_data.set('CONFIG_DEBUG_REMAP', get_option('debug_remap'))
2606config_host_data.set('CONFIG_QOM_CAST_DEBUG', get_option('qom_cast_debug'))
2607config_host_data.set('CONFIG_REPLICATION', get_option('replication').allowed())
2608config_host_data.set('CONFIG_FSFREEZE', qga_fsfreeze)
2609config_host_data.set('CONFIG_FSTRIM', qga_fstrim)
2610
2611# has_header
2612config_host_data.set('CONFIG_EPOLL', cc.has_header('sys/epoll.h'))
2613config_host_data.set('CONFIG_LINUX_MAGIC_H', cc.has_header('linux/magic.h'))
2614config_host_data.set('CONFIG_VALGRIND_H', cc.has_header('valgrind/valgrind.h'))
2615config_host_data.set('HAVE_BTRFS_H', cc.has_header('linux/btrfs.h'))
2616config_host_data.set('HAVE_DRM_H', cc.has_header('libdrm/drm.h'))
2617config_host_data.set('HAVE_OPENAT2_H', cc.has_header('linux/openat2.h'))
2618config_host_data.set('HAVE_PTY_H', cc.has_header('pty.h'))
2619config_host_data.set('HAVE_SYS_DISK_H', cc.has_header('sys/disk.h'))
2620config_host_data.set('HAVE_SYS_IOCCOM_H', cc.has_header('sys/ioccom.h'))
2621config_host_data.set('HAVE_SYS_KCOV_H', cc.has_header('sys/kcov.h'))
2622if host_os == 'windows'
2623  config_host_data.set('HAVE_AFUNIX_H', cc.has_header('afunix.h'))
2624endif
2625
2626# has_function
2627config_host_data.set('CONFIG_CLOSE_RANGE', cc.has_function('close_range'))
2628config_host_data.set('CONFIG_ACCEPT4', cc.has_function('accept4'))
2629config_host_data.set('CONFIG_CLOCK_ADJTIME', cc.has_function('clock_adjtime'))
2630config_host_data.set('CONFIG_DUP3', cc.has_function('dup3'))
2631config_host_data.set('CONFIG_FALLOCATE', cc.has_function('fallocate'))
2632config_host_data.set('CONFIG_POSIX_FALLOCATE', cc.has_function('posix_fallocate'))
2633config_host_data.set('CONFIG_GETCPU', cc.has_function('getcpu', prefix: gnu_source_prefix))
2634config_host_data.set('CONFIG_SCHED_GETCPU', cc.has_function('sched_getcpu', prefix: '#include <sched.h>'))
2635# Note that we need to specify prefix: here to avoid incorrectly
2636# thinking that Windows has posix_memalign()
2637config_host_data.set('CONFIG_POSIX_MEMALIGN', cc.has_function('posix_memalign', prefix: '#include <stdlib.h>'))
2638config_host_data.set('CONFIG_ALIGNED_MALLOC', cc.has_function('_aligned_malloc'))
2639config_host_data.set('CONFIG_VALLOC', cc.has_function('valloc'))
2640config_host_data.set('CONFIG_MEMALIGN', cc.has_function('memalign'))
2641config_host_data.set('CONFIG_PPOLL', cc.has_function('ppoll'))
2642config_host_data.set('CONFIG_PREADV', cc.has_function('preadv', prefix: '#include <sys/uio.h>'))
2643config_host_data.set('CONFIG_PTHREAD_FCHDIR_NP', cc.has_function('pthread_fchdir_np'))
2644config_host_data.set('CONFIG_SENDFILE', cc.has_function('sendfile'))
2645config_host_data.set('CONFIG_SETNS', cc.has_function('setns') and cc.has_function('unshare'))
2646config_host_data.set('CONFIG_SYNCFS', cc.has_function('syncfs'))
2647config_host_data.set('CONFIG_SYNC_FILE_RANGE', cc.has_function('sync_file_range'))
2648config_host_data.set('CONFIG_TIMERFD', cc.has_function('timerfd_create'))
2649config_host_data.set('CONFIG_GETLOADAVG', cc.has_function('getloadavg'))
2650config_host_data.set('HAVE_COPY_FILE_RANGE', cc.has_function('copy_file_range'))
2651config_host_data.set('HAVE_GETIFADDRS', cc.has_function('getifaddrs'))
2652config_host_data.set('HAVE_GLIB_WITH_SLICE_ALLOCATOR', glib_has_gslice)
2653config_host_data.set('HAVE_GLIB_WITH_ALIGNED_ALLOC', glib_has_aligned_alloc)
2654config_host_data.set('HAVE_OPENPTY', cc.has_function('openpty', dependencies: util))
2655config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul'))
2656config_host_data.set('HAVE_SYSTEM_FUNCTION', cc.has_function('system', prefix: '#include <stdlib.h>'))
2657if rbd.found()
2658  config_host_data.set('HAVE_RBD_NAMESPACE_EXISTS',
2659                       cc.has_function('rbd_namespace_exists',
2660                                       dependencies: rbd,
2661                                       prefix: '#include <rbd/librbd.h>'))
2662endif
2663if rdma.found()
2664  config_host_data.set('HAVE_IBV_ADVISE_MR',
2665                       cc.has_function('ibv_advise_mr',
2666                                       dependencies: rdma,
2667                                       prefix: '#include <infiniband/verbs.h>'))
2668endif
2669
2670have_asan_fiber = false
2671if get_option('asan') and \
2672   not cc.has_function('__sanitizer_start_switch_fiber',
2673                         args: '-fsanitize=address',
2674                         prefix: '#include <sanitizer/asan_interface.h>')
2675  warning('Missing ASAN due to missing fiber annotation interface')
2676  warning('Without code annotation, the report may be inferior.')
2677else
2678  have_asan_fiber = true
2679endif
2680config_host_data.set('CONFIG_ASAN_IFACE_FIBER', have_asan_fiber)
2681
2682have_inotify_init = cc.has_header_symbol('sys/inotify.h', 'inotify_init')
2683have_inotify_init1 = cc.has_header_symbol('sys/inotify.h', 'inotify_init1')
2684inotify = not_found
2685if (have_inotify_init or have_inotify_init1) and host_os == 'freebsd'
2686  # libinotify-kqueue
2687  inotify = cc.find_library('inotify')
2688  if have_inotify_init
2689    have_inotify_init = inotify.found()
2690  endif
2691  if have_inotify_init1
2692    have_inotify_init1 = inotify.found()
2693  endif
2694endif
2695config_host_data.set('CONFIG_INOTIFY', have_inotify_init)
2696config_host_data.set('CONFIG_INOTIFY1', have_inotify_init1)
2697
2698# has_header_symbol
2699config_host_data.set('CONFIG_BLKZONED',
2700                     cc.has_header_symbol('linux/blkzoned.h', 'BLKOPENZONE'))
2701config_host_data.set('CONFIG_EPOLL_CREATE1',
2702                     cc.has_header_symbol('sys/epoll.h', 'epoll_create1'))
2703config_host_data.set('CONFIG_FALLOCATE_PUNCH_HOLE',
2704                     cc.has_header_symbol('linux/falloc.h', 'FALLOC_FL_PUNCH_HOLE') and
2705                     cc.has_header_symbol('linux/falloc.h', 'FALLOC_FL_KEEP_SIZE'))
2706config_host_data.set('CONFIG_FALLOCATE_ZERO_RANGE',
2707                     cc.has_header_symbol('linux/falloc.h', 'FALLOC_FL_ZERO_RANGE'))
2708config_host_data.set('CONFIG_FIEMAP',
2709                     cc.has_header('linux/fiemap.h') and
2710                     cc.has_header_symbol('linux/fs.h', 'FS_IOC_FIEMAP'))
2711config_host_data.set('CONFIG_GETRANDOM',
2712                     cc.has_function('getrandom') and
2713                     cc.has_header_symbol('sys/random.h', 'GRND_NONBLOCK'))
2714config_host_data.set('CONFIG_PRCTL_PR_SET_TIMERSLACK',
2715                     cc.has_header_symbol('sys/prctl.h', 'PR_SET_TIMERSLACK'))
2716config_host_data.set('CONFIG_RTNETLINK',
2717                     cc.has_header_symbol('linux/rtnetlink.h', 'IFLA_PROTO_DOWN'))
2718config_host_data.set('CONFIG_SYSMACROS',
2719                     cc.has_header_symbol('sys/sysmacros.h', 'makedev'))
2720config_host_data.set('HAVE_OPTRESET',
2721                     cc.has_header_symbol('getopt.h', 'optreset'))
2722config_host_data.set('HAVE_IPPROTO_MPTCP',
2723                     cc.has_header_symbol('netinet/in.h', 'IPPROTO_MPTCP'))
2724
2725# has_member
2726config_host_data.set('HAVE_SIGEV_NOTIFY_THREAD_ID',
2727                     cc.has_member('struct sigevent', 'sigev_notify_thread_id',
2728                                   prefix: '#include <signal.h>'))
2729config_host_data.set('HAVE_STRUCT_STAT_ST_ATIM',
2730                     cc.has_member('struct stat', 'st_atim',
2731                                   prefix: '#include <sys/stat.h>'))
2732config_host_data.set('HAVE_BLK_ZONE_REP_CAPACITY',
2733                     cc.has_member('struct blk_zone', 'capacity',
2734                                   prefix: '#include <linux/blkzoned.h>'))
2735
2736# has_type
2737config_host_data.set('CONFIG_IOVEC',
2738                     cc.has_type('struct iovec',
2739                                 prefix: '#include <sys/uio.h>'))
2740config_host_data.set('HAVE_UTMPX',
2741                     cc.has_type('struct utmpx',
2742                                 prefix: '#include <utmpx.h>'))
2743
2744config_host_data.set('CONFIG_EVENTFD', cc.links('''
2745  #include <sys/eventfd.h>
2746  int main(void) { return eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); }'''))
2747config_host_data.set('CONFIG_FDATASYNC', cc.links(gnu_source_prefix + '''
2748  #include <unistd.h>
2749  int main(void) {
2750  #if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
2751  return fdatasync(0);
2752  #else
2753  #error Not supported
2754  #endif
2755  }'''))
2756
2757has_madvise = cc.links(gnu_source_prefix + '''
2758  #include <sys/types.h>
2759  #include <sys/mman.h>
2760  #include <stddef.h>
2761  int main(void) { return madvise(NULL, 0, MADV_DONTNEED); }''')
2762missing_madvise_proto = false
2763if has_madvise
2764  # Some platforms (illumos and Solaris before Solaris 11) provide madvise()
2765  # but forget to prototype it. In this case, has_madvise will be true (the
2766  # test program links despite a compile warning). To detect the
2767  # missing-prototype case, we try again with a definitely-bogus prototype.
2768  # This will only compile if the system headers don't provide the prototype;
2769  # otherwise the conflicting prototypes will cause a compiler error.
2770  missing_madvise_proto = cc.links(gnu_source_prefix + '''
2771    #include <sys/types.h>
2772    #include <sys/mman.h>
2773    #include <stddef.h>
2774    extern int madvise(int);
2775    int main(void) { return madvise(0); }''')
2776endif
2777config_host_data.set('CONFIG_MADVISE', has_madvise)
2778config_host_data.set('HAVE_MADVISE_WITHOUT_PROTOTYPE', missing_madvise_proto)
2779
2780config_host_data.set('CONFIG_MEMFD', cc.links(gnu_source_prefix + '''
2781  #include <sys/mman.h>
2782  int main(void) { return memfd_create("foo", MFD_ALLOW_SEALING); }'''))
2783config_host_data.set('CONFIG_OPEN_BY_HANDLE', cc.links(gnu_source_prefix + '''
2784  #include <fcntl.h>
2785  #if !defined(AT_EMPTY_PATH)
2786  # error missing definition
2787  #else
2788  int main(void) { struct file_handle fh; return open_by_handle_at(0, &fh, 0); }
2789  #endif'''))
2790
2791# On Darwin posix_madvise() has the same return semantics as plain madvise(),
2792# i.e. errno is set and -1 is returned. That's not really how POSIX defines the
2793# function. On the flip side, it has madvise() which is preferred anyways.
2794if host_os != 'darwin'
2795  config_host_data.set('CONFIG_POSIX_MADVISE', cc.links(gnu_source_prefix + '''
2796    #include <sys/mman.h>
2797    #include <stddef.h>
2798    int main(void) { return posix_madvise(NULL, 0, POSIX_MADV_DONTNEED); }'''))
2799endif
2800
2801config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_W_TID', cc.links(gnu_source_prefix + '''
2802  #include <pthread.h>
2803
2804  static void *f(void *p) { return NULL; }
2805  int main(void)
2806  {
2807    pthread_t thread;
2808    pthread_create(&thread, 0, f, 0);
2809    pthread_setname_np(thread, "QEMU");
2810    return 0;
2811  }''', dependencies: threads))
2812config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_WO_TID', cc.links(gnu_source_prefix + '''
2813  #include <pthread.h>
2814
2815  static void *f(void *p) { pthread_setname_np("QEMU"); return NULL; }
2816  int main(void)
2817  {
2818    pthread_t thread;
2819    pthread_create(&thread, 0, f, 0);
2820    return 0;
2821  }''', dependencies: threads))
2822config_host_data.set('CONFIG_PTHREAD_SET_NAME_NP', cc.links(gnu_source_prefix + '''
2823  #include <pthread.h>
2824  #include <pthread_np.h>
2825
2826  static void *f(void *p) { return NULL; }
2827  int main(void)
2828  {
2829    pthread_t thread;
2830    pthread_create(&thread, 0, f, 0);
2831    pthread_set_name_np(thread, "QEMU");
2832    return 0;
2833  }''', dependencies: threads))
2834config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(gnu_source_prefix + '''
2835  #include <pthread.h>
2836  #include <time.h>
2837
2838  int main(void)
2839  {
2840    pthread_condattr_t attr
2841    pthread_condattr_init(&attr);
2842    pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
2843    return 0;
2844  }''', dependencies: threads))
2845config_host_data.set('CONFIG_PTHREAD_AFFINITY_NP', cc.links(gnu_source_prefix + '''
2846  #include <pthread.h>
2847
2848  static void *f(void *p) { return NULL; }
2849  int main(void)
2850  {
2851    int setsize = CPU_ALLOC_SIZE(64);
2852    pthread_t thread;
2853    cpu_set_t *cpuset;
2854    pthread_create(&thread, 0, f, 0);
2855    cpuset = CPU_ALLOC(64);
2856    CPU_ZERO_S(setsize, cpuset);
2857    pthread_setaffinity_np(thread, setsize, cpuset);
2858    pthread_getaffinity_np(thread, setsize, cpuset);
2859    CPU_FREE(cpuset);
2860    return 0;
2861  }''', dependencies: threads))
2862config_host_data.set('CONFIG_SIGNALFD', cc.links(gnu_source_prefix + '''
2863  #include <sys/signalfd.h>
2864  #include <stddef.h>
2865  int main(void) { return signalfd(-1, NULL, SFD_CLOEXEC); }'''))
2866config_host_data.set('CONFIG_SPLICE', cc.links(gnu_source_prefix + '''
2867  #include <unistd.h>
2868  #include <fcntl.h>
2869  #include <limits.h>
2870
2871  int main(void)
2872  {
2873    int len, fd = 0;
2874    len = tee(STDIN_FILENO, STDOUT_FILENO, INT_MAX, SPLICE_F_NONBLOCK);
2875    splice(STDIN_FILENO, NULL, fd, NULL, len, SPLICE_F_MOVE);
2876    return 0;
2877  }'''))
2878
2879config_host_data.set('HAVE_MLOCKALL', cc.links(gnu_source_prefix + '''
2880  #include <sys/mman.h>
2881  int main(void) {
2882    return mlockall(MCL_FUTURE);
2883  }'''))
2884
2885have_l2tpv3 = false
2886if get_option('l2tpv3').allowed() and have_system
2887  have_l2tpv3 = cc.has_type('struct mmsghdr',
2888    prefix: gnu_source_prefix + '''
2889      #include <sys/socket.h>
2890      #include <linux/ip.h>''')
2891endif
2892config_host_data.set('CONFIG_L2TPV3', have_l2tpv3)
2893
2894have_netmap = false
2895if get_option('netmap').allowed() and have_system
2896  have_netmap = cc.compiles('''
2897    #include <inttypes.h>
2898    #include <net/if.h>
2899    #include <net/netmap.h>
2900    #include <net/netmap_user.h>
2901    #if (NETMAP_API < 11) || (NETMAP_API > 15)
2902    #error
2903    #endif
2904    int main(void) { return 0; }''')
2905  if not have_netmap and get_option('netmap').enabled()
2906    error('Netmap headers not available')
2907  endif
2908endif
2909config_host_data.set('CONFIG_NETMAP', have_netmap)
2910
2911# Work around a system header bug with some kernel/XFS header
2912# versions where they both try to define 'struct fsxattr':
2913# xfs headers will not try to redefine structs from linux headers
2914# if this macro is set.
2915config_host_data.set('HAVE_FSXATTR', cc.links('''
2916  #include <linux/fs.h>
2917  struct fsxattr foo;
2918  int main(void) {
2919    return 0;
2920  }'''))
2921
2922# Some versions of Mac OS X incorrectly define SIZE_MAX
2923config_host_data.set('HAVE_BROKEN_SIZE_MAX', not cc.compiles('''
2924    #include <stdint.h>
2925    #include <stdio.h>
2926    int main(void) {
2927        return printf("%zu", SIZE_MAX);
2928    }''', args: ['-Werror']))
2929
2930# See if 64-bit atomic operations are supported.
2931# Note that without __atomic builtins, we can only
2932# assume atomic loads/stores max at pointer size.
2933config_host_data.set('CONFIG_ATOMIC64', cc.links('''
2934  #include <stdint.h>
2935  int main(void)
2936  {
2937    uint64_t x = 0, y = 0;
2938    y = __atomic_load_n(&x, __ATOMIC_RELAXED);
2939    __atomic_store_n(&x, y, __ATOMIC_RELAXED);
2940    __atomic_compare_exchange_n(&x, &y, x, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
2941    __atomic_exchange_n(&x, y, __ATOMIC_RELAXED);
2942    __atomic_fetch_add(&x, y, __ATOMIC_RELAXED);
2943    return 0;
2944  }''', args: qemu_isa_flags))
2945
2946has_int128_type = cc.compiles('''
2947  __int128_t a;
2948  __uint128_t b;
2949  int main(void) { b = a; }''')
2950config_host_data.set('CONFIG_INT128_TYPE', has_int128_type)
2951
2952has_int128 = has_int128_type and cc.links('''
2953  __int128_t a;
2954  __uint128_t b;
2955  int main (void) {
2956    a = a + b;
2957    b = a * b;
2958    a = a * a;
2959    return 0;
2960  }''')
2961config_host_data.set('CONFIG_INT128', has_int128)
2962
2963if has_int128_type
2964  # "do we have 128-bit atomics which are handled inline and specifically not
2965  # via libatomic". The reason we can't use libatomic is documented in the
2966  # comment starting "GCC is a house divided" in include/qemu/atomic128.h.
2967  # We only care about these operations on 16-byte aligned pointers, so
2968  # force 16-byte alignment of the pointer, which may be greater than
2969  # __alignof(unsigned __int128) for the host.
2970  atomic_test_128 = '''
2971    int main(int ac, char **av) {
2972      __uint128_t *p = __builtin_assume_aligned(av[ac - 1], 16);
2973      p[1] = __atomic_load_n(&p[0], __ATOMIC_RELAXED);
2974      __atomic_store_n(&p[2], p[3], __ATOMIC_RELAXED);
2975      __atomic_compare_exchange_n(&p[4], &p[5], p[6], 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
2976      return 0;
2977    }'''
2978  has_atomic128 = cc.links(atomic_test_128, args: qemu_isa_flags)
2979
2980  config_host_data.set('CONFIG_ATOMIC128', has_atomic128)
2981
2982  if not has_atomic128
2983    # Even with __builtin_assume_aligned, the above test may have failed
2984    # without optimization enabled.  Try again with optimizations locally
2985    # enabled for the function.  See
2986    #   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107389
2987    has_atomic128_opt = cc.links('__attribute__((optimize("O1")))' + atomic_test_128,
2988                                 args: qemu_isa_flags)
2989    config_host_data.set('CONFIG_ATOMIC128_OPT', has_atomic128_opt)
2990
2991    if not has_atomic128_opt
2992      config_host_data.set('CONFIG_CMPXCHG128', cc.links('''
2993        int main(void)
2994        {
2995          __uint128_t x = 0, y = 0;
2996          __sync_val_compare_and_swap_16(&x, y, x);
2997          return 0;
2998        }
2999      ''', args: qemu_isa_flags))
3000    endif
3001  endif
3002endif
3003
3004config_host_data.set('CONFIG_GETAUXVAL', cc.links(gnu_source_prefix + '''
3005  #include <sys/auxv.h>
3006  int main(void) {
3007    return getauxval(AT_HWCAP) == 0;
3008  }'''))
3009
3010config_host_data.set('CONFIG_ELF_AUX_INFO', cc.links(gnu_source_prefix + '''
3011  #include <sys/auxv.h>
3012  int main(void) {
3013    unsigned long hwcap = 0;
3014    elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap));
3015    return hwcap;
3016  }'''))
3017
3018config_host_data.set('CONFIG_USBFS', have_linux_user and cc.compiles('''
3019  #include <linux/usbdevice_fs.h>
3020
3021  #ifndef USBDEVFS_GET_CAPABILITIES
3022  #error "USBDEVFS_GET_CAPABILITIES undefined"
3023  #endif
3024
3025  #ifndef USBDEVFS_DISCONNECT_CLAIM
3026  #error "USBDEVFS_DISCONNECT_CLAIM undefined"
3027  #endif
3028
3029  int main(void) { return 0; }'''))
3030
3031have_keyring = get_option('keyring') \
3032  .require(host_os == 'linux', error_message: 'keyring is only available on Linux') \
3033  .require(cc.compiles('''
3034    #include <errno.h>
3035    #include <asm/unistd.h>
3036    #include <linux/keyctl.h>
3037    #include <sys/syscall.h>
3038    #include <unistd.h>
3039    int main(void) {
3040        return syscall(__NR_keyctl, KEYCTL_READ, 0, NULL, NULL, 0);
3041    }'''), error_message: 'keyctl syscall not available on this system').allowed()
3042config_host_data.set('CONFIG_SECRET_KEYRING', have_keyring)
3043
3044have_cpuid_h = cc.links('''
3045  #include <cpuid.h>
3046  int main(void) {
3047    unsigned a, b, c, d;
3048    unsigned max = __get_cpuid_max(0, 0);
3049
3050    if (max >= 1) {
3051        __cpuid(1, a, b, c, d);
3052    }
3053
3054    if (max >= 7) {
3055        __cpuid_count(7, 0, a, b, c, d);
3056    }
3057
3058    return 0;
3059  }''')
3060config_host_data.set('CONFIG_CPUID_H', have_cpuid_h)
3061
3062# Don't bother to advertise asm/hwprobe.h for old versions that do
3063# not contain RISCV_HWPROBE_EXT_ZBA.
3064config_host_data.set('CONFIG_ASM_HWPROBE_H',
3065                     cc.has_header_symbol('asm/hwprobe.h',
3066                                          'RISCV_HWPROBE_EXT_ZBA'))
3067
3068config_host_data.set('CONFIG_AVX2_OPT', get_option('avx2') \
3069  .require(have_cpuid_h, error_message: 'cpuid.h not available, cannot enable AVX2') \
3070  .require(cc.links('''
3071    #include <cpuid.h>
3072    #include <immintrin.h>
3073    static int __attribute__((target("avx2"))) bar(void *a) {
3074      __m256i x = *(__m256i *)a;
3075      return _mm256_testz_si256(x, x);
3076    }
3077    int main(int argc, char *argv[]) { return bar(argv[argc - 1]); }
3078  '''), error_message: 'AVX2 not available').allowed())
3079
3080config_host_data.set('CONFIG_AVX512BW_OPT', get_option('avx512bw') \
3081  .require(have_cpuid_h, error_message: 'cpuid.h not available, cannot enable AVX512BW') \
3082  .require(cc.links('''
3083    #include <cpuid.h>
3084    #include <immintrin.h>
3085    static int __attribute__((target("avx512bw"))) bar(void *a) {
3086      __m512i *x = a;
3087      __m512i res= _mm512_abs_epi8(*x);
3088      return res[1];
3089    }
3090    int main(int argc, char *argv[]) { return bar(argv[0]); }
3091  '''), error_message: 'AVX512BW not available').allowed())
3092
3093# For both AArch64 and AArch32, detect if builtins are available.
3094config_host_data.set('CONFIG_ARM_AES_BUILTIN', cc.compiles('''
3095    #include <arm_neon.h>
3096    #ifndef __ARM_FEATURE_AES
3097    __attribute__((target("+crypto")))
3098    #endif
3099    void foo(uint8x16_t *p) { *p = vaesmcq_u8(*p); }
3100  '''))
3101
3102if get_option('membarrier').disabled()
3103  have_membarrier = false
3104elif host_os == 'windows'
3105  have_membarrier = true
3106elif host_os == 'linux'
3107  have_membarrier = cc.compiles('''
3108    #include <linux/membarrier.h>
3109    #include <sys/syscall.h>
3110    #include <unistd.h>
3111    #include <stdlib.h>
3112    int main(void) {
3113        syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
3114        syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0);
3115        exit(0);
3116    }''')
3117endif
3118config_host_data.set('CONFIG_MEMBARRIER', get_option('membarrier') \
3119  .require(have_membarrier, error_message: 'membarrier system call not available') \
3120  .allowed())
3121
3122have_afalg = get_option('crypto_afalg') \
3123  .require(cc.compiles(gnu_source_prefix + '''
3124    #include <errno.h>
3125    #include <sys/types.h>
3126    #include <sys/socket.h>
3127    #include <linux/if_alg.h>
3128    int main(void) {
3129      int sock;
3130      sock = socket(AF_ALG, SOCK_SEQPACKET, 0);
3131      return sock;
3132    }
3133  '''), error_message: 'AF_ALG requested but could not be detected').allowed()
3134config_host_data.set('CONFIG_AF_ALG', have_afalg)
3135
3136config_host_data.set('CONFIG_AF_VSOCK', cc.has_header_symbol(
3137  'linux/vm_sockets.h', 'AF_VSOCK',
3138  prefix: '#include <sys/socket.h>',
3139))
3140
3141have_vss = false
3142have_vss_sdk = false # old xp/2003 SDK
3143if host_os == 'windows' and 'cpp' in all_languages
3144  have_vss = cxx.compiles('''
3145    #define __MIDL_user_allocate_free_DEFINED__
3146    #include <vss.h>
3147    int main(void) { return VSS_CTX_BACKUP; }''')
3148  have_vss_sdk = cxx.has_header('vscoordint.h')
3149endif
3150config_host_data.set('HAVE_VSS_SDK', have_vss_sdk)
3151
3152# Older versions of MinGW do not import _lock_file and _unlock_file properly.
3153# This was fixed for v6.0.0 with commit b48e3ac8969d.
3154if host_os == 'windows'
3155  config_host_data.set('HAVE__LOCK_FILE', cc.links('''
3156    #include <stdio.h>
3157    int main(void) {
3158      _lock_file(NULL);
3159      _unlock_file(NULL);
3160      return 0;
3161    }''', name: '_lock_file and _unlock_file'))
3162endif
3163
3164if host_os == 'windows'
3165  mingw_has_setjmp_longjmp = cc.links('''
3166    #include <setjmp.h>
3167    int main(void) {
3168      /*
3169       * These functions are not available in setjmp header, but may be
3170       * available at link time, from libmingwex.a.
3171       */
3172      extern int __mingw_setjmp(jmp_buf);
3173      extern void __attribute__((noreturn)) __mingw_longjmp(jmp_buf, int);
3174      jmp_buf env;
3175      __mingw_setjmp(env);
3176      __mingw_longjmp(env, 0);
3177    }
3178  ''', name: 'mingw setjmp and longjmp')
3179
3180  if cpu == 'aarch64' and not mingw_has_setjmp_longjmp
3181    error('mingw must provide setjmp/longjmp for windows-arm64')
3182  endif
3183endif
3184
3185########################
3186# Target configuration #
3187########################
3188
3189minikconf = find_program('scripts/minikconf.py')
3190
3191config_all_accel = {}
3192config_all_devices = {}
3193config_devices_mak_list = []
3194config_devices_h = {}
3195config_target_h = {}
3196config_target_mak = {}
3197
3198disassemblers = {
3199  'alpha' : ['CONFIG_ALPHA_DIS'],
3200  'avr' : ['CONFIG_AVR_DIS'],
3201  'hexagon' : ['CONFIG_HEXAGON_DIS'],
3202  'hppa' : ['CONFIG_HPPA_DIS'],
3203  'i386' : ['CONFIG_I386_DIS'],
3204  'x86_64' : ['CONFIG_I386_DIS'],
3205  'm68k' : ['CONFIG_M68K_DIS'],
3206  'microblaze' : ['CONFIG_MICROBLAZE_DIS'],
3207  'mips' : ['CONFIG_MIPS_DIS'],
3208  'or1k' : ['CONFIG_OPENRISC_DIS'],
3209  'ppc' : ['CONFIG_PPC_DIS'],
3210  'riscv' : ['CONFIG_RISCV_DIS'],
3211  'rx' : ['CONFIG_RX_DIS'],
3212  's390' : ['CONFIG_S390_DIS'],
3213  'sh4' : ['CONFIG_SH4_DIS'],
3214  'sparc' : ['CONFIG_SPARC_DIS'],
3215  'xtensa' : ['CONFIG_XTENSA_DIS'],
3216  'loongarch' : ['CONFIG_LOONGARCH_DIS'],
3217}
3218
3219have_ivshmem = config_host_data.get('CONFIG_EVENTFD')
3220host_kconfig = \
3221  (get_option('fuzzing') ? ['CONFIG_FUZZ=y'] : []) + \
3222  (have_tpm ? ['CONFIG_TPM=y'] : []) + \
3223  (pixman.found() ? ['CONFIG_PIXMAN=y'] : []) + \
3224  (spice.found() ? ['CONFIG_SPICE=y'] : []) + \
3225  (have_ivshmem ? ['CONFIG_IVSHMEM=y'] : []) + \
3226  (opengl.found() ? ['CONFIG_OPENGL=y'] : []) + \
3227  (libcbor.found() ? ['CONFIG_LIBCBOR=y'] : []) + \
3228  (gnutls.found() ? ['CONFIG_GNUTLS=y'] : []) + \
3229  (x11.found() ? ['CONFIG_X11=y'] : []) + \
3230  (fdt.found() ? ['CONFIG_FDT=y'] : []) + \
3231  (have_vhost_user ? ['CONFIG_VHOST_USER=y'] : []) + \
3232  (have_vhost_vdpa ? ['CONFIG_VHOST_VDPA=y'] : []) + \
3233  (have_vhost_kernel ? ['CONFIG_VHOST_KERNEL=y'] : []) + \
3234  (have_virtfs ? ['CONFIG_VIRTFS=y'] : []) + \
3235  (host_os == 'linux' ? ['CONFIG_LINUX=y'] : []) + \
3236  (multiprocess_allowed ? ['CONFIG_MULTIPROCESS_ALLOWED=y'] : []) + \
3237  (vfio_user_server_allowed ? ['CONFIG_VFIO_USER_SERVER_ALLOWED=y'] : []) + \
3238  (hv_balloon ? ['CONFIG_HV_BALLOON_POSSIBLE=y'] : []) + \
3239  (have_rust ? ['CONFIG_HAVE_RUST=y'] : [])
3240
3241ignored = [ 'TARGET_XML_FILES', 'TARGET_ABI_DIR', 'TARGET_ARCH' ]
3242
3243default_targets = 'CONFIG_DEFAULT_TARGETS' in config_host
3244actual_target_dirs = []
3245fdt_required = []
3246foreach target : target_dirs
3247  config_target = { 'TARGET_NAME': target.split('-')[0] }
3248  if target.endswith('linux-user')
3249    if host_os != 'linux'
3250      if default_targets
3251        continue
3252      endif
3253      error('Target @0@ is only available on a Linux host'.format(target))
3254    endif
3255    config_target += { 'CONFIG_LINUX_USER': 'y' }
3256  elif target.endswith('bsd-user')
3257    if host_os not in bsd_oses
3258      if default_targets
3259        continue
3260      endif
3261      error('Target @0@ is only available on a BSD host'.format(target))
3262    endif
3263    config_target += { 'CONFIG_BSD_USER': 'y' }
3264  elif target.endswith('softmmu')
3265    config_target += { 'CONFIG_SYSTEM_ONLY': 'y' }
3266    config_target += { 'CONFIG_SOFTMMU': 'y' }
3267  endif
3268  if target.endswith('-user')
3269    config_target += {
3270      'CONFIG_USER_ONLY': 'y',
3271      'CONFIG_QEMU_INTERP_PREFIX':
3272        get_option('interp_prefix').replace('%M', config_target['TARGET_NAME']),
3273      'CONFIG_QEMU_RTSIG_MAP': get_option('rtsig_map'),
3274    }
3275  endif
3276
3277  target_kconfig = []
3278  foreach sym: accelerators
3279    if sym == 'CONFIG_TCG' or target in accelerator_targets.get(sym, [])
3280      config_target += { sym: 'y' }
3281      config_all_accel += { sym: 'y' }
3282      if target in modular_tcg
3283        config_target += { 'CONFIG_TCG_MODULAR': 'y' }
3284      else
3285        config_target += { 'CONFIG_TCG_BUILTIN': 'y' }
3286      endif
3287      target_kconfig += [ sym + '=y' ]
3288    endif
3289  endforeach
3290  if target_kconfig.length() == 0
3291    if default_targets
3292      continue
3293    endif
3294    error('No accelerator available for target @0@'.format(target))
3295  endif
3296
3297  config_target += keyval.load('configs/targets' / target + '.mak')
3298  config_target += { 'TARGET_' + config_target['TARGET_ARCH'].to_upper(): 'y' }
3299
3300  if 'TARGET_NEED_FDT' in config_target and not fdt.found()
3301    if default_targets
3302      warning('Disabling ' + target + ' due to missing libfdt')
3303    else
3304      fdt_required += target
3305    endif
3306    continue
3307  endif
3308
3309  actual_target_dirs += target
3310
3311  # Add default keys
3312  if 'TARGET_BASE_ARCH' not in config_target
3313    config_target += {'TARGET_BASE_ARCH': config_target['TARGET_ARCH']}
3314  endif
3315  if 'TARGET_ABI_DIR' not in config_target
3316    config_target += {'TARGET_ABI_DIR': config_target['TARGET_ARCH']}
3317  endif
3318  if 'TARGET_BIG_ENDIAN' not in config_target
3319    config_target += {'TARGET_BIG_ENDIAN': 'n'}
3320  endif
3321
3322  foreach k, v: disassemblers
3323    if host_arch.startswith(k) or config_target['TARGET_BASE_ARCH'].startswith(k)
3324      foreach sym: v
3325        config_target += { sym: 'y' }
3326      endforeach
3327    endif
3328  endforeach
3329
3330  config_target_data = configuration_data()
3331  foreach k, v: config_target
3332    if not k.startswith('TARGET_') and not k.startswith('CONFIG_')
3333      # do nothing
3334    elif ignored.contains(k)
3335      # do nothing
3336    elif k == 'TARGET_BASE_ARCH'
3337      # Note that TARGET_BASE_ARCH ends up in config-target.h but it is
3338      # not used to select files from sourcesets.
3339      config_target_data.set('TARGET_' + v.to_upper(), 1)
3340    elif k == 'TARGET_NAME' or k == 'CONFIG_QEMU_INTERP_PREFIX'
3341      config_target_data.set_quoted(k, v)
3342    elif v == 'y'
3343      config_target_data.set(k, 1)
3344    elif v == 'n'
3345      config_target_data.set(k, 0)
3346    else
3347      config_target_data.set(k, v)
3348    endif
3349  endforeach
3350  config_target_data.set('QEMU_ARCH',
3351                         'QEMU_ARCH_' + config_target['TARGET_BASE_ARCH'].to_upper())
3352  config_target_h += {target: configure_file(output: target + '-config-target.h',
3353                                               configuration: config_target_data)}
3354
3355  if target.endswith('-softmmu')
3356    target_kconfig += 'CONFIG_' + config_target['TARGET_ARCH'].to_upper() + '=y'
3357    target_kconfig += 'CONFIG_TARGET_BIG_ENDIAN=' + config_target['TARGET_BIG_ENDIAN']
3358
3359    config_input = meson.get_external_property(target, 'default')
3360    config_devices_mak = target + '-config-devices.mak'
3361    config_devices_mak = configure_file(
3362      input: ['configs/devices' / target / config_input + '.mak', 'Kconfig'],
3363      output: config_devices_mak,
3364      depfile: config_devices_mak + '.d',
3365      capture: true,
3366      command: [minikconf,
3367                get_option('default_devices') ? '--defconfig' : '--allnoconfig',
3368                config_devices_mak, '@DEPFILE@', '@INPUT@',
3369                host_kconfig, target_kconfig])
3370
3371    config_devices_data = configuration_data()
3372    config_devices = keyval.load(config_devices_mak)
3373    foreach k, v: config_devices
3374      config_devices_data.set(k, 1)
3375    endforeach
3376    config_devices_mak_list += config_devices_mak
3377    config_devices_h += {target: configure_file(output: target + '-config-devices.h',
3378                                                configuration: config_devices_data)}
3379    config_target += config_devices
3380    config_all_devices += config_devices
3381  endif
3382  config_target_mak += {target: config_target}
3383endforeach
3384target_dirs = actual_target_dirs
3385
3386target_configs_h = []
3387foreach target: target_dirs
3388  target_configs_h += config_target_h[target]
3389  target_configs_h += config_devices_h.get(target, [])
3390endforeach
3391genh += custom_target('config-poison.h',
3392                      input: [target_configs_h],
3393                      output: 'config-poison.h',
3394                      capture: true,
3395                      command: [find_program('scripts/make-config-poison.sh'),
3396                                target_configs_h])
3397
3398if fdt_required.length() > 0
3399  error('fdt disabled but required by targets ' + ', '.join(fdt_required))
3400endif
3401
3402###############
3403# Subprojects #
3404###############
3405
3406libvfio_user_dep = not_found
3407if have_system and vfio_user_server_allowed
3408  libvfio_user_proj = subproject('libvfio-user', required: true)
3409  libvfio_user_dep = libvfio_user_proj.get_variable('libvfio_user_dep')
3410endif
3411
3412vhost_user = not_found
3413if host_os == 'linux' and have_vhost_user
3414  libvhost_user = subproject('libvhost-user')
3415  vhost_user = libvhost_user.get_variable('vhost_user_dep')
3416endif
3417
3418libvduse = not_found
3419if have_libvduse
3420  libvduse_proj = subproject('libvduse')
3421  libvduse = libvduse_proj.get_variable('libvduse_dep')
3422endif
3423
3424#####################
3425# Generated sources #
3426#####################
3427
3428config_host_h = configure_file(output: 'config-host.h', configuration: config_host_data)
3429genh += config_host_h
3430
3431hxtool = find_program('scripts/hxtool')
3432shaderinclude = find_program('scripts/shaderinclude.py')
3433qapi_gen = find_program('scripts/qapi-gen.py')
3434qapi_gen_depends = [ meson.current_source_dir() / 'scripts/qapi/__init__.py',
3435                     meson.current_source_dir() / 'scripts/qapi/commands.py',
3436                     meson.current_source_dir() / 'scripts/qapi/common.py',
3437                     meson.current_source_dir() / 'scripts/qapi/error.py',
3438                     meson.current_source_dir() / 'scripts/qapi/events.py',
3439                     meson.current_source_dir() / 'scripts/qapi/expr.py',
3440                     meson.current_source_dir() / 'scripts/qapi/gen.py',
3441                     meson.current_source_dir() / 'scripts/qapi/introspect.py',
3442                     meson.current_source_dir() / 'scripts/qapi/main.py',
3443                     meson.current_source_dir() / 'scripts/qapi/parser.py',
3444                     meson.current_source_dir() / 'scripts/qapi/schema.py',
3445                     meson.current_source_dir() / 'scripts/qapi/source.py',
3446                     meson.current_source_dir() / 'scripts/qapi/types.py',
3447                     meson.current_source_dir() / 'scripts/qapi/features.py',
3448                     meson.current_source_dir() / 'scripts/qapi/visit.py',
3449                     meson.current_source_dir() / 'scripts/qapi-gen.py'
3450]
3451
3452tracetool = [
3453  python, files('scripts/tracetool.py'),
3454   '--backend=' + ','.join(get_option('trace_backends'))
3455]
3456tracetool_depends = files(
3457  'scripts/tracetool/backend/log.py',
3458  'scripts/tracetool/backend/__init__.py',
3459  'scripts/tracetool/backend/dtrace.py',
3460  'scripts/tracetool/backend/ftrace.py',
3461  'scripts/tracetool/backend/simple.py',
3462  'scripts/tracetool/backend/syslog.py',
3463  'scripts/tracetool/backend/ust.py',
3464  'scripts/tracetool/format/ust_events_c.py',
3465  'scripts/tracetool/format/ust_events_h.py',
3466  'scripts/tracetool/format/__init__.py',
3467  'scripts/tracetool/format/d.py',
3468  'scripts/tracetool/format/simpletrace_stap.py',
3469  'scripts/tracetool/format/c.py',
3470  'scripts/tracetool/format/h.py',
3471  'scripts/tracetool/format/log_stap.py',
3472  'scripts/tracetool/format/stap.py',
3473  'scripts/tracetool/__init__.py',
3474)
3475
3476qemu_version_cmd = [find_program('scripts/qemu-version.sh'),
3477                    meson.current_source_dir(),
3478                    get_option('pkgversion'), meson.project_version()]
3479qemu_version = custom_target('qemu-version.h',
3480                             output: 'qemu-version.h',
3481                             command: qemu_version_cmd,
3482                             capture: true,
3483                             build_by_default: true,
3484                             build_always_stale: true)
3485genh += qemu_version
3486
3487hxdep = []
3488hx_headers = [
3489  ['qemu-options.hx', 'qemu-options.def'],
3490  ['qemu-img-cmds.hx', 'qemu-img-cmds.h'],
3491]
3492if have_system
3493  hx_headers += [
3494    ['hmp-commands.hx', 'hmp-commands.h'],
3495    ['hmp-commands-info.hx', 'hmp-commands-info.h'],
3496  ]
3497endif
3498foreach d : hx_headers
3499  hxdep += custom_target(d[1],
3500                input: files(d[0]),
3501                output: d[1],
3502                capture: true,
3503                command: [hxtool, '-h', '@INPUT0@'])
3504endforeach
3505genh += hxdep
3506
3507###############
3508# Trace files #
3509###############
3510
3511# TODO: add each directory to the subdirs from its own meson.build, once
3512# we have those
3513trace_events_subdirs = [
3514  'crypto',
3515  'qapi',
3516  'qom',
3517  'monitor',
3518  'util',
3519  'gdbstub',
3520]
3521if have_linux_user
3522  trace_events_subdirs += [ 'linux-user' ]
3523endif
3524if have_bsd_user
3525  trace_events_subdirs += [ 'bsd-user' ]
3526endif
3527if have_block
3528  trace_events_subdirs += [
3529    'authz',
3530    'block',
3531    'chardev',
3532    'io',
3533    'nbd',
3534    'scsi',
3535  ]
3536endif
3537if have_system
3538  trace_events_subdirs += [
3539    'accel/kvm',
3540    'audio',
3541    'backends',
3542    'backends/tpm',
3543    'ebpf',
3544    'hw/9pfs',
3545    'hw/acpi',
3546    'hw/adc',
3547    'hw/alpha',
3548    'hw/arm',
3549    'hw/audio',
3550    'hw/block',
3551    'hw/char',
3552    'hw/display',
3553    'hw/dma',
3554    'hw/fsi',
3555    'hw/hyperv',
3556    'hw/i2c',
3557    'hw/i386',
3558    'hw/i386/xen',
3559    'hw/i386/kvm',
3560    'hw/ide',
3561    'hw/input',
3562    'hw/intc',
3563    'hw/isa',
3564    'hw/mem',
3565    'hw/mips',
3566    'hw/misc',
3567    'hw/misc/macio',
3568    'hw/net',
3569    'hw/net/can',
3570    'hw/nubus',
3571    'hw/nvme',
3572    'hw/nvram',
3573    'hw/pci',
3574    'hw/pci-host',
3575    'hw/ppc',
3576    'hw/rtc',
3577    'hw/riscv',
3578    'hw/s390x',
3579    'hw/scsi',
3580    'hw/sd',
3581    'hw/sensor',
3582    'hw/sh4',
3583    'hw/sparc',
3584    'hw/sparc64',
3585    'hw/ssi',
3586    'hw/timer',
3587    'hw/tpm',
3588    'hw/ufs',
3589    'hw/usb',
3590    'hw/vfio',
3591    'hw/virtio',
3592    'hw/watchdog',
3593    'hw/xen',
3594    'hw/gpio',
3595    'migration',
3596    'net',
3597    'system',
3598    'ui',
3599    'hw/remote',
3600  ]
3601endif
3602if have_system or have_user
3603  trace_events_subdirs += [
3604    'accel/tcg',
3605    'hw/core',
3606    'target/arm',
3607    'target/arm/hvf',
3608    'target/hppa',
3609    'target/i386',
3610    'target/i386/kvm',
3611    'target/loongarch',
3612    'target/mips/tcg',
3613    'target/ppc',
3614    'target/riscv',
3615    'target/s390x',
3616    'target/s390x/kvm',
3617    'target/sparc',
3618  ]
3619endif
3620
3621###################
3622# Collect sources #
3623###################
3624
3625authz_ss = ss.source_set()
3626blockdev_ss = ss.source_set()
3627block_ss = ss.source_set()
3628chardev_ss = ss.source_set()
3629common_ss = ss.source_set()
3630crypto_ss = ss.source_set()
3631hwcore_ss = ss.source_set()
3632io_ss = ss.source_set()
3633qmp_ss = ss.source_set()
3634qom_ss = ss.source_set()
3635system_ss = ss.source_set()
3636specific_fuzz_ss = ss.source_set()
3637specific_ss = ss.source_set()
3638rust_devices_ss = ss.source_set()
3639stub_ss = ss.source_set()
3640trace_ss = ss.source_set()
3641user_ss = ss.source_set()
3642util_ss = ss.source_set()
3643
3644# accel modules
3645qtest_module_ss = ss.source_set()
3646tcg_module_ss = ss.source_set()
3647
3648modules = {}
3649target_modules = {}
3650hw_arch = {}
3651target_arch = {}
3652target_system_arch = {}
3653target_user_arch = {}
3654
3655# NOTE: the trace/ subdirectory needs the qapi_trace_events variable
3656# that is filled in by qapi/.
3657subdir('qapi')
3658subdir('qobject')
3659subdir('stubs')
3660subdir('trace')
3661subdir('util')
3662subdir('qom')
3663subdir('authz')
3664subdir('crypto')
3665subdir('ui')
3666subdir('gdbstub')
3667if have_system
3668  subdir('hw')
3669else
3670  subdir('hw/core')
3671endif
3672
3673if enable_modules
3674  libmodulecommon = static_library('module-common', files('module-common.c') + genh, pic: true, c_args: '-DBUILD_DSO')
3675  modulecommon = declare_dependency(objects: libmodulecommon.extract_all_objects(recursive: false), compile_args: '-DBUILD_DSO')
3676endif
3677
3678qom_ss = qom_ss.apply({})
3679libqom = static_library('qom', qom_ss.sources() + genh,
3680                        dependencies: [qom_ss.dependencies()],
3681                        build_by_default: false)
3682qom = declare_dependency(objects: libqom.extract_all_objects(recursive: false),
3683                         dependencies: qom_ss.dependencies())
3684
3685event_loop_base = files('event-loop-base.c')
3686event_loop_base = static_library('event-loop-base',
3687                                 sources: event_loop_base + genh,
3688                                 build_by_default: false)
3689event_loop_base = declare_dependency(objects: event_loop_base.extract_all_objects(recursive: false),
3690                                     dependencies: [qom])
3691
3692stub_ss = stub_ss.apply({})
3693
3694util_ss.add_all(trace_ss)
3695util_ss = util_ss.apply({})
3696libqemuutil = static_library('qemuutil',
3697                             build_by_default: false,
3698                             sources: util_ss.sources() + stub_ss.sources() + genh,
3699                             dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc])
3700qemuutil_deps = [event_loop_base]
3701if host_os != 'windows'
3702  qemuutil_deps += [rt]
3703endif
3704qemuutil = declare_dependency(link_with: libqemuutil,
3705                              sources: genh + version_res,
3706                              dependencies: qemuutil_deps)
3707
3708if have_system or have_user
3709  decodetree = generator(find_program('scripts/decodetree.py'),
3710                         output: 'decode-@BASENAME@.c.inc',
3711                         arguments: ['@INPUT@', '@EXTRA_ARGS@', '-o', '@OUTPUT@'])
3712  subdir('libdecnumber')
3713  subdir('target')
3714endif
3715
3716subdir('audio')
3717subdir('io')
3718subdir('chardev')
3719subdir('fsdev')
3720subdir('dump')
3721
3722if have_block
3723  block_ss.add(files(
3724    'block.c',
3725    'blockjob.c',
3726    'job.c',
3727    'qemu-io-cmds.c',
3728  ))
3729  if config_host_data.get('CONFIG_REPLICATION')
3730    block_ss.add(files('replication.c'))
3731  endif
3732
3733  subdir('nbd')
3734  subdir('scsi')
3735  subdir('block')
3736
3737  blockdev_ss.add(files(
3738    'blockdev.c',
3739    'blockdev-nbd.c',
3740    'iothread.c',
3741    'job-qmp.c',
3742  ))
3743
3744  # os-posix.c contains POSIX-specific functions used by qemu-storage-daemon,
3745  # os-win32.c does not
3746  if host_os == 'windows'
3747    system_ss.add(files('os-win32.c'))
3748  else
3749    blockdev_ss.add(files('os-posix.c'))
3750  endif
3751endif
3752
3753common_ss.add(files('cpu-common.c'))
3754specific_ss.add(files('cpu-target.c'))
3755
3756subdir('system')
3757
3758# Work around a gcc bug/misfeature wherein constant propagation looks
3759# through an alias:
3760#   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99696
3761# to guess that a const variable is always zero.  Without lto, this is
3762# impossible, as the alias is restricted to page-vary-common.c.  Indeed,
3763# without lto, not even the alias is required -- we simply use different
3764# declarations in different compilation units.
3765pagevary = files('page-vary-common.c')
3766if get_option('b_lto')
3767  pagevary_flags = ['-fno-lto']
3768  if get_option('cfi')
3769    pagevary_flags += '-fno-sanitize=cfi-icall'
3770  endif
3771  pagevary = static_library('page-vary-common', sources: pagevary + genh,
3772                            c_args: pagevary_flags)
3773  pagevary = declare_dependency(link_with: pagevary)
3774endif
3775common_ss.add(pagevary)
3776specific_ss.add(files('page-target.c', 'page-vary-target.c'))
3777
3778subdir('backends')
3779subdir('disas')
3780subdir('migration')
3781subdir('monitor')
3782subdir('net')
3783subdir('replay')
3784subdir('semihosting')
3785subdir('stats')
3786subdir('tcg')
3787subdir('fpu')
3788subdir('accel')
3789subdir('plugins')
3790subdir('ebpf')
3791
3792if 'CONFIG_TCG' in config_all_accel
3793  subdir('contrib/plugins')
3794endif
3795
3796common_user_inc = []
3797
3798subdir('common-user')
3799subdir('bsd-user')
3800subdir('linux-user')
3801
3802# needed for fuzzing binaries
3803subdir('tests/qtest/libqos')
3804subdir('tests/qtest/fuzz')
3805
3806# accel modules
3807tcg_real_module_ss = ss.source_set()
3808tcg_real_module_ss.add_all(when: 'CONFIG_TCG_MODULAR', if_true: tcg_module_ss)
3809specific_ss.add_all(when: 'CONFIG_TCG_BUILTIN', if_true: tcg_module_ss)
3810target_modules += { 'accel' : { 'qtest': qtest_module_ss,
3811                                'tcg': tcg_real_module_ss }}
3812
3813##############################################
3814# Internal static_libraries and dependencies #
3815##############################################
3816
3817modinfo_collect = find_program('scripts/modinfo-collect.py')
3818modinfo_generate = find_program('scripts/modinfo-generate.py')
3819modinfo_files = []
3820
3821block_mods = []
3822system_mods = []
3823emulator_modules = []
3824foreach d, list : modules
3825  if not (d == 'block' ? have_block : have_system)
3826    continue
3827  endif
3828
3829  foreach m, module_ss : list
3830    if enable_modules
3831      module_ss.add(modulecommon)
3832      module_ss = module_ss.apply(config_all_devices, strict: false)
3833      sl = static_library(d + '-' + m, [genh, module_ss.sources()],
3834                          dependencies: module_ss.dependencies(), pic: true)
3835      if d == 'block'
3836        block_mods += sl
3837      else
3838        system_mods += sl
3839      endif
3840      emulator_modules += shared_module(sl.name(),
3841                    name_prefix: '',
3842                    objects: sl.extract_all_objects(recursive: false),
3843                    dependencies: module_ss.dependencies(),
3844                    install: true,
3845                    install_dir: qemu_moddir)
3846      if module_ss.sources() != []
3847        # FIXME: Should use sl.extract_all_objects(recursive: true) as
3848        # input. Sources can be used multiple times but objects are
3849        # unique when it comes to lookup in compile_commands.json.
3850        # Depnds on a mesion version with
3851        # https://github.com/mesonbuild/meson/pull/8900
3852        modinfo_files += custom_target(d + '-' + m + '.modinfo',
3853                                       output: d + '-' + m + '.modinfo',
3854                                       input: module_ss.sources() + genh,
3855                                       capture: true,
3856                                       command: [modinfo_collect, module_ss.sources()])
3857      endif
3858    else
3859      if d == 'block'
3860        block_ss.add_all(module_ss)
3861      else
3862        system_ss.add_all(module_ss)
3863      endif
3864    endif
3865  endforeach
3866endforeach
3867
3868foreach d, list : target_modules
3869  foreach m, module_ss : list
3870    if enable_modules
3871      module_ss.add(modulecommon)
3872      foreach target : target_dirs
3873        if target.endswith('-softmmu')
3874          config_target = config_target_mak[target]
3875          target_inc = [include_directories('target' / config_target['TARGET_BASE_ARCH'])]
3876          c_args = ['-DCOMPILING_PER_TARGET',
3877                    '-DCONFIG_TARGET="@0@-config-target.h"'.format(target),
3878                    '-DCONFIG_DEVICES="@0@-config-devices.h"'.format(target)]
3879          target_module_ss = module_ss.apply(config_target, strict: false)
3880          if target_module_ss.sources() != []
3881            module_name = d + '-' + m + '-' + config_target['TARGET_NAME']
3882            sl = static_library(module_name,
3883                                [genh, target_module_ss.sources()],
3884                                dependencies: target_module_ss.dependencies(),
3885                                include_directories: target_inc,
3886                                c_args: c_args,
3887                                pic: true)
3888            system_mods += sl
3889            emulator_modules += shared_module(sl.name(),
3890                    name_prefix: '',
3891                    objects: sl.extract_all_objects(recursive: false),
3892                    dependencies: target_module_ss.dependencies(),
3893                    install: true,
3894                    install_dir: qemu_moddir)
3895            # FIXME: Should use sl.extract_all_objects(recursive: true) too.
3896            modinfo_files += custom_target(module_name + '.modinfo',
3897                                           output: module_name + '.modinfo',
3898                                           input: target_module_ss.sources() + genh,
3899                                           capture: true,
3900                                           command: [modinfo_collect, '--target', target, target_module_ss.sources()])
3901          endif
3902        endif
3903      endforeach
3904    else
3905      specific_ss.add_all(module_ss)
3906    endif
3907  endforeach
3908endforeach
3909
3910if enable_modules
3911  foreach target : target_dirs
3912    if target.endswith('-softmmu')
3913      config_target = config_target_mak[target]
3914      config_devices_mak = target + '-config-devices.mak'
3915      modinfo_src = custom_target('modinfo-' + target + '.c',
3916                                  output: 'modinfo-' + target + '.c',
3917                                  input: modinfo_files,
3918                                  command: [modinfo_generate, '--devices', config_devices_mak, '@INPUT@'],
3919                                  capture: true)
3920
3921      modinfo_lib = static_library('modinfo-' + target + '.c', modinfo_src)
3922      modinfo_dep = declare_dependency(link_with: modinfo_lib)
3923
3924      arch = config_target['TARGET_NAME'] == 'sparc64' ? 'sparc64' : config_target['TARGET_BASE_ARCH']
3925      hw_arch[arch].add(modinfo_dep)
3926    endif
3927  endforeach
3928
3929  if emulator_modules.length() > 0
3930    alias_target('modules', emulator_modules)
3931  endif
3932endif
3933
3934nm = find_program('nm')
3935undefsym = find_program('scripts/undefsym.py')
3936block_syms = custom_target('block.syms', output: 'block.syms',
3937                             input: [libqemuutil, block_mods],
3938                             capture: true,
3939                             command: [undefsym, nm, '@INPUT@'])
3940qemu_syms = custom_target('qemu.syms', output: 'qemu.syms',
3941                             input: [libqemuutil, system_mods],
3942                             capture: true,
3943                             command: [undefsym, nm, '@INPUT@'])
3944
3945authz_ss = authz_ss.apply({})
3946libauthz = static_library('authz', authz_ss.sources() + genh,
3947                          dependencies: [authz_ss.dependencies()],
3948                          build_by_default: false)
3949
3950authz = declare_dependency(objects: libauthz.extract_all_objects(recursive: false),
3951                           dependencies: [authz_ss.dependencies(), qom])
3952
3953crypto_ss = crypto_ss.apply({})
3954libcrypto = static_library('crypto', crypto_ss.sources() + genh,
3955                           dependencies: [crypto_ss.dependencies()],
3956                           build_by_default: false)
3957
3958crypto = declare_dependency(objects: libcrypto.extract_all_objects(recursive: false),
3959                            dependencies: [crypto_ss.dependencies(), authz, qom])
3960
3961io_ss = io_ss.apply({})
3962libio = static_library('io', io_ss.sources() + genh,
3963                       dependencies: [io_ss.dependencies()],
3964                       link_with: libqemuutil,
3965                       build_by_default: false)
3966
3967io = declare_dependency(objects: libio.extract_all_objects(recursive: false),
3968                        dependencies: [io_ss.dependencies(), crypto, qom])
3969
3970libmigration = static_library('migration', sources: migration_files + genh,
3971                              build_by_default: false)
3972migration = declare_dependency(objects: libmigration.extract_all_objects(recursive: false),
3973                               dependencies: [qom, io])
3974system_ss.add(migration)
3975
3976block_ss = block_ss.apply({})
3977libblock = static_library('block', block_ss.sources() + genh,
3978                          dependencies: block_ss.dependencies(),
3979                          build_by_default: false)
3980
3981block = declare_dependency(objects: libblock.extract_all_objects(recursive: false),
3982                           dependencies: [block_ss.dependencies(), crypto, io])
3983
3984blockdev_ss = blockdev_ss.apply({})
3985libblockdev = static_library('blockdev', blockdev_ss.sources() + genh,
3986                             dependencies: blockdev_ss.dependencies(),
3987                             build_by_default: false)
3988
3989blockdev = declare_dependency(objects: libblockdev.extract_all_objects(recursive: false),
3990                              dependencies: [blockdev_ss.dependencies(), block, event_loop_base])
3991
3992qmp_ss = qmp_ss.apply({})
3993libqmp = static_library('qmp', qmp_ss.sources() + genh,
3994                        dependencies: qmp_ss.dependencies(),
3995                        build_by_default: false)
3996
3997qmp = declare_dependency(objects: libqmp.extract_all_objects(recursive: false),
3998                         dependencies: qmp_ss.dependencies())
3999
4000libchardev = static_library('chardev', chardev_ss.sources() + genh,
4001                            dependencies: chardev_ss.dependencies(),
4002                            build_by_default: false)
4003
4004chardev = declare_dependency(objects: libchardev.extract_all_objects(recursive: false),
4005                             dependencies: chardev_ss.dependencies())
4006
4007hwcore_ss = hwcore_ss.apply({})
4008libhwcore = static_library('hwcore', sources: hwcore_ss.sources() + genh,
4009                           build_by_default: false)
4010hwcore = declare_dependency(objects: libhwcore.extract_all_objects(recursive: false))
4011common_ss.add(hwcore)
4012
4013###########
4014# Targets #
4015###########
4016
4017system_ss.add(authz, blockdev, chardev, crypto, io, qmp)
4018common_ss.add(qom, qemuutil)
4019
4020common_ss.add_all(when: 'CONFIG_SYSTEM_ONLY', if_true: [system_ss])
4021common_ss.add_all(when: 'CONFIG_USER_ONLY', if_true: user_ss)
4022
4023# Note that this library is never used directly (only through extract_objects)
4024# and is not built by default; therefore, source files not used by the build
4025# configuration will be in build.ninja, but are never built by default.
4026common_all = static_library('common',
4027                            build_by_default: false,
4028                            sources: common_ss.all_sources() + genh,
4029                            include_directories: common_user_inc,
4030                            implicit_include_directories: false,
4031                            dependencies: common_ss.all_dependencies())
4032
4033if have_rust
4034  # We would like to use --generate-cstr, but it is only available
4035  # starting with bindgen 0.66.0.  The oldest supported versions
4036  # is 0.60.x (Debian 12 has 0.60.1) which introduces --allowlist-file.
4037  bindgen_args = [
4038    '--disable-header-comment',
4039    '--raw-line', '// @generated',
4040    '--ctypes-prefix', 'std::os::raw',
4041    '--generate-block',
4042    '--impl-debug',
4043    '--no-doc-comments',
4044    '--with-derive-default',
4045    '--no-layout-tests',
4046    '--no-prepend-enum-name',
4047    '--allowlist-file', meson.project_source_root() + '/include/.*',
4048    '--allowlist-file', meson.project_source_root() + '/.*',
4049    '--allowlist-file', meson.project_build_root() + '/.*'
4050    ]
4051  if not rustfmt.found()
4052    if bindgen.version().version_compare('<0.65.0')
4053      bindgen_args += ['--no-rustfmt-bindings']
4054    else
4055      bindgen_args += ['--formatter', 'none']
4056    endif
4057  endif
4058  if bindgen.version().version_compare('>=0.66.0')
4059    bindgen_args += ['--rust-target', '1.59']
4060  endif
4061  if bindgen.version().version_compare('<0.61.0')
4062    # default in 0.61+
4063    bindgen_args += ['--size_t-is-usize']
4064  else
4065    bindgen_args += ['--merge-extern-blocks']
4066  endif
4067  c_enums = [
4068    'DeviceCategory',
4069    'GpioPolarity',
4070    'MachineInitPhase',
4071    'MemoryDeviceInfoKind',
4072    'MigrationPolicy',
4073    'MigrationPriority',
4074    'QEMUChrEvent',
4075    'QEMUClockType',
4076    'device_endian',
4077    'module_init_type',
4078  ]
4079  foreach enum : c_enums
4080    bindgen_args += ['--rustified-enum', enum]
4081  endforeach
4082  c_bitfields = [
4083    'ClockEvent',
4084    'VMStateFlags',
4085  ]
4086  foreach enum : c_bitfields
4087    bindgen_args += ['--bitfield-enum', enum]
4088  endforeach
4089
4090  # TODO: Remove this comment when the clang/libclang mismatch issue is solved.
4091  #
4092  # Rust bindings generation with `bindgen` might fail in some cases where the
4093  # detected `libclang` does not match the expected `clang` version/target. In
4094  # this case you must pass the path to `clang` and `libclang` to your build
4095  # command invocation using the environment variables CLANG_PATH and
4096  # LIBCLANG_PATH
4097  bindings_rs = rust.bindgen(
4098    input: 'rust/wrapper.h',
4099    dependencies: common_ss.all_dependencies(),
4100    output: 'bindings.inc.rs',
4101    include_directories: include_directories('.', 'include'),
4102    bindgen_version: ['>=0.60.0'],
4103    args: bindgen_args,
4104    )
4105  subdir('rust')
4106endif
4107
4108
4109feature_to_c = find_program('scripts/feature_to_c.py')
4110rust_root_crate = find_program('scripts/rust/rust_root_crate.sh')
4111
4112if host_os == 'darwin'
4113  entitlement = find_program('scripts/entitlement.sh')
4114endif
4115
4116traceable = []
4117emulators = {}
4118foreach target : target_dirs
4119  config_target = config_target_mak[target]
4120  target_name = config_target['TARGET_NAME']
4121  target_base_arch = config_target['TARGET_BASE_ARCH']
4122  arch_srcs = [config_target_h[target]]
4123  arch_deps = []
4124  c_args = ['-DCOMPILING_PER_TARGET',
4125            '-DCONFIG_TARGET="@0@-config-target.h"'.format(target),
4126  ]
4127  link_args = emulator_link_args
4128
4129  target_inc = [include_directories('target' / config_target['TARGET_BASE_ARCH'])]
4130  if host_os == 'linux'
4131    target_inc += include_directories('linux-headers', is_system: true)
4132  endif
4133  if target.endswith('-softmmu')
4134    target_type='system'
4135    t = target_system_arch[target_base_arch].apply(config_target, strict: false)
4136    arch_srcs += t.sources()
4137    arch_deps += t.dependencies()
4138
4139    hw_dir = target_name == 'sparc64' ? 'sparc64' : target_base_arch
4140    if hw_arch.has_key(hw_dir)
4141      hw = hw_arch[hw_dir].apply(config_target, strict: false)
4142      arch_srcs += hw.sources()
4143      arch_deps += hw.dependencies()
4144    endif
4145
4146    c_args += ['-DCONFIG_DEVICES="@0@-config-devices.h"'.format(target)]
4147    arch_srcs += config_devices_h[target]
4148    link_args += ['@block.syms', '@qemu.syms']
4149  else
4150    abi = config_target['TARGET_ABI_DIR']
4151    target_type='user'
4152    target_inc += common_user_inc
4153    if target_base_arch in target_user_arch
4154      t = target_user_arch[target_base_arch].apply(config_target, strict: false)
4155      arch_srcs += t.sources()
4156      arch_deps += t.dependencies()
4157    endif
4158    if 'CONFIG_LINUX_USER' in config_target
4159      base_dir = 'linux-user'
4160    endif
4161    if 'CONFIG_BSD_USER' in config_target
4162      base_dir = 'bsd-user'
4163      target_inc += include_directories('bsd-user/' / host_os)
4164      target_inc += include_directories('bsd-user/host/' / host_arch)
4165      dir = base_dir / abi
4166      arch_srcs += files(dir / 'signal.c', dir / 'target_arch_cpu.c')
4167    endif
4168    target_inc += include_directories(
4169      base_dir,
4170      base_dir / abi,
4171    )
4172    if 'CONFIG_LINUX_USER' in config_target
4173      dir = base_dir / abi
4174      arch_srcs += files(dir / 'signal.c', dir / 'cpu_loop.c')
4175      if config_target.has_key('TARGET_SYSTBL_ABI')
4176        arch_srcs += \
4177          syscall_nr_generators[abi].process(base_dir / abi / config_target['TARGET_SYSTBL'],
4178                                             extra_args : config_target['TARGET_SYSTBL_ABI'])
4179      endif
4180    endif
4181  endif
4182
4183  if 'TARGET_XML_FILES' in config_target
4184    gdbstub_xml = custom_target(target + '-gdbstub-xml.c',
4185                                output: target + '-gdbstub-xml.c',
4186                                input: files(config_target['TARGET_XML_FILES'].split()),
4187                                command: [feature_to_c, '@INPUT@'],
4188                                capture: true)
4189    arch_srcs += gdbstub_xml
4190  endif
4191
4192  t = target_arch[target_base_arch].apply(config_target, strict: false)
4193  arch_srcs += t.sources()
4194  arch_deps += t.dependencies()
4195
4196  target_common = common_ss.apply(config_target, strict: false)
4197  objects = common_all.extract_objects(target_common.sources())
4198  arch_deps += target_common.dependencies()
4199
4200  target_specific = specific_ss.apply(config_target, strict: false)
4201  arch_srcs += target_specific.sources()
4202  arch_deps += target_specific.dependencies()
4203
4204  if have_rust and target_type == 'system'
4205    target_rust = rust_devices_ss.apply(config_target, strict: false)
4206    crates = []
4207    foreach dep : target_rust.dependencies()
4208      crates += dep.get_variable('crate')
4209    endforeach
4210    if crates.length() > 0
4211      rlib_rs = custom_target('rust_' + target.underscorify() + '.rs',
4212                              output: 'rust_' + target.underscorify() + '.rs',
4213                              command: [rust_root_crate, crates],
4214                              capture: true,
4215                              build_by_default: true,
4216                              build_always_stale: true)
4217      rlib = static_library('rust_' + target.underscorify(),
4218                            rlib_rs,
4219                            dependencies: target_rust.dependencies(),
4220                            override_options: ['rust_std=2021', 'build.rust_std=2021'],
4221                            rust_abi: 'c')
4222      arch_deps += declare_dependency(link_whole: [rlib])
4223    endif
4224  endif
4225
4226  # allow using headers from the dependencies but do not include the sources,
4227  # because this emulator only needs those in "objects".  For external
4228  # dependencies, the full dependency is included below in the executable.
4229  lib_deps = []
4230  foreach dep : arch_deps
4231    lib_deps += dep.partial_dependency(compile_args: true, includes: true)
4232  endforeach
4233
4234  lib = static_library('qemu-' + target,
4235                 sources: arch_srcs + genh,
4236                 dependencies: lib_deps,
4237                 objects: objects,
4238                 include_directories: target_inc,
4239                 c_args: c_args,
4240                 build_by_default: false)
4241
4242  if target.endswith('-softmmu')
4243    execs = [{
4244      'name': 'qemu-system-' + target_name,
4245      'win_subsystem': 'console',
4246      'sources': files('system/main.c'),
4247      'dependencies': [sdl]
4248    }]
4249    if host_os == 'windows' and (sdl.found() or gtk.found())
4250      execs += [{
4251        'name': 'qemu-system-' + target_name + 'w',
4252        'win_subsystem': 'windows',
4253        'sources': files('system/main.c'),
4254        'dependencies': [sdl]
4255      }]
4256    endif
4257    if get_option('fuzzing')
4258      specific_fuzz = specific_fuzz_ss.apply(config_target, strict: false)
4259      execs += [{
4260        'name': 'qemu-fuzz-' + target_name,
4261        'win_subsystem': 'console',
4262        'sources': specific_fuzz.sources(),
4263        'dependencies': specific_fuzz.dependencies(),
4264      }]
4265    endif
4266  else
4267    execs = [{
4268      'name': 'qemu-' + target_name,
4269      'win_subsystem': 'console',
4270      'sources': [],
4271      'dependencies': []
4272    }]
4273  endif
4274  foreach exe: execs
4275    exe_name = exe['name']
4276    if host_os == 'darwin'
4277      exe_name += '-unsigned'
4278    endif
4279
4280    emulator = executable(exe_name, exe['sources'],
4281               install: true,
4282               c_args: c_args,
4283               dependencies: arch_deps + exe['dependencies'],
4284               objects: lib.extract_all_objects(recursive: true),
4285               link_depends: [block_syms, qemu_syms],
4286               link_args: link_args,
4287               win_subsystem: exe['win_subsystem'])
4288
4289    if host_os == 'darwin'
4290      icon = 'pc-bios/qemu.rsrc'
4291      build_input = [emulator, files(icon)]
4292      install_input = [
4293        get_option('bindir') / exe_name,
4294        meson.current_source_dir() / icon
4295      ]
4296      if 'CONFIG_HVF' in config_target
4297        entitlements = 'accel/hvf/entitlements.plist'
4298        build_input += files(entitlements)
4299        install_input += meson.current_source_dir() / entitlements
4300      endif
4301
4302      emulators += {exe['name'] : custom_target(exe['name'],
4303                   input: build_input,
4304                   output: exe['name'],
4305                   command: [entitlement, '@OUTPUT@', '@INPUT@'])
4306      }
4307
4308      meson.add_install_script(entitlement, '--install',
4309                               get_option('bindir') / exe['name'],
4310                               install_input)
4311    else
4312      emulators += {exe['name']: emulator}
4313    endif
4314
4315    traceable += [{
4316      'exe': exe['name'],
4317      'probe-prefix': 'qemu.' + target_type + '.' + target_name,
4318    }]
4319
4320  endforeach
4321endforeach
4322
4323# Other build targets
4324
4325if get_option('plugins')
4326  install_headers('include/qemu/qemu-plugin.h')
4327  if host_os == 'windows'
4328    # On windows, we want to deliver the qemu_plugin_api.lib file in the qemu installer,
4329    # so that plugin authors can compile against it.
4330    install_data(win32_qemu_plugin_api_lib, install_dir: 'lib')
4331  endif
4332endif
4333
4334subdir('qga')
4335
4336# Don't build qemu-keymap if xkbcommon is not explicitly enabled
4337# when we don't build tools or system
4338if xkbcommon.found()
4339  # used for the update-keymaps target, so include rules even if !have_tools
4340  qemu_keymap = executable('qemu-keymap', files('qemu-keymap.c', 'ui/input-keymap.c') + genh,
4341                           dependencies: [qemuutil, xkbcommon], install: have_tools)
4342endif
4343
4344if have_tools
4345  qemu_img = executable('qemu-img', [files('qemu-img.c'), hxdep],
4346             link_args: '@block.syms', link_depends: block_syms,
4347             dependencies: [authz, block, crypto, io, qom, qemuutil], install: true)
4348  qemu_io = executable('qemu-io', files('qemu-io.c'),
4349             link_args: '@block.syms', link_depends: block_syms,
4350             dependencies: [block, qemuutil], install: true)
4351  qemu_nbd = executable('qemu-nbd', files('qemu-nbd.c'),
4352               link_args: '@block.syms', link_depends: block_syms,
4353               dependencies: [blockdev, qemuutil, selinux],
4354               install: true)
4355
4356  subdir('storage-daemon')
4357
4358  foreach exe: [ 'qemu-img', 'qemu-io', 'qemu-nbd', 'qemu-storage-daemon']
4359    traceable += [{
4360      'exe': exe,
4361      'probe-prefix': 'qemu.' + exe.substring(5).replace('-', '_')
4362    }]
4363  endforeach
4364
4365  subdir('contrib/elf2dmp')
4366
4367  executable('qemu-edid', files('qemu-edid.c', 'hw/display/edid-generate.c'),
4368             dependencies: [qemuutil, rt],
4369             install: true)
4370
4371  if have_vhost_user
4372    subdir('contrib/vhost-user-blk')
4373    subdir('contrib/vhost-user-gpu')
4374    subdir('contrib/vhost-user-input')
4375    subdir('contrib/vhost-user-scsi')
4376  endif
4377
4378  if host_os == 'linux'
4379    executable('qemu-bridge-helper', files('qemu-bridge-helper.c'),
4380               dependencies: [qemuutil, libcap_ng],
4381               install: true,
4382               install_dir: get_option('libexecdir'))
4383
4384    executable('qemu-pr-helper', files('scsi/qemu-pr-helper.c', 'scsi/utils.c'),
4385               dependencies: [authz, crypto, io, qom, qemuutil,
4386                              libcap_ng, mpathpersist],
4387               install: true)
4388
4389    if cpu in ['x86', 'x86_64']
4390      executable('qemu-vmsr-helper', files('tools/i386/qemu-vmsr-helper.c'),
4391               dependencies: [authz, crypto, io, qom, qemuutil,
4392                              libcap_ng, mpathpersist],
4393               install: true)
4394    endif
4395  endif
4396
4397  if have_ivshmem
4398    subdir('contrib/ivshmem-client')
4399    subdir('contrib/ivshmem-server')
4400  endif
4401endif
4402
4403if stap.found()
4404  foreach t: traceable
4405    foreach stp: [
4406      {'ext': '.stp-build', 'fmt': 'stap', 'bin': meson.current_build_dir() / t['exe'], 'install': false},
4407      {'ext': '.stp', 'fmt': 'stap', 'bin': get_option('prefix') / get_option('bindir') / t['exe'], 'install': true},
4408      {'ext': '-simpletrace.stp', 'fmt': 'simpletrace-stap', 'bin': '', 'install': true},
4409      {'ext': '-log.stp', 'fmt': 'log-stap', 'bin': '', 'install': true},
4410    ]
4411      cmd = [
4412        tracetool, '--group=all', '--format=' + stp['fmt'],
4413        '--binary=' + stp['bin'],
4414        '--probe-prefix=' + t['probe-prefix'],
4415        '@INPUT@', '@OUTPUT@'
4416      ]
4417
4418      custom_target(t['exe'] + stp['ext'],
4419                    input: trace_events_all,
4420                    output: t['exe'] + stp['ext'],
4421                    install: stp['install'],
4422                    install_dir: get_option('datadir') / 'systemtap/tapset',
4423                    command: cmd,
4424                    depend_files: tracetool_depends)
4425    endforeach
4426  endforeach
4427endif
4428
4429subdir('scripts')
4430subdir('tools')
4431subdir('pc-bios')
4432subdir('docs')
4433subdir('tests')
4434if gtk.found()
4435  subdir('po')
4436endif
4437
4438if host_machine.system() == 'windows'
4439  nsis_cmd = [
4440    find_program('scripts/nsis.py'),
4441    '@OUTPUT@',
4442    get_option('prefix'),
4443    meson.current_source_dir(),
4444    glib_pc.get_variable('bindir'),
4445    host_machine.cpu(),
4446    '--',
4447    '-DDISPLAYVERSION=' + meson.project_version(),
4448  ]
4449  if build_docs
4450    nsis_cmd += '-DCONFIG_DOCUMENTATION=y'
4451  endif
4452  if gtk.found()
4453    nsis_cmd += '-DCONFIG_GTK=y'
4454  endif
4455
4456  nsis = custom_target('nsis',
4457                       output: 'qemu-setup-' + meson.project_version() + '.exe',
4458                       input: files('qemu.nsi'),
4459                       build_always_stale: true,
4460                       command: nsis_cmd + ['@INPUT@'])
4461  alias_target('installer', nsis)
4462endif
4463
4464#########################
4465# Configuration summary #
4466#########################
4467
4468# Build environment
4469summary_info = {}
4470summary_info += {'Build directory':   meson.current_build_dir()}
4471summary_info += {'Source path':       meson.current_source_dir()}
4472summary_info += {'Download dependencies': get_option('wrap_mode') != 'nodownload'}
4473summary(summary_info, bool_yn: true, section: 'Build environment')
4474
4475# Directories
4476summary_info += {'Install prefix':    get_option('prefix')}
4477summary_info += {'BIOS directory':    qemu_datadir}
4478pathsep = host_os == 'windows' ? ';' : ':'
4479summary_info += {'firmware path':     pathsep.join(get_option('qemu_firmwarepath'))}
4480summary_info += {'binary directory':  get_option('prefix') / get_option('bindir')}
4481summary_info += {'library directory': get_option('prefix') / get_option('libdir')}
4482summary_info += {'module directory':  qemu_moddir}
4483summary_info += {'libexec directory': get_option('prefix') / get_option('libexecdir')}
4484summary_info += {'include directory': get_option('prefix') / get_option('includedir')}
4485summary_info += {'config directory':  get_option('prefix') / get_option('sysconfdir')}
4486if host_os != 'windows'
4487  summary_info += {'local state directory': get_option('prefix') / get_option('localstatedir')}
4488  summary_info += {'Manual directory':      get_option('prefix') / get_option('mandir')}
4489else
4490  summary_info += {'local state directory': 'queried at runtime'}
4491endif
4492summary_info += {'Doc directory':     get_option('prefix') / get_option('docdir')}
4493summary(summary_info, bool_yn: true, section: 'Directories')
4494
4495# Host binaries
4496summary_info = {}
4497summary_info += {'python':            '@0@ (version: @1@)'.format(python.full_path(), python.language_version())}
4498summary_info += {'sphinx-build':      sphinx_build}
4499
4500# FIXME: the [binaries] section of machine files, which can be probed
4501# with find_program(), would be great for passing gdb and genisoimage
4502# paths from configure to Meson.  However, there seems to be no way to
4503# hide a program (for example if gdb is too old).
4504if config_host.has_key('GDB')
4505  summary_info += {'gdb':             config_host['GDB']}
4506endif
4507summary_info += {'iasl':              iasl}
4508summary_info += {'genisoimage':       config_host['GENISOIMAGE']}
4509if host_os == 'windows' and have_ga
4510  summary_info += {'wixl':            wixl}
4511endif
4512if slirp.found() and have_system
4513  summary_info += {'smbd':            have_slirp_smbd ? smbd_path : false}
4514endif
4515summary(summary_info, bool_yn: true, section: 'Host binaries')
4516
4517# Configurable features
4518summary_info = {}
4519summary_info += {'Documentation':     build_docs}
4520summary_info += {'system-mode emulation': have_system}
4521summary_info += {'user-mode emulation': have_user}
4522summary_info += {'block layer':       have_block}
4523summary_info += {'Install blobs':     get_option('install_blobs')}
4524summary_info += {'module support':    enable_modules}
4525if enable_modules
4526  summary_info += {'alternative module path': get_option('module_upgrades')}
4527endif
4528summary_info += {'fuzzing support':   get_option('fuzzing')}
4529if have_system
4530  summary_info += {'Audio drivers':     ' '.join(audio_drivers_selected)}
4531endif
4532summary_info += {'Trace backends':    ','.join(get_option('trace_backends'))}
4533if 'simple' in get_option('trace_backends')
4534  summary_info += {'Trace output file': get_option('trace_file') + '-<pid>'}
4535endif
4536summary_info += {'D-Bus display':     dbus_display}
4537summary_info += {'QOM debugging':     get_option('qom_cast_debug')}
4538summary_info += {'Relocatable install': get_option('relocatable')}
4539summary_info += {'vhost-kernel support': have_vhost_kernel}
4540summary_info += {'vhost-net support': have_vhost_net}
4541summary_info += {'vhost-user support': have_vhost_user}
4542summary_info += {'vhost-user-crypto support': have_vhost_user_crypto}
4543summary_info += {'vhost-user-blk server support': have_vhost_user_blk_server}
4544summary_info += {'vhost-vdpa support': have_vhost_vdpa}
4545summary_info += {'build guest agent': have_ga}
4546summary(summary_info, bool_yn: true, section: 'Configurable features')
4547
4548# Compilation information
4549summary_info = {}
4550summary_info += {'host CPU':          cpu}
4551summary_info += {'host endianness':   build_machine.endian()}
4552summary_info += {'C compiler':        ' '.join(meson.get_compiler('c').cmd_array())}
4553summary_info += {'Host C compiler':   ' '.join(meson.get_compiler('c', native: true).cmd_array())}
4554if 'cpp' in all_languages
4555  summary_info += {'C++ compiler':    ' '.join(meson.get_compiler('cpp').cmd_array())}
4556else
4557  summary_info += {'C++ compiler':      false}
4558endif
4559if 'objc' in all_languages
4560  summary_info += {'Objective-C compiler': ' '.join(meson.get_compiler('objc').cmd_array())}
4561else
4562  summary_info += {'Objective-C compiler': false}
4563endif
4564summary_info += {'Rust support':      have_rust}
4565if have_rust
4566  summary_info += {'Rust target':     config_host['RUST_TARGET_TRIPLE']}
4567  summary_info += {'rustc':           ' '.join(rustc.cmd_array())}
4568  summary_info += {'rustc version':   rustc.version()}
4569  summary_info += {'bindgen':         bindgen.full_path()}
4570  summary_info += {'bindgen version': bindgen.version()}
4571endif
4572option_cflags = (get_option('debug') ? ['-g'] : [])
4573if get_option('optimization') != 'plain'
4574  option_cflags += ['-O' + get_option('optimization')]
4575endif
4576summary_info += {'CFLAGS':            ' '.join(get_option('c_args') + option_cflags)}
4577if 'cpp' in all_languages
4578  summary_info += {'CXXFLAGS':        ' '.join(get_option('cpp_args') + option_cflags)}
4579endif
4580if 'objc' in all_languages
4581  summary_info += {'OBJCFLAGS':       ' '.join(get_option('objc_args') + option_cflags)}
4582endif
4583link_args = get_option('c_link_args')
4584if link_args.length() > 0
4585  summary_info += {'LDFLAGS':         ' '.join(link_args)}
4586endif
4587summary_info += {'QEMU_CFLAGS':       ' '.join(qemu_common_flags + qemu_cflags)}
4588if 'cpp' in all_languages
4589  summary_info += {'QEMU_CXXFLAGS':     ' '.join(qemu_common_flags + qemu_cxxflags)}
4590endif
4591if 'objc' in all_languages
4592  summary_info += {'QEMU_OBJCFLAGS':    ' '.join(qemu_common_flags)}
4593endif
4594summary_info += {'QEMU_LDFLAGS':      ' '.join(qemu_ldflags)}
4595summary_info += {'link-time optimization (LTO)': get_option('b_lto')}
4596summary_info += {'PIE':               get_option('b_pie')}
4597summary_info += {'static build':      get_option('prefer_static')}
4598summary_info += {'malloc trim support': has_malloc_trim}
4599summary_info += {'membarrier':        have_membarrier}
4600summary_info += {'debug graph lock':  get_option('debug_graph_lock')}
4601summary_info += {'debug stack usage': get_option('debug_stack_usage')}
4602summary_info += {'mutex debugging':   get_option('debug_mutex')}
4603summary_info += {'memory allocator':  get_option('malloc')}
4604summary_info += {'avx2 optimization': config_host_data.get('CONFIG_AVX2_OPT')}
4605summary_info += {'avx512bw optimization': config_host_data.get('CONFIG_AVX512BW_OPT')}
4606summary_info += {'gcov':              get_option('b_coverage')}
4607summary_info += {'thread sanitizer':  get_option('tsan')}
4608summary_info += {'CFI support':       get_option('cfi')}
4609if get_option('cfi')
4610  summary_info += {'CFI debug support': get_option('cfi_debug')}
4611endif
4612summary_info += {'strip binaries':    get_option('strip')}
4613summary_info += {'sparse':            sparse}
4614summary_info += {'mingw32 support':   host_os == 'windows'}
4615summary(summary_info, bool_yn: true, section: 'Compilation')
4616
4617# snarf the cross-compilation information for tests
4618summary_info = {}
4619have_cross = false
4620foreach target: target_dirs
4621  tcg_mak = meson.current_build_dir() / 'tests/tcg' / target / 'config-target.mak'
4622  if fs.exists(tcg_mak)
4623    config_cross_tcg = keyval.load(tcg_mak)
4624    if 'CC' in config_cross_tcg
4625      summary_info += {config_cross_tcg['TARGET_NAME']: config_cross_tcg['CC']}
4626      have_cross = true
4627    endif
4628  endif
4629endforeach
4630if have_cross
4631  summary(summary_info, bool_yn: true, section: 'Cross compilers')
4632endif
4633
4634# Targets and accelerators
4635summary_info = {}
4636if have_system
4637  summary_info += {'KVM support':       config_all_accel.has_key('CONFIG_KVM')}
4638  summary_info += {'HVF support':       config_all_accel.has_key('CONFIG_HVF')}
4639  summary_info += {'WHPX support':      config_all_accel.has_key('CONFIG_WHPX')}
4640  summary_info += {'NVMM support':      config_all_accel.has_key('CONFIG_NVMM')}
4641  summary_info += {'Xen support':       xen.found()}
4642  if xen.found()
4643    summary_info += {'xen ctrl version':  xen.version()}
4644  endif
4645  summary_info += {'Xen emulation':     config_all_devices.has_key('CONFIG_XEN_EMU')}
4646endif
4647summary_info += {'TCG support':       config_all_accel.has_key('CONFIG_TCG')}
4648if config_all_accel.has_key('CONFIG_TCG')
4649  if get_option('tcg_interpreter')
4650    summary_info += {'TCG backend':   'TCI (TCG with bytecode interpreter, slow)'}
4651  else
4652    summary_info += {'TCG backend':   'native (@0@)'.format(cpu)}
4653  endif
4654  summary_info += {'TCG plugins':       get_option('plugins')}
4655  summary_info += {'TCG debug enabled': get_option('debug_tcg')}
4656  if have_linux_user or have_bsd_user
4657    summary_info += {'syscall buffer debugging support': get_option('debug_remap')}
4658  endif
4659endif
4660summary_info += {'target list':       ' '.join(target_dirs)}
4661if have_system
4662  summary_info += {'default devices':   get_option('default_devices')}
4663  summary_info += {'out of process emulation': multiprocess_allowed}
4664  summary_info += {'vfio-user server': vfio_user_server_allowed}
4665endif
4666summary(summary_info, bool_yn: true, section: 'Targets and accelerators')
4667
4668# Block layer
4669summary_info = {}
4670summary_info += {'coroutine backend': coroutine_backend}
4671summary_info += {'coroutine pool':    have_coroutine_pool}
4672if have_block
4673  summary_info += {'Block whitelist (rw)': get_option('block_drv_rw_whitelist')}
4674  summary_info += {'Block whitelist (ro)': get_option('block_drv_ro_whitelist')}
4675  summary_info += {'Use block whitelist in tools': get_option('block_drv_whitelist_in_tools')}
4676  summary_info += {'VirtFS (9P) support':    have_virtfs}
4677  summary_info += {'replication support': config_host_data.get('CONFIG_REPLICATION')}
4678  summary_info += {'bochs support':     get_option('bochs').allowed()}
4679  summary_info += {'cloop support':     get_option('cloop').allowed()}
4680  summary_info += {'dmg support':       get_option('dmg').allowed()}
4681  summary_info += {'qcow v1 support':   get_option('qcow1').allowed()}
4682  summary_info += {'vdi support':       get_option('vdi').allowed()}
4683  summary_info += {'vhdx support':      get_option('vhdx').allowed()}
4684  summary_info += {'vmdk support':      get_option('vmdk').allowed()}
4685  summary_info += {'vpc support':       get_option('vpc').allowed()}
4686  summary_info += {'vvfat support':     get_option('vvfat').allowed()}
4687  summary_info += {'qed support':       get_option('qed').allowed()}
4688  summary_info += {'parallels support': get_option('parallels').allowed()}
4689  summary_info += {'FUSE exports':      fuse}
4690  summary_info += {'VDUSE block exports': have_vduse_blk_export}
4691endif
4692summary(summary_info, bool_yn: true, section: 'Block layer support')
4693
4694# Crypto
4695summary_info = {}
4696summary_info += {'TLS priority':      get_option('tls_priority')}
4697summary_info += {'GNUTLS support':    gnutls}
4698if gnutls.found()
4699  summary_info += {'  GNUTLS crypto':   gnutls_crypto.found()}
4700endif
4701summary_info += {'libgcrypt':         gcrypt}
4702summary_info += {'nettle':            nettle}
4703if nettle.found()
4704   summary_info += {'  XTS':             xts != 'private'}
4705endif
4706summary_info += {'SM4 ALG support':   crypto_sm4}
4707summary_info += {'SM3 ALG support':   crypto_sm3}
4708summary_info += {'AF_ALG support':    have_afalg}
4709summary_info += {'rng-none':          get_option('rng_none')}
4710summary_info += {'Linux keyring':     have_keyring}
4711summary_info += {'Linux keyutils':    keyutils}
4712summary(summary_info, bool_yn: true, section: 'Crypto')
4713
4714# UI
4715summary_info = {}
4716if host_os == 'darwin'
4717  summary_info += {'Cocoa support':           cocoa}
4718endif
4719summary_info += {'SDL support':       sdl}
4720summary_info += {'SDL image support': sdl_image}
4721summary_info += {'GTK support':       gtk}
4722summary_info += {'pixman':            pixman}
4723summary_info += {'VTE support':       vte}
4724summary_info += {'PNG support':       png}
4725summary_info += {'VNC support':       vnc}
4726if vnc.found()
4727  summary_info += {'VNC SASL support':  sasl}
4728  summary_info += {'VNC JPEG support':  jpeg}
4729endif
4730summary_info += {'spice protocol support': spice_protocol}
4731if spice_protocol.found()
4732  summary_info += {'  spice server support': spice}
4733endif
4734summary_info += {'curses support':    curses}
4735summary_info += {'brlapi support':    brlapi}
4736summary(summary_info, bool_yn: true, section: 'User interface')
4737
4738# Graphics backends
4739summary_info = {}
4740summary_info += {'VirGL support':     virgl}
4741summary_info += {'Rutabaga support':  rutabaga}
4742summary(summary_info, bool_yn: true, section: 'Graphics backends')
4743
4744# Audio backends
4745summary_info = {}
4746if host_os not in ['darwin', 'haiku', 'windows']
4747  summary_info += {'OSS support':     oss}
4748  summary_info += {'sndio support':   sndio}
4749elif host_os == 'darwin'
4750  summary_info += {'CoreAudio support': coreaudio}
4751elif host_os == 'windows'
4752  summary_info += {'DirectSound support': dsound}
4753endif
4754if host_os == 'linux'
4755  summary_info += {'ALSA support':    alsa}
4756  summary_info += {'PulseAudio support': pulse}
4757endif
4758summary_info += {'PipeWire support':  pipewire}
4759summary_info += {'JACK support':      jack}
4760summary(summary_info, bool_yn: true, section: 'Audio backends')
4761
4762# Network backends
4763summary_info = {}
4764if host_os == 'darwin'
4765  summary_info += {'vmnet.framework support': vmnet}
4766endif
4767summary_info += {'AF_XDP support':    libxdp}
4768summary_info += {'slirp support':     slirp}
4769summary_info += {'vde support':       vde}
4770summary_info += {'netmap support':    have_netmap}
4771summary_info += {'l2tpv3 support':    have_l2tpv3}
4772summary(summary_info, bool_yn: true, section: 'Network backends')
4773
4774# Libraries
4775summary_info = {}
4776summary_info += {'libtasn1':          tasn1}
4777summary_info += {'PAM':               pam}
4778summary_info += {'iconv support':     iconv}
4779summary_info += {'blkio support':     blkio}
4780summary_info += {'curl support':      curl}
4781summary_info += {'Multipath support': mpathpersist}
4782summary_info += {'Linux AIO support': libaio}
4783summary_info += {'Linux io_uring support': linux_io_uring}
4784summary_info += {'ATTR/XATTR support': libattr}
4785summary_info += {'RDMA support':      rdma}
4786summary_info += {'fdt support':       fdt_opt == 'internal' ? 'internal' : fdt}
4787summary_info += {'libcap-ng support': libcap_ng}
4788summary_info += {'bpf support':       libbpf}
4789summary_info += {'rbd support':       rbd}
4790summary_info += {'smartcard support': cacard}
4791summary_info += {'U2F support':       u2f}
4792summary_info += {'libusb':            libusb}
4793summary_info += {'usb net redir':     usbredir}
4794summary_info += {'OpenGL support (epoxy)': opengl}
4795summary_info += {'GBM':               gbm}
4796summary_info += {'libiscsi support':  libiscsi}
4797summary_info += {'libnfs support':    libnfs}
4798if host_os == 'windows'
4799  if have_ga
4800    summary_info += {'QGA VSS support':   have_qga_vss}
4801  endif
4802endif
4803summary_info += {'seccomp support':   seccomp}
4804summary_info += {'GlusterFS support': glusterfs}
4805summary_info += {'hv-balloon support': hv_balloon}
4806summary_info += {'TPM support':       have_tpm}
4807summary_info += {'libssh support':    libssh}
4808summary_info += {'lzo support':       lzo}
4809summary_info += {'snappy support':    snappy}
4810summary_info += {'bzip2 support':     libbzip2}
4811summary_info += {'lzfse support':     liblzfse}
4812summary_info += {'zstd support':      zstd}
4813summary_info += {'Query Processing Library support': qpl}
4814summary_info += {'UADK Library support': uadk}
4815summary_info += {'qatzip support':    qatzip}
4816summary_info += {'NUMA host support': numa}
4817summary_info += {'capstone':          capstone}
4818summary_info += {'libpmem support':   libpmem}
4819summary_info += {'libdaxctl support': libdaxctl}
4820summary_info += {'libcbor support':   libcbor}
4821summary_info += {'libudev':           libudev}
4822# Dummy dependency, keep .found()
4823summary_info += {'FUSE lseek':        fuse_lseek.found()}
4824summary_info += {'selinux':           selinux}
4825summary_info += {'libdw':             libdw}
4826if host_os == 'freebsd'
4827  summary_info += {'libinotify-kqueue': inotify}
4828endif
4829summary(summary_info, bool_yn: true, section: 'Dependencies')
4830
4831if host_arch == 'unknown'
4832  message()
4833  warning('UNSUPPORTED HOST CPU')
4834  message()
4835  message('Support for CPU host architecture ' + cpu + ' is not currently')
4836  message('maintained. The QEMU project does not guarantee that QEMU will')
4837  message('compile or work on this host CPU. You can help by volunteering')
4838  message('to maintain it and providing a build host for our continuous')
4839  message('integration setup.')
4840  if get_option('tcg').allowed() and target_dirs.length() > 0
4841    message()
4842    message('configure has succeeded and you can continue to build, but')
4843    message('QEMU will use a slow interpreter to emulate the target CPU.')
4844  endif
4845elif host_arch == 'mips'
4846  message()
4847  warning('DEPRECATED HOST CPU')
4848  message()
4849  message('Support for CPU host architecture ' + cpu + ' is going to be')
4850  message('dropped as soon as the QEMU project stops supporting Debian 12')
4851  message('("Bookworm"). Going forward, the QEMU project will not guarantee')
4852  message('that QEMU will compile or work on this host CPU.')
4853endif
4854
4855if not supported_oses.contains(host_os)
4856  message()
4857  warning('UNSUPPORTED HOST OS')
4858  message()
4859  message('Support for host OS ' + host_os + 'is not currently maintained.')
4860  message('configure has succeeded and you can continue to build, but')
4861  message('the QEMU project does not guarantee that QEMU will compile or')
4862  message('work on this operating system. You can help by volunteering')
4863  message('to maintain it and providing a build host for our continuous')
4864  message('integration setup. This will ensure that future versions of QEMU')
4865  message('will keep working on ' + host_os + '.')
4866endif
4867
4868if host_arch == 'unknown' or not supported_oses.contains(host_os)
4869  message()
4870  message('If you want to help supporting QEMU on this platform, please')
4871  message('contact the developers at qemu-devel@nongnu.org.')
4872endif
4873
4874actually_reloc = get_option('relocatable')
4875# check if get_relocated_path() is actually able to relocate paths
4876if get_option('relocatable') and \
4877  not (get_option('prefix') / get_option('bindir')).startswith(get_option('prefix') / '')
4878  message()
4879  warning('bindir not included within prefix, the installation will not be relocatable.')
4880  actually_reloc = false
4881endif
4882if not actually_reloc and (host_os == 'windows' or get_option('relocatable'))
4883  if host_os == 'windows'
4884    message()
4885    warning('Windows installs should usually be relocatable.')
4886  endif
4887  message()
4888  message('QEMU will have to be installed under ' + get_option('prefix') + '.')
4889  message('Use --disable-relocatable to remove this warning.')
4890endif
4891