xref: /qemu/meson.build (revision eb64a0c6ae492f8ef37f31c9d4994bfc69f02e3d)
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  # We would like to use --generate-cstr, but it is only available
4204  # starting with bindgen 0.66.0.  The oldest supported versions
4205  # is 0.60.x (Debian 12 has 0.60.1) which introduces --allowlist-file.
4206  bindgen_args = [
4207    '--disable-header-comment',
4208    '--raw-line', '// @generated',
4209    '--ctypes-prefix', 'std::os::raw',
4210    '--generate-block',
4211    '--impl-debug',
4212    '--no-doc-comments',
4213    '--with-derive-default',
4214    '--no-layout-tests',
4215    '--no-prepend-enum-name',
4216    '--allowlist-file', meson.project_source_root() + '/include/.*',
4217    '--allowlist-file', meson.project_source_root() + '/.*',
4218    '--allowlist-file', meson.project_build_root() + '/.*'
4219    ]
4220  if not rustfmt.found()
4221    if bindgen.version().version_compare('<0.65.0')
4222      bindgen_args += ['--no-rustfmt-bindings']
4223    else
4224      bindgen_args += ['--formatter', 'none']
4225    endif
4226  endif
4227  if bindgen.version().version_compare('>=0.66.0')
4228    bindgen_args += ['--rust-target', '1.59']
4229  endif
4230  if bindgen.version().version_compare('<0.61.0')
4231    # default in 0.61+
4232    bindgen_args += ['--size_t-is-usize']
4233  else
4234    bindgen_args += ['--merge-extern-blocks']
4235  endif
4236  c_enums = [
4237    'DeviceCategory',
4238    'GpioPolarity',
4239    'MachineInitPhase',
4240    'MemoryDeviceInfoKind',
4241    'MigrationPolicy',
4242    'MigrationPriority',
4243    'QEMUChrEvent',
4244    'QEMUClockType',
4245    'ResetType',
4246    'device_endian',
4247    'module_init_type',
4248  ]
4249  foreach enum : c_enums
4250    bindgen_args += ['--rustified-enum', enum]
4251  endforeach
4252  c_bitfields = [
4253    'ClockEvent',
4254    'VMStateFlags',
4255  ]
4256  foreach enum : c_bitfields
4257    bindgen_args += ['--bitfield-enum', enum]
4258  endforeach
4259
4260  # TODO: Remove this comment when the clang/libclang mismatch issue is solved.
4261  #
4262  # Rust bindings generation with `bindgen` might fail in some cases where the
4263  # detected `libclang` does not match the expected `clang` version/target. In
4264  # this case you must pass the path to `clang` and `libclang` to your build
4265  # command invocation using the environment variables CLANG_PATH and
4266  # LIBCLANG_PATH
4267  bindings_rs = rust.bindgen(
4268    input: 'rust/wrapper.h',
4269    dependencies: common_ss.all_dependencies(),
4270    output: 'bindings.inc.rs',
4271    include_directories: include_directories('.', 'include'),
4272    bindgen_version: ['>=0.60.0'],
4273    args: bindgen_args,
4274    )
4275  subdir('rust')
4276endif
4277
4278
4279feature_to_c = find_program('scripts/feature_to_c.py')
4280rust_root_crate = find_program('scripts/rust/rust_root_crate.sh')
4281
4282if host_os == 'darwin'
4283  entitlement = find_program('scripts/entitlement.sh')
4284endif
4285
4286traceable = []
4287emulators = {}
4288foreach target : target_dirs
4289  config_target = config_target_mak[target]
4290  target_name = config_target['TARGET_NAME']
4291  target_base_arch = config_target['TARGET_BASE_ARCH']
4292  arch_srcs = [config_target_h[target]]
4293  arch_deps = []
4294  c_args = ['-DCOMPILING_PER_TARGET',
4295            '-DCONFIG_TARGET="@0@-config-target.h"'.format(target),
4296  ]
4297  link_args = emulator_link_args
4298
4299  target_inc = [include_directories('target' / config_target['TARGET_BASE_ARCH'])]
4300  if host_os == 'linux'
4301    target_inc += include_directories('linux-headers', is_system: true)
4302  endif
4303  if target.endswith('-softmmu')
4304    target_type='system'
4305    t = target_system_arch[target_base_arch].apply(config_target, strict: false)
4306    arch_srcs += t.sources()
4307    arch_deps += t.dependencies()
4308
4309    hw_dir = target_name == 'sparc64' ? 'sparc64' : target_base_arch
4310    if hw_arch.has_key(hw_dir)
4311      hw = hw_arch[hw_dir].apply(config_target, strict: false)
4312      arch_srcs += hw.sources()
4313      arch_deps += hw.dependencies()
4314    endif
4315
4316    c_args += ['-DCONFIG_DEVICES="@0@-config-devices.h"'.format(target)]
4317    arch_srcs += config_devices_h[target]
4318    link_args += ['@block.syms', '@qemu.syms']
4319  else
4320    abi = config_target['TARGET_ABI_DIR']
4321    target_type='user'
4322    target_inc += common_user_inc
4323    if target_base_arch in target_user_arch
4324      t = target_user_arch[target_base_arch].apply(config_target, strict: false)
4325      arch_srcs += t.sources()
4326      arch_deps += t.dependencies()
4327    endif
4328    if 'CONFIG_LINUX_USER' in config_target
4329      base_dir = 'linux-user'
4330    endif
4331    if 'CONFIG_BSD_USER' in config_target
4332      base_dir = 'bsd-user'
4333      target_inc += include_directories('bsd-user/' / host_os)
4334      target_inc += include_directories('bsd-user/host/' / host_arch)
4335      dir = base_dir / abi
4336      arch_srcs += files(dir / 'signal.c', dir / 'target_arch_cpu.c')
4337    endif
4338    target_inc += include_directories(
4339      base_dir,
4340      base_dir / abi,
4341    )
4342    if 'CONFIG_LINUX_USER' in config_target
4343      dir = base_dir / abi
4344      arch_srcs += files(dir / 'signal.c', dir / 'cpu_loop.c')
4345      if config_target.has_key('TARGET_SYSTBL_ABI')
4346        arch_srcs += \
4347          syscall_nr_generators[abi].process(base_dir / abi / config_target['TARGET_SYSTBL'],
4348                                             extra_args : config_target['TARGET_SYSTBL_ABI'])
4349      endif
4350    endif
4351  endif
4352
4353  if 'TARGET_XML_FILES' in config_target
4354    gdbstub_xml = custom_target(target + '-gdbstub-xml.c',
4355                                output: target + '-gdbstub-xml.c',
4356                                input: files(config_target['TARGET_XML_FILES'].split()),
4357                                command: [feature_to_c, '@INPUT@'],
4358                                capture: true)
4359    arch_srcs += gdbstub_xml
4360  endif
4361
4362  t = target_arch[target_base_arch].apply(config_target, strict: false)
4363  arch_srcs += t.sources()
4364  arch_deps += t.dependencies()
4365
4366  target_common = common_ss.apply(config_target, strict: false)
4367  objects = [common_all.extract_objects(target_common.sources())]
4368  arch_deps += target_common.dependencies()
4369  if target_base_arch in target_common_arch_libs
4370    src = target_common_arch[target_base_arch].apply(config_target, strict: false)
4371    lib = target_common_arch_libs[target_base_arch]
4372    objects += lib.extract_objects(src.sources())
4373    arch_deps += src.dependencies()
4374  endif
4375  if target_type == 'system'
4376    src = system_ss.apply(config_target, strict: false)
4377    objects += libsystem.extract_objects(src.sources())
4378    arch_deps += src.dependencies()
4379  endif
4380  if target_type == 'user'
4381    src = user_ss.apply(config_target, strict: false)
4382    objects += libuser.extract_objects(src.sources())
4383    arch_deps += src.dependencies()
4384  endif
4385  if target_type == 'system' and target_base_arch in target_common_system_arch_libs
4386    src = target_common_system_arch[target_base_arch].apply(config_target, strict: false)
4387    lib = target_common_system_arch_libs[target_base_arch]
4388    objects += lib.extract_objects(src.sources())
4389    arch_deps += src.dependencies()
4390  endif
4391
4392  target_specific = specific_ss.apply(config_target, strict: false)
4393  arch_srcs += target_specific.sources()
4394  arch_deps += target_specific.dependencies()
4395
4396  if have_rust and target_type == 'system'
4397    target_rust = rust_devices_ss.apply(config_target, strict: false)
4398    crates = []
4399    foreach dep : target_rust.dependencies()
4400      crates += dep.get_variable('crate')
4401    endforeach
4402    if crates.length() > 0
4403      rlib_rs = custom_target('rust_' + target.underscorify() + '.rs',
4404                              output: 'rust_' + target.underscorify() + '.rs',
4405                              command: [rust_root_crate, crates],
4406                              capture: true,
4407                              build_by_default: true,
4408                              build_always_stale: true)
4409      rlib = static_library('rust_' + target.underscorify(),
4410                            structured_sources([], {'.': rlib_rs}),
4411                            dependencies: target_rust.dependencies(),
4412                            override_options: ['rust_std=2021', 'build.rust_std=2021'],
4413                            rust_abi: 'c')
4414      arch_deps += declare_dependency(link_whole: [rlib])
4415    endif
4416  endif
4417
4418  # allow using headers from the dependencies but do not include the sources,
4419  # because this emulator only needs those in "objects".  For external
4420  # dependencies, the full dependency is included below in the executable.
4421  lib_deps = []
4422  foreach dep : arch_deps
4423    lib_deps += dep.partial_dependency(compile_args: true, includes: true)
4424  endforeach
4425
4426  lib = static_library('qemu-' + target,
4427                 sources: arch_srcs + genh,
4428                 dependencies: lib_deps,
4429                 objects: objects,
4430                 include_directories: target_inc,
4431                 c_args: c_args,
4432                 build_by_default: false)
4433
4434  if target.endswith('-softmmu')
4435    execs = [{
4436      'name': 'qemu-system-' + target_name,
4437      'win_subsystem': 'console',
4438      'sources': files('system/main.c'),
4439      'dependencies': [sdl]
4440    }]
4441    if host_os == 'windows' and (sdl.found() or gtk.found())
4442      execs += [{
4443        'name': 'qemu-system-' + target_name + 'w',
4444        'win_subsystem': 'windows',
4445        'sources': files('system/main.c'),
4446        'dependencies': [sdl]
4447      }]
4448    endif
4449    if get_option('fuzzing')
4450      specific_fuzz = specific_fuzz_ss.apply(config_target, strict: false)
4451      execs += [{
4452        'name': 'qemu-fuzz-' + target_name,
4453        'win_subsystem': 'console',
4454        'sources': specific_fuzz.sources(),
4455        'dependencies': specific_fuzz.dependencies(),
4456      }]
4457    endif
4458  else
4459    execs = [{
4460      'name': 'qemu-' + target_name,
4461      'win_subsystem': 'console',
4462      'sources': [],
4463      'dependencies': []
4464    }]
4465  endif
4466  foreach exe: execs
4467    exe_name = exe['name']
4468    if host_os == 'darwin'
4469      exe_name += '-unsigned'
4470    endif
4471
4472    emulator = executable(exe_name, exe['sources'],
4473               install: true,
4474               c_args: c_args,
4475               dependencies: arch_deps + exe['dependencies'],
4476               objects: lib.extract_all_objects(recursive: true),
4477               link_depends: [block_syms, qemu_syms],
4478               link_args: link_args,
4479               win_subsystem: exe['win_subsystem'])
4480
4481    if host_os == 'darwin'
4482      icon = 'pc-bios/qemu.rsrc'
4483      build_input = [emulator, files(icon)]
4484      install_input = [
4485        get_option('bindir') / exe_name,
4486        meson.current_source_dir() / icon
4487      ]
4488      if 'CONFIG_HVF' in config_target
4489        entitlements = 'accel/hvf/entitlements.plist'
4490        build_input += files(entitlements)
4491        install_input += meson.current_source_dir() / entitlements
4492      endif
4493
4494      emulators += {exe['name'] : custom_target(exe['name'],
4495                   input: build_input,
4496                   output: exe['name'],
4497                   command: [entitlement, '@OUTPUT@', '@INPUT@'])
4498      }
4499
4500      meson.add_install_script(entitlement, '--install',
4501                               get_option('bindir') / exe['name'],
4502                               install_input)
4503    else
4504      emulators += {exe['name']: emulator}
4505    endif
4506
4507    traceable += [{
4508      'exe': exe['name'],
4509      'probe-prefix': 'qemu.' + target_type + '.' + target_name,
4510    }]
4511
4512  endforeach
4513endforeach
4514
4515# Other build targets
4516
4517if get_option('plugins')
4518  install_headers('include/qemu/qemu-plugin.h')
4519  if host_os == 'windows'
4520    # On windows, we want to deliver the qemu_plugin_api.lib file in the qemu installer,
4521    # so that plugin authors can compile against it.
4522    install_data(win32_qemu_plugin_api_lib, install_dir: 'lib')
4523  endif
4524endif
4525
4526subdir('qga')
4527
4528# Don't build qemu-keymap if xkbcommon is not explicitly enabled
4529# when we don't build tools or system
4530if xkbcommon.found()
4531  # used for the update-keymaps target, so include rules even if !have_tools
4532  qemu_keymap = executable('qemu-keymap', files('qemu-keymap.c', 'ui/input-keymap.c') + genh,
4533                           dependencies: [qemuutil, xkbcommon], install: have_tools)
4534endif
4535
4536if have_tools
4537  qemu_img = executable('qemu-img', [files('qemu-img.c'), hxdep],
4538             link_args: '@block.syms', link_depends: block_syms,
4539             dependencies: [authz, block, crypto, io, qom, qemuutil], install: true)
4540  qemu_io = executable('qemu-io', files('qemu-io.c'),
4541             link_args: '@block.syms', link_depends: block_syms,
4542             dependencies: [block, qemuutil], install: true)
4543  qemu_nbd = executable('qemu-nbd', files('qemu-nbd.c'),
4544               link_args: '@block.syms', link_depends: block_syms,
4545               dependencies: [blockdev, qemuutil, selinux],
4546               install: true)
4547
4548  subdir('storage-daemon')
4549
4550  foreach exe: [ 'qemu-img', 'qemu-io', 'qemu-nbd', 'qemu-storage-daemon']
4551    traceable += [{
4552      'exe': exe,
4553      'probe-prefix': 'qemu.' + exe.substring(5).replace('-', '_')
4554    }]
4555  endforeach
4556
4557  subdir('contrib/elf2dmp')
4558
4559  executable('qemu-edid', files('qemu-edid.c', 'hw/display/edid-generate.c'),
4560             dependencies: [qemuutil, rt],
4561             install: true)
4562
4563  if have_vhost_user
4564    subdir('contrib/vhost-user-blk')
4565    subdir('contrib/vhost-user-gpu')
4566    subdir('contrib/vhost-user-input')
4567    subdir('contrib/vhost-user-scsi')
4568  endif
4569
4570  if host_os == 'linux'
4571    executable('qemu-bridge-helper', files('qemu-bridge-helper.c'),
4572               dependencies: [qemuutil, libcap_ng],
4573               install: true,
4574               install_dir: get_option('libexecdir'))
4575
4576    executable('qemu-pr-helper', files('scsi/qemu-pr-helper.c', 'scsi/utils.c'),
4577               dependencies: [authz, crypto, io, qom, qemuutil,
4578                              libcap_ng, mpathpersist],
4579               install: true)
4580
4581    if cpu in ['x86', 'x86_64']
4582      executable('qemu-vmsr-helper', files('tools/i386/qemu-vmsr-helper.c'),
4583               dependencies: [authz, crypto, io, qom, qemuutil,
4584                              libcap_ng, mpathpersist],
4585               install: true)
4586    endif
4587  endif
4588
4589  if have_ivshmem
4590    subdir('contrib/ivshmem-client')
4591    subdir('contrib/ivshmem-server')
4592  endif
4593endif
4594
4595if stap.found()
4596  foreach t: traceable
4597    foreach stp: [
4598      {'ext': '.stp-build', 'fmt': 'stap', 'bin': meson.current_build_dir() / t['exe'], 'install': false},
4599      {'ext': '.stp', 'fmt': 'stap', 'bin': get_option('prefix') / get_option('bindir') / t['exe'], 'install': true},
4600      {'ext': '-simpletrace.stp', 'fmt': 'simpletrace-stap', 'bin': '', 'install': true},
4601      {'ext': '-log.stp', 'fmt': 'log-stap', 'bin': '', 'install': true},
4602    ]
4603      cmd = [
4604        tracetool, '--group=all', '--format=' + stp['fmt'],
4605        '--binary=' + stp['bin'],
4606        '--probe-prefix=' + t['probe-prefix'],
4607        '@INPUT@', '@OUTPUT@'
4608      ]
4609
4610      custom_target(t['exe'] + stp['ext'],
4611                    input: trace_events_all,
4612                    output: t['exe'] + stp['ext'],
4613                    install: stp['install'],
4614                    install_dir: get_option('datadir') / 'systemtap/tapset',
4615                    command: cmd,
4616                    depend_files: tracetool_depends)
4617    endforeach
4618  endforeach
4619endif
4620
4621subdir('scripts')
4622subdir('tools')
4623subdir('pc-bios')
4624subdir('docs')
4625# Tests are disabled on emscripten because they rely on host features that aren't
4626# supported by emscripten (e.g. fork and unix socket).
4627if host_os != 'emscripten'
4628  subdir('tests')
4629endif
4630if gtk.found()
4631  subdir('po')
4632endif
4633
4634if host_machine.system() == 'windows'
4635  nsis_cmd = [
4636    find_program('scripts/nsis.py'),
4637    '@OUTPUT@',
4638    get_option('prefix'),
4639    meson.current_source_dir(),
4640    glib_pc.get_variable('bindir'),
4641    host_machine.cpu(),
4642    '--',
4643    '-DDISPLAYVERSION=' + meson.project_version(),
4644  ]
4645  if build_docs
4646    nsis_cmd += '-DCONFIG_DOCUMENTATION=y'
4647  endif
4648  if gtk.found()
4649    nsis_cmd += '-DCONFIG_GTK=y'
4650  endif
4651
4652  nsis = custom_target('nsis',
4653                       output: 'qemu-setup-' + meson.project_version() + '.exe',
4654                       input: files('qemu.nsi'),
4655                       build_always_stale: true,
4656                       command: nsis_cmd + ['@INPUT@'])
4657  alias_target('installer', nsis)
4658endif
4659
4660#########################
4661# Configuration summary #
4662#########################
4663
4664# Build environment
4665summary_info = {}
4666summary_info += {'Build directory':   meson.current_build_dir()}
4667summary_info += {'Source path':       meson.current_source_dir()}
4668summary_info += {'Download dependencies': get_option('wrap_mode') != 'nodownload'}
4669summary(summary_info, bool_yn: true, section: 'Build environment')
4670
4671# Directories
4672summary_info += {'Install prefix':    get_option('prefix')}
4673summary_info += {'BIOS directory':    qemu_datadir}
4674pathsep = host_os == 'windows' ? ';' : ':'
4675summary_info += {'firmware path':     pathsep.join(get_option('qemu_firmwarepath'))}
4676summary_info += {'binary directory':  get_option('prefix') / get_option('bindir')}
4677summary_info += {'library directory': get_option('prefix') / get_option('libdir')}
4678summary_info += {'module directory':  qemu_moddir}
4679summary_info += {'libexec directory': get_option('prefix') / get_option('libexecdir')}
4680summary_info += {'include directory': get_option('prefix') / get_option('includedir')}
4681summary_info += {'config directory':  get_option('prefix') / get_option('sysconfdir')}
4682if host_os != 'windows'
4683  summary_info += {'local state directory': get_option('prefix') / get_option('localstatedir')}
4684  summary_info += {'Manual directory':      get_option('prefix') / get_option('mandir')}
4685else
4686  summary_info += {'local state directory': 'queried at runtime'}
4687endif
4688summary_info += {'Doc directory':     get_option('prefix') / get_option('docdir')}
4689summary(summary_info, bool_yn: true, section: 'Directories')
4690
4691# Host binaries
4692summary_info = {}
4693summary_info += {'python':            '@0@ (version: @1@)'.format(python.full_path(), python.language_version())}
4694summary_info += {'sphinx-build':      sphinx_build}
4695
4696# FIXME: the [binaries] section of machine files, which can be probed
4697# with find_program(), would be great for passing gdb and genisoimage
4698# paths from configure to Meson.  However, there seems to be no way to
4699# hide a program (for example if gdb is too old).
4700if config_host.has_key('GDB')
4701  summary_info += {'gdb':             config_host['GDB']}
4702endif
4703summary_info += {'iasl':              iasl}
4704summary_info += {'genisoimage':       config_host['GENISOIMAGE']}
4705if host_os == 'windows' and have_ga
4706  summary_info += {'wixl':            wixl}
4707endif
4708if slirp.found() and have_system
4709  summary_info += {'smbd':            have_slirp_smbd ? smbd_path : false}
4710endif
4711summary(summary_info, bool_yn: true, section: 'Host binaries')
4712
4713# Configurable features
4714summary_info = {}
4715summary_info += {'Documentation':     build_docs}
4716summary_info += {'system-mode emulation': have_system}
4717summary_info += {'user-mode emulation': have_user}
4718summary_info += {'block layer':       have_block}
4719summary_info += {'Install blobs':     get_option('install_blobs')}
4720summary_info += {'module support':    enable_modules}
4721if enable_modules
4722  summary_info += {'alternative module path': get_option('module_upgrades')}
4723endif
4724summary_info += {'fuzzing support':   get_option('fuzzing')}
4725if have_system
4726  summary_info += {'Audio drivers':     ' '.join(audio_drivers_selected)}
4727endif
4728summary_info += {'Trace backends':    ','.join(get_option('trace_backends'))}
4729if 'simple' in get_option('trace_backends')
4730  summary_info += {'Trace output file': get_option('trace_file') + '-<pid>'}
4731endif
4732summary_info += {'QOM debugging':     get_option('qom_cast_debug')}
4733summary_info += {'Relocatable install': get_option('relocatable')}
4734summary_info += {'vhost-kernel support': have_vhost_kernel}
4735summary_info += {'vhost-net support': have_vhost_net}
4736summary_info += {'vhost-user support': have_vhost_user}
4737summary_info += {'vhost-user-crypto support': have_vhost_user_crypto}
4738summary_info += {'vhost-user-blk server support': have_vhost_user_blk_server}
4739summary_info += {'vhost-vdpa support': have_vhost_vdpa}
4740summary_info += {'build guest agent': have_ga}
4741summary(summary_info, bool_yn: true, section: 'Configurable features')
4742
4743# Compilation information
4744summary_info = {}
4745summary_info += {'host CPU':          cpu}
4746summary_info += {'host endianness':   build_machine.endian()}
4747summary_info += {'C compiler':        ' '.join(meson.get_compiler('c').cmd_array())}
4748summary_info += {'Host C compiler':   ' '.join(meson.get_compiler('c', native: true).cmd_array())}
4749if 'cpp' in all_languages
4750  summary_info += {'C++ compiler':    ' '.join(meson.get_compiler('cpp').cmd_array())}
4751else
4752  summary_info += {'C++ compiler':      false}
4753endif
4754if 'objc' in all_languages
4755  summary_info += {'Objective-C compiler': ' '.join(meson.get_compiler('objc').cmd_array())}
4756else
4757  summary_info += {'Objective-C compiler': false}
4758endif
4759summary_info += {'Rust support':      have_rust}
4760if have_rust
4761  summary_info += {'Rust target':     config_host['RUST_TARGET_TRIPLE']}
4762  summary_info += {'rustc':           ' '.join(rustc.cmd_array())}
4763  summary_info += {'rustc version':   rustc.version()}
4764  summary_info += {'rustdoc':         rustdoc}
4765  summary_info += {'bindgen':         bindgen.full_path()}
4766  summary_info += {'bindgen version': bindgen.version()}
4767endif
4768option_cflags = (get_option('debug') ? ['-g'] : [])
4769if get_option('optimization') != 'plain'
4770  option_cflags += ['-O' + get_option('optimization')]
4771endif
4772summary_info += {'CFLAGS':            ' '.join(get_option('c_args') + option_cflags)}
4773if 'cpp' in all_languages
4774  summary_info += {'CXXFLAGS':        ' '.join(get_option('cpp_args') + option_cflags)}
4775endif
4776if 'objc' in all_languages
4777  summary_info += {'OBJCFLAGS':       ' '.join(get_option('objc_args') + option_cflags)}
4778endif
4779link_args = get_option('c_link_args')
4780if link_args.length() > 0
4781  summary_info += {'LDFLAGS':         ' '.join(link_args)}
4782endif
4783summary_info += {'QEMU_CFLAGS':       ' '.join(qemu_common_flags + qemu_cflags)}
4784if 'cpp' in all_languages
4785  summary_info += {'QEMU_CXXFLAGS':     ' '.join(qemu_common_flags + qemu_cxxflags)}
4786endif
4787if 'objc' in all_languages
4788  summary_info += {'QEMU_OBJCFLAGS':    ' '.join(qemu_common_flags)}
4789endif
4790summary_info += {'QEMU_LDFLAGS':      ' '.join(qemu_ldflags)}
4791summary_info += {'link-time optimization (LTO)': get_option('b_lto')}
4792summary_info += {'PIE':               get_option('b_pie')}
4793summary_info += {'static build':      get_option('prefer_static')}
4794summary_info += {'malloc trim support': has_malloc_trim}
4795summary_info += {'membarrier':        have_membarrier}
4796summary_info += {'debug graph lock':  get_option('debug_graph_lock')}
4797summary_info += {'debug stack usage': get_option('debug_stack_usage')}
4798summary_info += {'mutex debugging':   get_option('debug_mutex')}
4799summary_info += {'memory allocator':  get_option('malloc')}
4800summary_info += {'avx2 optimization': config_host_data.get('CONFIG_AVX2_OPT')}
4801summary_info += {'avx512bw optimization': config_host_data.get('CONFIG_AVX512BW_OPT')}
4802summary_info += {'gcov':              get_option('b_coverage')}
4803summary_info += {'thread sanitizer':  get_option('tsan')}
4804summary_info += {'CFI support':       get_option('cfi')}
4805if get_option('cfi')
4806  summary_info += {'CFI debug support': get_option('cfi_debug')}
4807endif
4808summary_info += {'strip binaries':    get_option('strip')}
4809summary_info += {'sparse':            sparse}
4810summary_info += {'mingw32 support':   host_os == 'windows'}
4811summary(summary_info, bool_yn: true, section: 'Compilation')
4812
4813# snarf the cross-compilation information for tests
4814summary_info = {}
4815have_cross = false
4816foreach target: target_dirs
4817  tcg_mak = meson.current_build_dir() / 'tests/tcg' / target / 'config-target.mak'
4818  if fs.exists(tcg_mak)
4819    config_cross_tcg = keyval.load(tcg_mak)
4820    if 'CC' in config_cross_tcg
4821      summary_info += {config_cross_tcg['TARGET_NAME']: config_cross_tcg['CC']}
4822      have_cross = true
4823    endif
4824  endif
4825endforeach
4826if have_cross
4827  summary(summary_info, bool_yn: true, section: 'Cross compilers')
4828endif
4829
4830# Targets and accelerators
4831summary_info = {}
4832if have_system
4833  summary_info += {'KVM support':       config_all_accel.has_key('CONFIG_KVM')}
4834  summary_info += {'HVF support':       config_all_accel.has_key('CONFIG_HVF')}
4835  summary_info += {'WHPX support':      config_all_accel.has_key('CONFIG_WHPX')}
4836  summary_info += {'NVMM support':      config_all_accel.has_key('CONFIG_NVMM')}
4837  summary_info += {'Xen support':       xen.found()}
4838  if xen.found()
4839    summary_info += {'xen ctrl version':  xen.version()}
4840  endif
4841  summary_info += {'Xen emulation':     config_all_devices.has_key('CONFIG_XEN_EMU')}
4842endif
4843summary_info += {'TCG support':       config_all_accel.has_key('CONFIG_TCG')}
4844if config_all_accel.has_key('CONFIG_TCG')
4845  if get_option('tcg_interpreter')
4846    summary_info += {'TCG backend':   'TCI (TCG with bytecode interpreter, slow)'}
4847  else
4848    summary_info += {'TCG backend':   'native (@0@)'.format(cpu)}
4849  endif
4850  summary_info += {'TCG plugins':       get_option('plugins')}
4851  summary_info += {'TCG debug enabled': get_option('debug_tcg')}
4852  if have_linux_user or have_bsd_user
4853    summary_info += {'syscall buffer debugging support': get_option('debug_remap')}
4854  endif
4855endif
4856summary_info += {'target list':       ' '.join(target_dirs)}
4857if have_system
4858  summary_info += {'default devices':   get_option('default_devices')}
4859  summary_info += {'out of process emulation': multiprocess_allowed}
4860  summary_info += {'vfio-user server': vfio_user_server_allowed}
4861endif
4862summary(summary_info, bool_yn: true, section: 'Targets and accelerators')
4863
4864# Block layer
4865summary_info = {}
4866summary_info += {'coroutine backend': coroutine_backend}
4867summary_info += {'coroutine pool':    have_coroutine_pool}
4868if have_block
4869  summary_info += {'Block whitelist (rw)': get_option('block_drv_rw_whitelist')}
4870  summary_info += {'Block whitelist (ro)': get_option('block_drv_ro_whitelist')}
4871  summary_info += {'Use block whitelist in tools': get_option('block_drv_whitelist_in_tools')}
4872  summary_info += {'VirtFS (9P) support':    have_virtfs}
4873  summary_info += {'replication support': config_host_data.get('CONFIG_REPLICATION')}
4874  summary_info += {'bochs support':     get_option('bochs').allowed()}
4875  summary_info += {'cloop support':     get_option('cloop').allowed()}
4876  summary_info += {'dmg support':       get_option('dmg').allowed()}
4877  summary_info += {'qcow v1 support':   get_option('qcow1').allowed()}
4878  summary_info += {'vdi support':       get_option('vdi').allowed()}
4879  summary_info += {'vhdx support':      get_option('vhdx').allowed()}
4880  summary_info += {'vmdk support':      get_option('vmdk').allowed()}
4881  summary_info += {'vpc support':       get_option('vpc').allowed()}
4882  summary_info += {'vvfat support':     get_option('vvfat').allowed()}
4883  summary_info += {'qed support':       get_option('qed').allowed()}
4884  summary_info += {'parallels support': get_option('parallels').allowed()}
4885  summary_info += {'FUSE exports':      fuse}
4886  summary_info += {'VDUSE block exports': have_vduse_blk_export}
4887endif
4888summary(summary_info, bool_yn: true, section: 'Block layer support')
4889
4890# Crypto
4891summary_info = {}
4892summary_info += {'TLS priority':      get_option('tls_priority')}
4893summary_info += {'GNUTLS support':    gnutls}
4894if gnutls.found()
4895  summary_info += {'  GNUTLS crypto':   gnutls_crypto.found()}
4896endif
4897summary_info += {'libgcrypt':         gcrypt}
4898summary_info += {'nettle':            nettle}
4899if nettle.found()
4900   summary_info += {'  XTS':             xts != 'private'}
4901endif
4902summary_info += {'SM4 ALG support':   crypto_sm4}
4903summary_info += {'SM3 ALG support':   crypto_sm3}
4904summary_info += {'AF_ALG support':    have_afalg}
4905summary_info += {'rng-none':          get_option('rng_none')}
4906summary_info += {'Linux keyring':     have_keyring}
4907summary_info += {'Linux keyutils':    keyutils}
4908summary(summary_info, bool_yn: true, section: 'Crypto')
4909
4910# UI
4911summary_info = {}
4912if host_os == 'darwin'
4913  summary_info += {'Cocoa support':           cocoa}
4914endif
4915summary_info += {'D-Bus display':     dbus_display}
4916summary_info += {'SDL support':       sdl}
4917summary_info += {'SDL image support': sdl_image}
4918summary_info += {'GTK support':       gtk}
4919summary_info += {'pixman':            pixman}
4920summary_info += {'VTE support':       vte}
4921summary_info += {'PNG support':       png}
4922summary_info += {'VNC support':       vnc}
4923if vnc.found()
4924  summary_info += {'VNC SASL support':  sasl}
4925  summary_info += {'VNC JPEG support':  jpeg}
4926endif
4927summary_info += {'spice protocol support': spice_protocol}
4928if spice_protocol.found()
4929  summary_info += {'  spice server support': spice}
4930endif
4931summary_info += {'curses support':    curses}
4932summary_info += {'brlapi support':    brlapi}
4933summary(summary_info, bool_yn: true, section: 'User interface')
4934
4935# Graphics backends
4936summary_info = {}
4937summary_info += {'VirGL support':     virgl}
4938summary_info += {'Rutabaga support':  rutabaga}
4939summary(summary_info, bool_yn: true, section: 'Graphics backends')
4940
4941# Audio backends
4942summary_info = {}
4943if host_os not in ['darwin', 'haiku', 'windows']
4944  summary_info += {'OSS support':     oss}
4945  summary_info += {'sndio support':   sndio}
4946elif host_os == 'darwin'
4947  summary_info += {'CoreAudio support': coreaudio}
4948elif host_os == 'windows'
4949  summary_info += {'DirectSound support': dsound}
4950endif
4951if host_os == 'linux'
4952  summary_info += {'ALSA support':    alsa}
4953  summary_info += {'PulseAudio support': pulse}
4954endif
4955summary_info += {'PipeWire support':  pipewire}
4956summary_info += {'JACK support':      jack}
4957summary(summary_info, bool_yn: true, section: 'Audio backends')
4958
4959# Network backends
4960summary_info = {}
4961if host_os == 'darwin'
4962  summary_info += {'vmnet.framework support': vmnet}
4963endif
4964summary_info += {'AF_XDP support':    libxdp}
4965summary_info += {'slirp support':     slirp}
4966summary_info += {'vde support':       vde}
4967summary_info += {'netmap support':    have_netmap}
4968summary_info += {'l2tpv3 support':    have_l2tpv3}
4969summary(summary_info, bool_yn: true, section: 'Network backends')
4970
4971# Libraries
4972summary_info = {}
4973summary_info += {'libtasn1':          tasn1}
4974summary_info += {'PAM':               pam}
4975summary_info += {'iconv support':     iconv}
4976summary_info += {'blkio support':     blkio}
4977summary_info += {'curl support':      curl}
4978summary_info += {'Multipath support': mpathpersist}
4979summary_info += {'Linux AIO support': libaio}
4980summary_info += {'Linux io_uring support': linux_io_uring}
4981summary_info += {'ATTR/XATTR support': libattr}
4982summary_info += {'RDMA support':      rdma}
4983summary_info += {'fdt support':       fdt_opt == 'internal' ? 'internal' : fdt}
4984summary_info += {'libcap-ng support': libcap_ng}
4985summary_info += {'bpf support':       libbpf}
4986summary_info += {'rbd support':       rbd}
4987summary_info += {'smartcard support': cacard}
4988summary_info += {'U2F support':       u2f}
4989summary_info += {'libusb':            libusb}
4990summary_info += {'usb net redir':     usbredir}
4991summary_info += {'OpenGL support (epoxy)': opengl}
4992summary_info += {'GBM':               gbm}
4993summary_info += {'libiscsi support':  libiscsi}
4994summary_info += {'libnfs support':    libnfs}
4995if host_os == 'windows'
4996  if have_ga
4997    summary_info += {'QGA VSS support':   have_qga_vss}
4998  endif
4999endif
5000summary_info += {'seccomp support':   seccomp}
5001summary_info += {'GlusterFS support': glusterfs}
5002summary_info += {'hv-balloon support': hv_balloon}
5003summary_info += {'TPM support':       have_tpm}
5004summary_info += {'libssh support':    libssh}
5005summary_info += {'lzo support':       lzo}
5006summary_info += {'snappy support':    snappy}
5007summary_info += {'bzip2 support':     libbzip2}
5008summary_info += {'lzfse support':     liblzfse}
5009summary_info += {'zstd support':      zstd}
5010summary_info += {'Query Processing Library support': qpl}
5011summary_info += {'UADK Library support': uadk}
5012summary_info += {'qatzip support':    qatzip}
5013summary_info += {'NUMA host support': numa}
5014summary_info += {'capstone':          capstone}
5015summary_info += {'libpmem support':   libpmem}
5016summary_info += {'libdaxctl support': libdaxctl}
5017summary_info += {'libcbor support':   libcbor}
5018summary_info += {'libudev':           libudev}
5019# Dummy dependency, keep .found()
5020summary_info += {'FUSE lseek':        fuse_lseek.found()}
5021summary_info += {'selinux':           selinux}
5022summary_info += {'libdw':             libdw}
5023if host_os == 'freebsd'
5024  summary_info += {'libinotify-kqueue': inotify}
5025endif
5026if host_os == 'darwin'
5027  summary_info += {'ParavirtualizedGraphics support': pvg}
5028endif
5029summary_info += {'valgrind':          valgrind}
5030summary(summary_info, bool_yn: true, section: 'Dependencies')
5031
5032if host_arch == 'unknown'
5033  message()
5034  warning('UNSUPPORTED HOST CPU')
5035  message()
5036  message('Support for CPU host architecture ' + cpu + ' is not currently')
5037  message('maintained. The QEMU project does not guarantee that QEMU will')
5038  message('compile or work on this host CPU. You can help by volunteering')
5039  message('to maintain it and providing a build host for our continuous')
5040  message('integration setup.')
5041  if have_tcg
5042    message()
5043    message('configure has succeeded and you can continue to build, but')
5044    message('QEMU will use a slow interpreter to emulate the target CPU.')
5045  endif
5046elif host_long_bits < 64
5047  message()
5048  warning('DEPRECATED HOST CPU')
5049  message()
5050  message('Support for 32-bit CPU host architecture ' + cpu + ' is going')
5051  message('to be dropped in a future QEMU release.')
5052endif
5053
5054if not supported_oses.contains(host_os)
5055  message()
5056  warning('UNSUPPORTED HOST OS')
5057  message()
5058  message('Support for host OS ' + host_os + 'is not currently maintained.')
5059  message('configure has succeeded and you can continue to build, but')
5060  message('the QEMU project does not guarantee that QEMU will compile or')
5061  message('work on this operating system. You can help by volunteering')
5062  message('to maintain it and providing a build host for our continuous')
5063  message('integration setup. This will ensure that future versions of QEMU')
5064  message('will keep working on ' + host_os + '.')
5065endif
5066
5067if host_arch == 'unknown' or not supported_oses.contains(host_os)
5068  message()
5069  message('If you want to help supporting QEMU on this platform, please')
5070  message('contact the developers at qemu-devel@nongnu.org.')
5071endif
5072
5073actually_reloc = get_option('relocatable')
5074# check if get_relocated_path() is actually able to relocate paths
5075if get_option('relocatable') and \
5076  not (get_option('prefix') / get_option('bindir')).startswith(get_option('prefix') / '')
5077  message()
5078  warning('bindir not included within prefix, the installation will not be relocatable.')
5079  actually_reloc = false
5080endif
5081if not actually_reloc and (host_os == 'windows' or get_option('relocatable'))
5082  if host_os == 'windows'
5083    message()
5084    warning('Windows installs should usually be relocatable.')
5085  endif
5086  message()
5087  message('QEMU will have to be installed under ' + get_option('prefix') + '.')
5088  message('Use --disable-relocatable to remove this warning.')
5089endif
5090