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