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