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