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