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