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