xref: /openbmc/qemu/meson.build (revision 374d766da75ab89749f59813f7ae55d913c37b58)
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/vfio-user',
3687    'hw/virtio',
3688    'hw/vmapple',
3689    'hw/watchdog',
3690    'hw/xen',
3691    'hw/gpio',
3692    'migration',
3693    'net',
3694    'system',
3695    'ui',
3696    'hw/remote',
3697  ]
3698endif
3699if have_system or have_user
3700  trace_events_subdirs += [
3701    'accel/tcg',
3702    'hw/core',
3703    'target/arm',
3704    'target/arm/hvf',
3705    'target/hppa',
3706    'target/i386',
3707    'target/i386/kvm',
3708    'target/loongarch',
3709    'target/mips/tcg',
3710    'target/ppc',
3711    'target/riscv',
3712    'target/s390x',
3713    'target/s390x/kvm',
3714    'target/sparc',
3715  ]
3716endif
3717
3718###################
3719# Collect sources #
3720###################
3721
3722authz_ss = ss.source_set()
3723blockdev_ss = ss.source_set()
3724block_ss = ss.source_set()
3725chardev_ss = ss.source_set()
3726common_ss = ss.source_set()
3727crypto_ss = ss.source_set()
3728hwcore_ss = ss.source_set()
3729io_ss = ss.source_set()
3730qmp_ss = ss.source_set()
3731qom_ss = ss.source_set()
3732system_ss = ss.source_set()
3733specific_fuzz_ss = ss.source_set()
3734specific_ss = ss.source_set()
3735rust_devices_ss = ss.source_set()
3736stub_ss = ss.source_set()
3737trace_ss = ss.source_set()
3738user_ss = ss.source_set()
3739util_ss = ss.source_set()
3740
3741# accel modules
3742qtest_module_ss = ss.source_set()
3743
3744modules = {}
3745target_modules = {}
3746plugin_modules = []
3747hw_arch = {}
3748target_arch = {}
3749target_system_arch = {}
3750target_user_arch = {}
3751hw_common_arch = {}
3752target_common_arch = {}
3753target_common_system_arch = {}
3754
3755# NOTE: the trace/ subdirectory needs the qapi_trace_events variable
3756# that is filled in by qapi/.
3757subdir('qapi')
3758subdir('qobject')
3759subdir('stubs')
3760subdir('trace')
3761subdir('util')
3762subdir('qom')
3763subdir('authz')
3764subdir('crypto')
3765subdir('ui')
3766subdir('gdbstub')
3767if have_system
3768  subdir('hw')
3769else
3770  subdir('hw/core')
3771endif
3772
3773if enable_modules
3774  libmodulecommon = static_library('module-common', files('module-common.c') + genh, pic: true, c_args: '-DBUILD_DSO')
3775  modulecommon = declare_dependency(objects: libmodulecommon.extract_all_objects(recursive: false), compile_args: '-DBUILD_DSO')
3776endif
3777
3778qom_ss = qom_ss.apply({})
3779libqom = static_library('qom', qom_ss.sources() + genh,
3780                        dependencies: [qom_ss.dependencies()],
3781                        build_by_default: false)
3782qom = declare_dependency(objects: libqom.extract_all_objects(recursive: false),
3783                         dependencies: qom_ss.dependencies())
3784
3785event_loop_base = files('event-loop-base.c')
3786event_loop_base = static_library('event-loop-base',
3787                                 sources: event_loop_base + genh,
3788                                 build_by_default: false)
3789event_loop_base = declare_dependency(objects: event_loop_base.extract_all_objects(recursive: false),
3790                                     dependencies: [qom])
3791
3792stub_ss = stub_ss.apply({})
3793
3794util_ss.add_all(trace_ss)
3795util_ss = util_ss.apply({})
3796libqemuutil = static_library('qemuutil',
3797                             build_by_default: false,
3798                             sources: util_ss.sources() + stub_ss.sources() + genh,
3799                             dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc])
3800qemuutil_deps = [event_loop_base]
3801if host_os != 'windows'
3802  qemuutil_deps += [rt]
3803endif
3804qemuutil = declare_dependency(link_with: libqemuutil,
3805                              sources: genh + version_res,
3806                              dependencies: qemuutil_deps)
3807
3808if have_system or have_user
3809  decodetree = generator(find_program('scripts/decodetree.py'),
3810                         output: 'decode-@BASENAME@.c.inc',
3811                         arguments: ['@INPUT@', '@EXTRA_ARGS@', '-o', '@OUTPUT@'])
3812  subdir('libdecnumber')
3813  subdir('target')
3814endif
3815
3816subdir('audio')
3817subdir('io')
3818subdir('chardev')
3819subdir('fsdev')
3820subdir('dump')
3821
3822if have_block
3823  block_ss.add(files(
3824    'block.c',
3825    'blockjob.c',
3826    'job.c',
3827    'qemu-io-cmds.c',
3828  ))
3829  if config_host_data.get('CONFIG_REPLICATION')
3830    block_ss.add(files('replication.c'))
3831  endif
3832
3833  subdir('nbd')
3834  subdir('scsi')
3835  subdir('block')
3836
3837  blockdev_ss.add(files(
3838    'blockdev.c',
3839    'blockdev-nbd.c',
3840    'iothread.c',
3841    'job-qmp.c',
3842  ))
3843
3844  # os-posix.c contains POSIX-specific functions used by qemu-storage-daemon,
3845  # os-win32.c does not
3846  if host_os == 'windows'
3847    system_ss.add(files('os-win32.c'))
3848  elif host_os == 'emscripten'
3849    blockdev_ss.add(files('os-wasm.c'))
3850  else
3851    blockdev_ss.add(files('os-posix.c'))
3852  endif
3853endif
3854
3855common_ss.add(files('cpu-common.c'))
3856specific_ss.add(files('cpu-target.c'))
3857
3858subdir('system')
3859
3860# Work around a gcc bug/misfeature wherein constant propagation looks
3861# through an alias:
3862#   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99696
3863# to guess that a const variable is always zero.  Without lto, this is
3864# impossible, as the alias is restricted to page-vary-common.c.  Indeed,
3865# without lto, not even the alias is required -- we simply use different
3866# declarations in different compilation units.
3867pagevary = files('page-vary-common.c')
3868if get_option('b_lto')
3869  pagevary_flags = ['-fno-lto']
3870  if get_option('cfi')
3871    pagevary_flags += '-fno-sanitize=cfi-icall'
3872  endif
3873  pagevary = static_library('page-vary-common', sources: pagevary + genh,
3874                            c_args: pagevary_flags)
3875  pagevary = declare_dependency(link_with: pagevary)
3876endif
3877common_ss.add(pagevary)
3878specific_ss.add(files('page-target.c', 'page-vary-target.c'))
3879
3880common_ss.add(files('target-info.c'))
3881specific_ss.add(files('target-info-stub.c'))
3882
3883subdir('backends')
3884subdir('disas')
3885subdir('migration')
3886subdir('monitor')
3887subdir('net')
3888subdir('replay')
3889subdir('semihosting')
3890subdir('stats')
3891subdir('tcg')
3892subdir('fpu')
3893subdir('accel')
3894subdir('plugins')
3895subdir('ebpf')
3896
3897if 'CONFIG_TCG' in config_all_accel
3898  subdir('contrib/plugins')
3899endif
3900
3901common_user_inc = []
3902
3903subdir('common-user')
3904subdir('bsd-user')
3905subdir('linux-user')
3906
3907# needed for fuzzing binaries
3908subdir('tests/qtest/libqos')
3909subdir('tests/qtest/fuzz')
3910
3911# accel modules
3912target_modules += { 'accel' : { 'qtest': qtest_module_ss }}
3913
3914##############################################
3915# Internal static_libraries and dependencies #
3916##############################################
3917
3918modinfo_collect = find_program('scripts/modinfo-collect.py')
3919modinfo_generate = find_program('scripts/modinfo-generate.py')
3920modinfo_files = []
3921
3922block_mods = []
3923system_mods = []
3924emulator_modules = []
3925foreach d, list : modules
3926  if not (d == 'block' ? have_block : have_system)
3927    continue
3928  endif
3929
3930  foreach m, module_ss : list
3931    if enable_modules
3932      module_ss.add(modulecommon)
3933      module_ss = module_ss.apply(config_all_devices, strict: false)
3934      sl = static_library(d + '-' + m, [genh, module_ss.sources()],
3935                          dependencies: module_ss.dependencies(), pic: true)
3936      if d == 'block'
3937        block_mods += sl
3938      else
3939        system_mods += sl
3940      endif
3941      emulator_modules += shared_module(sl.name(),
3942                    name_prefix: '',
3943                    objects: sl.extract_all_objects(recursive: false),
3944                    dependencies: module_ss.dependencies(),
3945                    install: true,
3946                    install_dir: qemu_moddir)
3947      if module_ss.sources() != []
3948        modinfo_files += custom_target(d + '-' + m + '.modinfo',
3949                                       output: d + '-' + m + '.modinfo',
3950                                       input: sl.extract_all_objects(recursive: true),
3951                                       capture: true,
3952                                       command: [modinfo_collect, '@INPUT@'])
3953      endif
3954    else
3955      if d == 'block'
3956        block_ss.add_all(module_ss)
3957      else
3958        system_ss.add_all(module_ss)
3959      endif
3960    endif
3961  endforeach
3962endforeach
3963
3964foreach d, list : target_modules
3965  foreach m, module_ss : list
3966    if enable_modules
3967      module_ss.add(modulecommon)
3968      foreach target : target_dirs
3969        if target.endswith('-softmmu')
3970          config_target = config_target_mak[target]
3971          target_inc = [include_directories('target' / config_target['TARGET_BASE_ARCH'])]
3972          c_args = ['-DCOMPILING_PER_TARGET',
3973                    '-DCONFIG_TARGET="@0@-config-target.h"'.format(target),
3974                    '-DCONFIG_DEVICES="@0@-config-devices.h"'.format(target)]
3975          target_module_ss = module_ss.apply(config_target, strict: false)
3976          if target_module_ss.sources() != []
3977            module_name = d + '-' + m + '-' + config_target['TARGET_NAME']
3978            sl = static_library(module_name,
3979                                [genh, target_module_ss.sources()],
3980                                dependencies: target_module_ss.dependencies(),
3981                                include_directories: target_inc,
3982                                c_args: c_args,
3983                                pic: true)
3984            system_mods += sl
3985            emulator_modules += shared_module(sl.name(),
3986                    name_prefix: '',
3987                    objects: sl.extract_all_objects(recursive: false),
3988                    dependencies: target_module_ss.dependencies(),
3989                    install: true,
3990                    install_dir: qemu_moddir)
3991            modinfo_files += custom_target(module_name + '.modinfo',
3992                                           output: module_name + '.modinfo',
3993                                           input: sl.extract_all_objects(recursive: true),
3994                                           capture: true,
3995                                           command: [modinfo_collect, '--target', target, '@INPUT@'])
3996          endif
3997        endif
3998      endforeach
3999    else
4000      specific_ss.add_all(module_ss)
4001    endif
4002  endforeach
4003endforeach
4004
4005if enable_modules
4006  foreach target : target_dirs
4007    if target.endswith('-softmmu')
4008      config_target = config_target_mak[target]
4009      config_devices_mak = target + '-config-devices.mak'
4010      modinfo_src = custom_target('modinfo-' + target + '.c',
4011                                  output: 'modinfo-' + target + '.c',
4012                                  input: modinfo_files,
4013                                  command: [modinfo_generate, '--devices', config_devices_mak, '@INPUT@'],
4014                                  capture: true)
4015
4016      modinfo_lib = static_library('modinfo-' + target + '.c', modinfo_src)
4017      modinfo_dep = declare_dependency(link_with: modinfo_lib)
4018
4019      arch = config_target['TARGET_NAME'] == 'sparc64' ? 'sparc64' : config_target['TARGET_BASE_ARCH']
4020      hw_arch[arch].add(modinfo_dep)
4021    endif
4022  endforeach
4023
4024  if emulator_modules.length() > 0
4025    alias_target('modules', emulator_modules)
4026  endif
4027endif
4028
4029nm = find_program('nm')
4030undefsym = find_program('scripts/undefsym.py')
4031block_syms = custom_target('block.syms', output: 'block.syms',
4032                             input: [libqemuutil, block_mods],
4033                             capture: true,
4034                             command: [undefsym, nm, '@INPUT@'])
4035qemu_syms = custom_target('qemu.syms', output: 'qemu.syms',
4036                             input: [libqemuutil, system_mods],
4037                             capture: true,
4038                             command: [undefsym, nm, '@INPUT@'])
4039
4040authz_ss = authz_ss.apply({})
4041libauthz = static_library('authz', authz_ss.sources() + genh,
4042                          dependencies: [authz_ss.dependencies()],
4043                          build_by_default: false)
4044
4045authz = declare_dependency(objects: libauthz.extract_all_objects(recursive: false),
4046                           dependencies: [authz_ss.dependencies(), qom])
4047
4048crypto_ss = crypto_ss.apply({})
4049libcrypto = static_library('crypto', crypto_ss.sources() + genh,
4050                           dependencies: [crypto_ss.dependencies()],
4051                           build_by_default: false)
4052
4053crypto = declare_dependency(objects: libcrypto.extract_all_objects(recursive: false),
4054                            dependencies: [crypto_ss.dependencies(), authz, qom])
4055
4056io_ss = io_ss.apply({})
4057libio = static_library('io', io_ss.sources() + genh,
4058                       dependencies: [io_ss.dependencies()],
4059                       link_with: libqemuutil,
4060                       build_by_default: false)
4061
4062io = declare_dependency(objects: libio.extract_all_objects(recursive: false),
4063                        dependencies: [io_ss.dependencies(), crypto, qom])
4064
4065libmigration = static_library('migration', sources: migration_files + genh,
4066                              build_by_default: false)
4067migration = declare_dependency(objects: libmigration.extract_all_objects(recursive: false),
4068                               dependencies: [qom, io])
4069system_ss.add(migration)
4070
4071block_ss = block_ss.apply({})
4072libblock = static_library('block', block_ss.sources() + genh,
4073                          dependencies: block_ss.dependencies(),
4074                          build_by_default: false)
4075
4076block = declare_dependency(objects: libblock.extract_all_objects(recursive: false),
4077                           dependencies: [block_ss.dependencies(), crypto, io])
4078
4079blockdev_ss = blockdev_ss.apply({})
4080libblockdev = static_library('blockdev', blockdev_ss.sources() + genh,
4081                             dependencies: blockdev_ss.dependencies(),
4082                             build_by_default: false)
4083
4084blockdev = declare_dependency(objects: libblockdev.extract_all_objects(recursive: false),
4085                              dependencies: [blockdev_ss.dependencies(), block, event_loop_base])
4086
4087qmp_ss = qmp_ss.apply({})
4088libqmp = static_library('qmp', qmp_ss.sources() + genh,
4089                        dependencies: qmp_ss.dependencies(),
4090                        build_by_default: false)
4091
4092qmp = declare_dependency(objects: libqmp.extract_all_objects(recursive: false),
4093                         dependencies: qmp_ss.dependencies())
4094
4095libchardev = static_library('chardev', chardev_ss.sources() + genh,
4096                            dependencies: chardev_ss.dependencies(),
4097                            build_by_default: false)
4098
4099chardev = declare_dependency(objects: libchardev.extract_all_objects(recursive: false),
4100                             dependencies: [chardev_ss.dependencies(), io])
4101
4102hwcore_ss = hwcore_ss.apply({})
4103libhwcore = static_library('hwcore', sources: hwcore_ss.sources() + genh,
4104                           build_by_default: false)
4105hwcore = declare_dependency(objects: libhwcore.extract_all_objects(recursive: false))
4106common_ss.add(hwcore)
4107
4108###########
4109# Targets #
4110###########
4111
4112system_ss.add(authz, blockdev, chardev, crypto, io, qmp)
4113common_ss.add(qom, qemuutil)
4114
4115libuser = static_library('user',
4116                         user_ss.all_sources() + genh,
4117                         c_args: ['-DCONFIG_USER_ONLY',
4118                                  '-DCOMPILING_SYSTEM_VS_USER'],
4119                         include_directories: common_user_inc,
4120                         dependencies: user_ss.all_dependencies(),
4121                         build_by_default: false)
4122
4123libsystem = static_library('system',
4124                           system_ss.all_sources() + genh,
4125                           c_args: ['-DCONFIG_SOFTMMU',
4126                                    '-DCOMPILING_SYSTEM_VS_USER'],
4127                           dependencies: system_ss.all_dependencies(),
4128                           build_by_default: false)
4129
4130# Note that this library is never used directly (only through extract_objects)
4131# and is not built by default; therefore, source files not used by the build
4132# configuration will be in build.ninja, but are never built by default.
4133common_all = static_library('common',
4134                            build_by_default: false,
4135                            sources: common_ss.all_sources() + genh,
4136                            implicit_include_directories: false,
4137                            dependencies: common_ss.all_dependencies())
4138
4139# construct common libraries per base architecture
4140target_common_arch_libs = {}
4141target_common_system_arch_libs = {}
4142foreach target_base_arch, config_base_arch : config_base_arch_mak
4143  target_inc = [include_directories('target' / target_base_arch)]
4144  inc = [common_user_inc + target_inc]
4145
4146  target_common = common_ss.apply(config_base_arch, strict: false)
4147  target_system = system_ss.apply(config_base_arch, strict: false)
4148  target_user = user_ss.apply(config_base_arch, strict: false)
4149  common_deps = []
4150  system_deps = []
4151  user_deps = []
4152  foreach dep: target_common.dependencies()
4153    common_deps += dep.partial_dependency(compile_args: true, includes: true)
4154  endforeach
4155  foreach dep: target_system.dependencies()
4156    system_deps += dep.partial_dependency(compile_args: true, includes: true)
4157  endforeach
4158  foreach dep: target_user.dependencies()
4159    user_deps += dep.partial_dependency(compile_args: true, includes: true)
4160  endforeach
4161
4162  # prevent common code to access cpu compile time definition,
4163  # but still allow access to cpu.h
4164  target_c_args = ['-DCPU_DEFS_H']
4165  target_system_c_args = target_c_args + ['-DCOMPILING_SYSTEM_VS_USER', '-DCONFIG_SOFTMMU']
4166
4167  if target_base_arch in target_common_arch
4168    src = target_common_arch[target_base_arch]
4169    lib = static_library(
4170      'common_' + target_base_arch,
4171      build_by_default: false,
4172      sources: src.all_sources() + genh,
4173      include_directories: inc,
4174      c_args: target_c_args,
4175      dependencies: src.all_dependencies() + common_deps +
4176                    system_deps + user_deps)
4177    target_common_arch_libs += {target_base_arch: lib}
4178  endif
4179
4180  # merge hw_common_arch in target_common_system_arch
4181  if target_base_arch in hw_common_arch
4182    hw_src = hw_common_arch[target_base_arch]
4183    if target_base_arch in target_common_system_arch
4184      target_common_system_arch[target_base_arch].add_all(hw_src)
4185    else
4186      target_common_system_arch += {target_base_arch: hw_src}
4187    endif
4188  endif
4189
4190  if target_base_arch in target_common_system_arch
4191    src = target_common_system_arch[target_base_arch]
4192    lib = static_library(
4193      'system_' + target_base_arch,
4194      build_by_default: false,
4195      sources: src.all_sources() + genh,
4196      include_directories: inc,
4197      c_args: target_system_c_args,
4198      dependencies: src.all_dependencies() + common_deps + system_deps)
4199    target_common_system_arch_libs += {target_base_arch: lib}
4200  endif
4201endforeach
4202
4203if have_rust
4204  bindings_incdir = include_directories('.', 'include')
4205  # We would like to use --generate-cstr, but it is only available
4206  # starting with bindgen 0.66.0.  The oldest supported versions
4207  # is 0.60.x (Debian 12 has 0.60.1) which introduces --allowlist-file.
4208  bindgen_args_common = [
4209    '--disable-header-comment',
4210    '--raw-line', '// @generated',
4211    '--ctypes-prefix', 'std::os::raw',
4212    '--generate-block',
4213    '--impl-debug',
4214    '--no-doc-comments',
4215    '--with-derive-default',
4216    '--no-layout-tests',
4217    '--no-prepend-enum-name',
4218    '--allowlist-file', meson.project_source_root() + '/include/.*',
4219    '--allowlist-file', meson.project_source_root() + '/.*',
4220    '--allowlist-file', meson.project_build_root() + '/.*'
4221    ]
4222  if not rustfmt.found()
4223    if bindgen.version().version_compare('<0.65.0')
4224      bindgen_args_common += ['--no-rustfmt-bindings']
4225    else
4226      bindgen_args_common += ['--formatter', 'none']
4227    endif
4228  endif
4229  if bindgen.version().version_compare('>=0.66.0')
4230    bindgen_args_common += ['--rust-target', '1.59']
4231  endif
4232  if bindgen.version().version_compare('<0.61.0')
4233    # default in 0.61+
4234    bindgen_args_common += ['--size_t-is-usize']
4235  else
4236    bindgen_args_common += ['--merge-extern-blocks']
4237  endif
4238  subdir('rust')
4239endif
4240
4241
4242feature_to_c = find_program('scripts/feature_to_c.py')
4243rust_root_crate = find_program('scripts/rust/rust_root_crate.sh')
4244
4245if host_os == 'darwin'
4246  entitlement = find_program('scripts/entitlement.sh')
4247endif
4248
4249traceable = []
4250emulators = {}
4251foreach target : target_dirs
4252  config_target = config_target_mak[target]
4253  target_name = config_target['TARGET_NAME']
4254  target_base_arch = config_target['TARGET_BASE_ARCH']
4255  arch_srcs = [config_target_h[target]]
4256  arch_deps = []
4257  c_args = ['-DCOMPILING_PER_TARGET',
4258            '-DCONFIG_TARGET="@0@-config-target.h"'.format(target),
4259  ]
4260  link_args = emulator_link_args
4261
4262  target_inc = [include_directories('target' / config_target['TARGET_BASE_ARCH'])]
4263  if host_os == 'linux'
4264    target_inc += include_directories('linux-headers', is_system: true)
4265  endif
4266  if target.endswith('-softmmu')
4267    target_type='system'
4268    t = target_system_arch[target_base_arch].apply(config_target, strict: false)
4269    arch_srcs += t.sources()
4270    arch_deps += t.dependencies()
4271
4272    hw_dir = target_name == 'sparc64' ? 'sparc64' : target_base_arch
4273    if hw_arch.has_key(hw_dir)
4274      hw = hw_arch[hw_dir].apply(config_target, strict: false)
4275      arch_srcs += hw.sources()
4276      arch_deps += hw.dependencies()
4277    endif
4278
4279    c_args += ['-DCONFIG_DEVICES="@0@-config-devices.h"'.format(target)]
4280    arch_srcs += config_devices_h[target]
4281    link_args += ['@block.syms', '@qemu.syms']
4282  else
4283    abi = config_target['TARGET_ABI_DIR']
4284    target_type='user'
4285    target_inc += common_user_inc
4286    if target_base_arch in target_user_arch
4287      t = target_user_arch[target_base_arch].apply(config_target, strict: false)
4288      arch_srcs += t.sources()
4289      arch_deps += t.dependencies()
4290    endif
4291    if 'CONFIG_LINUX_USER' in config_target
4292      base_dir = 'linux-user'
4293    endif
4294    if 'CONFIG_BSD_USER' in config_target
4295      base_dir = 'bsd-user'
4296      target_inc += include_directories('bsd-user/' / host_os)
4297      target_inc += include_directories('bsd-user/host/' / host_arch)
4298      dir = base_dir / abi
4299      arch_srcs += files(dir / 'signal.c', dir / 'target_arch_cpu.c')
4300    endif
4301    target_inc += include_directories(
4302      base_dir,
4303      base_dir / abi,
4304    )
4305    if 'CONFIG_LINUX_USER' in config_target
4306      dir = base_dir / abi
4307      arch_srcs += files(dir / 'signal.c', dir / 'cpu_loop.c')
4308      if config_target.has_key('TARGET_SYSTBL_ABI')
4309        arch_srcs += \
4310          syscall_nr_generators[abi].process(base_dir / abi / config_target['TARGET_SYSTBL'],
4311                                             extra_args : config_target['TARGET_SYSTBL_ABI'])
4312      endif
4313    endif
4314  endif
4315
4316  if 'TARGET_XML_FILES' in config_target
4317    gdbstub_xml = custom_target(target + '-gdbstub-xml.c',
4318                                output: target + '-gdbstub-xml.c',
4319                                input: files(config_target['TARGET_XML_FILES'].split()),
4320                                command: [feature_to_c, '@INPUT@'],
4321                                capture: true)
4322    arch_srcs += gdbstub_xml
4323  endif
4324
4325  t = target_arch[target_base_arch].apply(config_target, strict: false)
4326  arch_srcs += t.sources()
4327  arch_deps += t.dependencies()
4328
4329  target_common = common_ss.apply(config_target, strict: false)
4330  objects = [common_all.extract_objects(target_common.sources())]
4331  arch_deps += target_common.dependencies()
4332  if target_base_arch in target_common_arch_libs
4333    src = target_common_arch[target_base_arch].apply(config_target, strict: false)
4334    lib = target_common_arch_libs[target_base_arch]
4335    objects += lib.extract_objects(src.sources())
4336    arch_deps += src.dependencies()
4337  endif
4338  if target_type == 'system'
4339    src = system_ss.apply(config_target, strict: false)
4340    objects += libsystem.extract_objects(src.sources())
4341    arch_deps += src.dependencies()
4342  endif
4343  if target_type == 'user'
4344    src = user_ss.apply(config_target, strict: false)
4345    objects += libuser.extract_objects(src.sources())
4346    arch_deps += src.dependencies()
4347  endif
4348  if target_type == 'system' and target_base_arch in target_common_system_arch_libs
4349    src = target_common_system_arch[target_base_arch].apply(config_target, strict: false)
4350    lib = target_common_system_arch_libs[target_base_arch]
4351    objects += lib.extract_objects(src.sources())
4352    arch_deps += src.dependencies()
4353  endif
4354
4355  target_specific = specific_ss.apply(config_target, strict: false)
4356  arch_srcs += target_specific.sources()
4357  arch_deps += target_specific.dependencies()
4358
4359  if have_rust and target_type == 'system'
4360    target_rust = rust_devices_ss.apply(config_target, strict: false)
4361    crates = []
4362    foreach dep : target_rust.dependencies()
4363      crates += dep.get_variable('crate')
4364    endforeach
4365    if crates.length() > 0
4366      rlib_rs = custom_target('rust_' + target.underscorify() + '.rs',
4367                              output: 'rust_' + target.underscorify() + '.rs',
4368                              command: [rust_root_crate, crates],
4369                              capture: true,
4370                              build_by_default: true,
4371                              build_always_stale: true)
4372      rlib = static_library('rust_' + target.underscorify(),
4373                            structured_sources([], {'.': rlib_rs}),
4374                            dependencies: target_rust.dependencies(),
4375                            override_options: ['rust_std=2021', 'build.rust_std=2021'],
4376                            rust_abi: 'c')
4377      arch_deps += declare_dependency(link_whole: [rlib])
4378    endif
4379  endif
4380
4381  # allow using headers from the dependencies but do not include the sources,
4382  # because this emulator only needs those in "objects".  For external
4383  # dependencies, the full dependency is included below in the executable.
4384  lib_deps = []
4385  foreach dep : arch_deps
4386    lib_deps += dep.partial_dependency(compile_args: true, includes: true)
4387  endforeach
4388
4389  lib = static_library('qemu-' + target,
4390                 sources: arch_srcs + genh,
4391                 dependencies: lib_deps,
4392                 objects: objects,
4393                 include_directories: target_inc,
4394                 c_args: c_args,
4395                 build_by_default: false)
4396
4397  if target.endswith('-softmmu')
4398    execs = [{
4399      'name': 'qemu-system-' + target_name,
4400      'win_subsystem': 'console',
4401      'sources': files('system/main.c'),
4402      'dependencies': [sdl]
4403    }]
4404    if host_os == 'windows' and (sdl.found() or gtk.found())
4405      execs += [{
4406        'name': 'qemu-system-' + target_name + 'w',
4407        'win_subsystem': 'windows',
4408        'sources': files('system/main.c'),
4409        'dependencies': [sdl]
4410      }]
4411    endif
4412    if get_option('fuzzing')
4413      specific_fuzz = specific_fuzz_ss.apply(config_target, strict: false)
4414      execs += [{
4415        'name': 'qemu-fuzz-' + target_name,
4416        'win_subsystem': 'console',
4417        'sources': specific_fuzz.sources(),
4418        'dependencies': specific_fuzz.dependencies(),
4419      }]
4420    endif
4421  else
4422    execs = [{
4423      'name': 'qemu-' + target_name,
4424      'win_subsystem': 'console',
4425      'sources': [],
4426      'dependencies': []
4427    }]
4428  endif
4429  foreach exe: execs
4430    exe_name = exe['name']
4431    if host_os == 'darwin'
4432      exe_name += '-unsigned'
4433    endif
4434
4435    emulator = executable(exe_name, exe['sources'],
4436               install: true,
4437               c_args: c_args,
4438               dependencies: arch_deps + exe['dependencies'],
4439               objects: lib.extract_all_objects(recursive: true),
4440               link_depends: [block_syms, qemu_syms],
4441               link_args: link_args,
4442               win_subsystem: exe['win_subsystem'])
4443
4444    if host_os == 'darwin'
4445      icon = 'pc-bios/qemu.rsrc'
4446      build_input = [emulator, files(icon)]
4447      install_input = [
4448        get_option('bindir') / exe_name,
4449        meson.current_source_dir() / icon
4450      ]
4451      if 'CONFIG_HVF' in config_target
4452        entitlements = 'accel/hvf/entitlements.plist'
4453        build_input += files(entitlements)
4454        install_input += meson.current_source_dir() / entitlements
4455      endif
4456
4457      emulators += {exe['name'] : custom_target(exe['name'],
4458                   input: build_input,
4459                   output: exe['name'],
4460                   command: [entitlement, '@OUTPUT@', '@INPUT@'])
4461      }
4462
4463      meson.add_install_script(entitlement, '--install',
4464                               get_option('bindir') / exe['name'],
4465                               install_input)
4466    else
4467      emulators += {exe['name']: emulator}
4468    endif
4469
4470    traceable += [{
4471      'exe': exe['name'],
4472      'probe-prefix': 'qemu.' + target_type + '.' + target_name,
4473    }]
4474
4475  endforeach
4476endforeach
4477
4478# Other build targets
4479
4480if get_option('plugins')
4481  install_headers('include/qemu/qemu-plugin.h')
4482  if host_os == 'windows'
4483    # On windows, we want to deliver the qemu_plugin_api.lib file in the qemu installer,
4484    # so that plugin authors can compile against it.
4485    install_data(win32_qemu_plugin_api_lib, install_dir: 'lib')
4486  endif
4487endif
4488
4489subdir('qga')
4490
4491# Don't build qemu-keymap if xkbcommon is not explicitly enabled
4492# when we don't build tools or system
4493if xkbcommon.found()
4494  # used for the update-keymaps target, so include rules even if !have_tools
4495  qemu_keymap = executable('qemu-keymap', files('qemu-keymap.c', 'ui/input-keymap.c') + genh,
4496                           dependencies: [qemuutil, xkbcommon], install: have_tools)
4497endif
4498
4499if have_tools
4500  qemu_img = executable('qemu-img', [files('qemu-img.c'), hxdep],
4501             link_args: '@block.syms', link_depends: block_syms,
4502             dependencies: [authz, block, crypto, io, qom, qemuutil], install: true)
4503  qemu_io = executable('qemu-io', files('qemu-io.c'),
4504             link_args: '@block.syms', link_depends: block_syms,
4505             dependencies: [block, qemuutil], install: true)
4506  qemu_nbd = executable('qemu-nbd', files('qemu-nbd.c'),
4507               link_args: '@block.syms', link_depends: block_syms,
4508               dependencies: [blockdev, qemuutil, selinux],
4509               install: true)
4510
4511  subdir('storage-daemon')
4512
4513  foreach exe: [ 'qemu-img', 'qemu-io', 'qemu-nbd', 'qemu-storage-daemon']
4514    traceable += [{
4515      'exe': exe,
4516      'probe-prefix': 'qemu.' + exe.substring(5).replace('-', '_')
4517    }]
4518  endforeach
4519
4520  subdir('contrib/elf2dmp')
4521
4522  executable('qemu-edid', files('qemu-edid.c', 'hw/display/edid-generate.c'),
4523             dependencies: [qemuutil, rt],
4524             install: true)
4525
4526  if have_vhost_user
4527    subdir('contrib/vhost-user-blk')
4528    subdir('contrib/vhost-user-gpu')
4529    subdir('contrib/vhost-user-input')
4530    subdir('contrib/vhost-user-scsi')
4531  endif
4532
4533  if host_os == 'linux'
4534    executable('qemu-bridge-helper', files('qemu-bridge-helper.c'),
4535               dependencies: [qemuutil, libcap_ng],
4536               install: true,
4537               install_dir: get_option('libexecdir'))
4538
4539    executable('qemu-pr-helper', files('scsi/qemu-pr-helper.c', 'scsi/utils.c'),
4540               dependencies: [authz, crypto, io, qom, qemuutil,
4541                              libcap_ng, mpathpersist],
4542               install: true)
4543
4544    if cpu in ['x86', 'x86_64']
4545      executable('qemu-vmsr-helper', files('tools/i386/qemu-vmsr-helper.c'),
4546               dependencies: [authz, crypto, io, qom, qemuutil,
4547                              libcap_ng, mpathpersist],
4548               install: true)
4549    endif
4550  endif
4551
4552  if have_ivshmem
4553    subdir('contrib/ivshmem-client')
4554    subdir('contrib/ivshmem-server')
4555  endif
4556endif
4557
4558if stap.found()
4559  foreach t: traceable
4560    foreach stp: [
4561      {'ext': '.stp-build', 'fmt': 'stap', 'bin': meson.current_build_dir() / t['exe'], 'install': false},
4562      {'ext': '.stp', 'fmt': 'stap', 'bin': get_option('prefix') / get_option('bindir') / t['exe'], 'install': true},
4563      {'ext': '-simpletrace.stp', 'fmt': 'simpletrace-stap', 'bin': '', 'install': true},
4564      {'ext': '-log.stp', 'fmt': 'log-stap', 'bin': '', 'install': true},
4565    ]
4566      cmd = [
4567        tracetool, '--group=all', '--format=' + stp['fmt'],
4568        '--binary=' + stp['bin'],
4569        '--probe-prefix=' + t['probe-prefix'],
4570        '@INPUT@', '@OUTPUT@'
4571      ]
4572
4573      custom_target(t['exe'] + stp['ext'],
4574                    input: trace_events_all,
4575                    output: t['exe'] + stp['ext'],
4576                    install: stp['install'],
4577                    install_dir: get_option('datadir') / 'systemtap/tapset',
4578                    command: cmd,
4579                    depend_files: tracetool_depends)
4580    endforeach
4581  endforeach
4582endif
4583
4584subdir('scripts')
4585subdir('tools')
4586subdir('pc-bios')
4587subdir('docs')
4588# Tests are disabled on emscripten because they rely on host features that aren't
4589# supported by emscripten (e.g. fork and unix socket).
4590if host_os != 'emscripten'
4591  subdir('tests')
4592endif
4593if gtk.found()
4594  subdir('po')
4595endif
4596
4597if host_machine.system() == 'windows'
4598  nsis_cmd = [
4599    find_program('scripts/nsis.py'),
4600    '@OUTPUT@',
4601    get_option('prefix'),
4602    meson.current_source_dir(),
4603    glib_pc.get_variable('bindir'),
4604    host_machine.cpu(),
4605    '--',
4606    '-DDISPLAYVERSION=' + meson.project_version(),
4607  ]
4608  if build_docs
4609    nsis_cmd += '-DCONFIG_DOCUMENTATION=y'
4610  endif
4611  if gtk.found()
4612    nsis_cmd += '-DCONFIG_GTK=y'
4613  endif
4614
4615  nsis = custom_target('nsis',
4616                       output: 'qemu-setup-' + meson.project_version() + '.exe',
4617                       input: files('qemu.nsi'),
4618                       build_always_stale: true,
4619                       command: nsis_cmd + ['@INPUT@'])
4620  alias_target('installer', nsis)
4621endif
4622
4623#########################
4624# Configuration summary #
4625#########################
4626
4627# Build environment
4628summary_info = {}
4629summary_info += {'Build directory':   meson.current_build_dir()}
4630summary_info += {'Source path':       meson.current_source_dir()}
4631summary_info += {'Download dependencies': get_option('wrap_mode') != 'nodownload'}
4632summary(summary_info, bool_yn: true, section: 'Build environment')
4633
4634# Directories
4635summary_info += {'Install prefix':    get_option('prefix')}
4636summary_info += {'BIOS directory':    qemu_datadir}
4637pathsep = host_os == 'windows' ? ';' : ':'
4638summary_info += {'firmware path':     pathsep.join(get_option('qemu_firmwarepath'))}
4639summary_info += {'binary directory':  get_option('prefix') / get_option('bindir')}
4640summary_info += {'library directory': get_option('prefix') / get_option('libdir')}
4641summary_info += {'module directory':  qemu_moddir}
4642summary_info += {'libexec directory': get_option('prefix') / get_option('libexecdir')}
4643summary_info += {'include directory': get_option('prefix') / get_option('includedir')}
4644summary_info += {'config directory':  get_option('prefix') / get_option('sysconfdir')}
4645if host_os != 'windows'
4646  summary_info += {'local state directory': get_option('prefix') / get_option('localstatedir')}
4647  summary_info += {'Manual directory':      get_option('prefix') / get_option('mandir')}
4648else
4649  summary_info += {'local state directory': 'queried at runtime'}
4650endif
4651summary_info += {'Doc directory':     get_option('prefix') / get_option('docdir')}
4652summary(summary_info, bool_yn: true, section: 'Directories')
4653
4654# Host binaries
4655summary_info = {}
4656summary_info += {'python':            '@0@ (version: @1@)'.format(python.full_path(), python.language_version())}
4657summary_info += {'sphinx-build':      sphinx_build}
4658
4659# FIXME: the [binaries] section of machine files, which can be probed
4660# with find_program(), would be great for passing gdb and genisoimage
4661# paths from configure to Meson.  However, there seems to be no way to
4662# hide a program (for example if gdb is too old).
4663if config_host.has_key('GDB')
4664  summary_info += {'gdb':             config_host['GDB']}
4665endif
4666summary_info += {'iasl':              iasl}
4667summary_info += {'genisoimage':       config_host['GENISOIMAGE']}
4668if host_os == 'windows' and have_ga
4669  summary_info += {'wixl':            wixl}
4670endif
4671if slirp.found() and have_system
4672  summary_info += {'smbd':            have_slirp_smbd ? smbd_path : false}
4673endif
4674summary(summary_info, bool_yn: true, section: 'Host binaries')
4675
4676# Configurable features
4677summary_info = {}
4678summary_info += {'Documentation':     build_docs}
4679summary_info += {'system-mode emulation': have_system}
4680summary_info += {'user-mode emulation': have_user}
4681summary_info += {'block layer':       have_block}
4682summary_info += {'Install blobs':     get_option('install_blobs')}
4683summary_info += {'module support':    enable_modules}
4684if enable_modules
4685  summary_info += {'alternative module path': get_option('module_upgrades')}
4686endif
4687summary_info += {'fuzzing support':   get_option('fuzzing')}
4688if have_system
4689  summary_info += {'Audio drivers':     ' '.join(audio_drivers_selected)}
4690endif
4691summary_info += {'Trace backends':    ','.join(get_option('trace_backends'))}
4692if 'simple' in get_option('trace_backends')
4693  summary_info += {'Trace output file': get_option('trace_file') + '-<pid>'}
4694endif
4695summary_info += {'QOM debugging':     get_option('qom_cast_debug')}
4696summary_info += {'Relocatable install': get_option('relocatable')}
4697summary_info += {'vhost-kernel support': have_vhost_kernel}
4698summary_info += {'vhost-net support': have_vhost_net}
4699summary_info += {'vhost-user support': have_vhost_user}
4700summary_info += {'vhost-user-crypto support': have_vhost_user_crypto}
4701summary_info += {'vhost-user-blk server support': have_vhost_user_blk_server}
4702summary_info += {'vhost-vdpa support': have_vhost_vdpa}
4703summary_info += {'build guest agent': have_ga}
4704summary(summary_info, bool_yn: true, section: 'Configurable features')
4705
4706# Compilation information
4707summary_info = {}
4708summary_info += {'host CPU':          cpu}
4709summary_info += {'host endianness':   build_machine.endian()}
4710summary_info += {'C compiler':        ' '.join(meson.get_compiler('c').cmd_array())}
4711summary_info += {'Host C compiler':   ' '.join(meson.get_compiler('c', native: true).cmd_array())}
4712if 'cpp' in all_languages
4713  summary_info += {'C++ compiler':    ' '.join(meson.get_compiler('cpp').cmd_array())}
4714else
4715  summary_info += {'C++ compiler':      false}
4716endif
4717if 'objc' in all_languages
4718  summary_info += {'Objective-C compiler': ' '.join(meson.get_compiler('objc').cmd_array())}
4719else
4720  summary_info += {'Objective-C compiler': false}
4721endif
4722summary_info += {'Rust support':      have_rust}
4723if have_rust
4724  summary_info += {'Rust target':     config_host['RUST_TARGET_TRIPLE']}
4725  summary_info += {'rustc':           ' '.join(rustc.cmd_array())}
4726  summary_info += {'rustc version':   rustc.version()}
4727  summary_info += {'rustdoc':         rustdoc}
4728  summary_info += {'bindgen':         bindgen.full_path()}
4729  summary_info += {'bindgen version': bindgen.version()}
4730endif
4731option_cflags = (get_option('debug') ? ['-g'] : [])
4732if get_option('optimization') != 'plain'
4733  option_cflags += ['-O' + get_option('optimization')]
4734endif
4735summary_info += {'CFLAGS':            ' '.join(get_option('c_args') + option_cflags)}
4736if 'cpp' in all_languages
4737  summary_info += {'CXXFLAGS':        ' '.join(get_option('cpp_args') + option_cflags)}
4738endif
4739if 'objc' in all_languages
4740  summary_info += {'OBJCFLAGS':       ' '.join(get_option('objc_args') + option_cflags)}
4741endif
4742link_args = get_option('c_link_args')
4743if link_args.length() > 0
4744  summary_info += {'LDFLAGS':         ' '.join(link_args)}
4745endif
4746summary_info += {'QEMU_CFLAGS':       ' '.join(qemu_common_flags + qemu_cflags)}
4747if 'cpp' in all_languages
4748  summary_info += {'QEMU_CXXFLAGS':     ' '.join(qemu_common_flags + qemu_cxxflags)}
4749endif
4750if 'objc' in all_languages
4751  summary_info += {'QEMU_OBJCFLAGS':    ' '.join(qemu_common_flags)}
4752endif
4753summary_info += {'QEMU_LDFLAGS':      ' '.join(qemu_ldflags)}
4754summary_info += {'link-time optimization (LTO)': get_option('b_lto')}
4755summary_info += {'PIE':               get_option('b_pie')}
4756summary_info += {'static build':      get_option('prefer_static')}
4757summary_info += {'malloc trim support': has_malloc_trim}
4758summary_info += {'membarrier':        have_membarrier}
4759summary_info += {'debug graph lock':  get_option('debug_graph_lock')}
4760summary_info += {'debug stack usage': get_option('debug_stack_usage')}
4761summary_info += {'mutex debugging':   get_option('debug_mutex')}
4762summary_info += {'memory allocator':  get_option('malloc')}
4763summary_info += {'avx2 optimization': config_host_data.get('CONFIG_AVX2_OPT')}
4764summary_info += {'avx512bw optimization': config_host_data.get('CONFIG_AVX512BW_OPT')}
4765summary_info += {'gcov':              get_option('b_coverage')}
4766summary_info += {'thread sanitizer':  get_option('tsan')}
4767summary_info += {'CFI support':       get_option('cfi')}
4768if get_option('cfi')
4769  summary_info += {'CFI debug support': get_option('cfi_debug')}
4770endif
4771summary_info += {'strip binaries':    get_option('strip')}
4772summary_info += {'sparse':            sparse}
4773summary_info += {'mingw32 support':   host_os == 'windows'}
4774summary(summary_info, bool_yn: true, section: 'Compilation')
4775
4776# snarf the cross-compilation information for tests
4777summary_info = {}
4778have_cross = false
4779foreach target: target_dirs
4780  tcg_mak = meson.current_build_dir() / 'tests/tcg' / target / 'config-target.mak'
4781  if fs.exists(tcg_mak)
4782    config_cross_tcg = keyval.load(tcg_mak)
4783    if 'CC' in config_cross_tcg
4784      summary_info += {config_cross_tcg['TARGET_NAME']: config_cross_tcg['CC']}
4785      have_cross = true
4786    endif
4787  endif
4788endforeach
4789if have_cross
4790  summary(summary_info, bool_yn: true, section: 'Cross compilers')
4791endif
4792
4793# Targets and accelerators
4794summary_info = {}
4795if have_system
4796  summary_info += {'KVM support':       config_all_accel.has_key('CONFIG_KVM')}
4797  summary_info += {'HVF support':       config_all_accel.has_key('CONFIG_HVF')}
4798  summary_info += {'WHPX support':      config_all_accel.has_key('CONFIG_WHPX')}
4799  summary_info += {'NVMM support':      config_all_accel.has_key('CONFIG_NVMM')}
4800  summary_info += {'Xen support':       xen.found()}
4801  if xen.found()
4802    summary_info += {'xen ctrl version':  xen.version()}
4803  endif
4804  summary_info += {'Xen emulation':     config_all_devices.has_key('CONFIG_XEN_EMU')}
4805endif
4806summary_info += {'TCG support':       config_all_accel.has_key('CONFIG_TCG')}
4807if config_all_accel.has_key('CONFIG_TCG')
4808  if get_option('tcg_interpreter')
4809    summary_info += {'TCG backend':   'TCI (TCG with bytecode interpreter, slow)'}
4810  else
4811    summary_info += {'TCG backend':   'native (@0@)'.format(cpu)}
4812  endif
4813  summary_info += {'TCG plugins':       get_option('plugins')}
4814  summary_info += {'TCG debug enabled': get_option('debug_tcg')}
4815  if have_linux_user or have_bsd_user
4816    summary_info += {'syscall buffer debugging support': get_option('debug_remap')}
4817  endif
4818endif
4819summary_info += {'target list':       ' '.join(target_dirs)}
4820if have_system
4821  summary_info += {'default devices':   get_option('default_devices')}
4822  summary_info += {'out of process emulation': multiprocess_allowed}
4823  summary_info += {'vfio-user server': vfio_user_server_allowed}
4824endif
4825summary(summary_info, bool_yn: true, section: 'Targets and accelerators')
4826
4827# Block layer
4828summary_info = {}
4829summary_info += {'coroutine backend': coroutine_backend}
4830summary_info += {'coroutine pool':    have_coroutine_pool}
4831if have_block
4832  summary_info += {'Block whitelist (rw)': get_option('block_drv_rw_whitelist')}
4833  summary_info += {'Block whitelist (ro)': get_option('block_drv_ro_whitelist')}
4834  summary_info += {'Use block whitelist in tools': get_option('block_drv_whitelist_in_tools')}
4835  summary_info += {'VirtFS (9P) support':    have_virtfs}
4836  summary_info += {'replication support': config_host_data.get('CONFIG_REPLICATION')}
4837  summary_info += {'bochs support':     get_option('bochs').allowed()}
4838  summary_info += {'cloop support':     get_option('cloop').allowed()}
4839  summary_info += {'dmg support':       get_option('dmg').allowed()}
4840  summary_info += {'qcow v1 support':   get_option('qcow1').allowed()}
4841  summary_info += {'vdi support':       get_option('vdi').allowed()}
4842  summary_info += {'vhdx support':      get_option('vhdx').allowed()}
4843  summary_info += {'vmdk support':      get_option('vmdk').allowed()}
4844  summary_info += {'vpc support':       get_option('vpc').allowed()}
4845  summary_info += {'vvfat support':     get_option('vvfat').allowed()}
4846  summary_info += {'qed support':       get_option('qed').allowed()}
4847  summary_info += {'parallels support': get_option('parallels').allowed()}
4848  summary_info += {'FUSE exports':      fuse}
4849  summary_info += {'VDUSE block exports': have_vduse_blk_export}
4850endif
4851summary(summary_info, bool_yn: true, section: 'Block layer support')
4852
4853# Crypto
4854summary_info = {}
4855summary_info += {'TLS priority':      get_option('tls_priority')}
4856summary_info += {'GNUTLS support':    gnutls}
4857if gnutls.found()
4858  summary_info += {'  GNUTLS crypto':   gnutls_crypto.found()}
4859endif
4860summary_info += {'libgcrypt':         gcrypt}
4861summary_info += {'nettle':            nettle}
4862if nettle.found()
4863   summary_info += {'  XTS':             xts != 'private'}
4864endif
4865summary_info += {'SM4 ALG support':   crypto_sm4}
4866summary_info += {'SM3 ALG support':   crypto_sm3}
4867summary_info += {'AF_ALG support':    have_afalg}
4868summary_info += {'rng-none':          get_option('rng_none')}
4869summary_info += {'Linux keyring':     have_keyring}
4870summary_info += {'Linux keyutils':    keyutils}
4871summary(summary_info, bool_yn: true, section: 'Crypto')
4872
4873# UI
4874summary_info = {}
4875if host_os == 'darwin'
4876  summary_info += {'Cocoa support':           cocoa}
4877endif
4878summary_info += {'D-Bus display':     dbus_display}
4879summary_info += {'SDL support':       sdl}
4880summary_info += {'SDL image support': sdl_image}
4881summary_info += {'GTK support':       gtk}
4882summary_info += {'pixman':            pixman}
4883summary_info += {'VTE support':       vte}
4884summary_info += {'PNG support':       png}
4885summary_info += {'VNC support':       vnc}
4886if vnc.found()
4887  summary_info += {'VNC SASL support':  sasl}
4888  summary_info += {'VNC JPEG support':  jpeg}
4889endif
4890summary_info += {'spice protocol support': spice_protocol}
4891if spice_protocol.found()
4892  summary_info += {'  spice server support': spice}
4893endif
4894summary_info += {'curses support':    curses}
4895summary_info += {'brlapi support':    brlapi}
4896summary(summary_info, bool_yn: true, section: 'User interface')
4897
4898# Graphics backends
4899summary_info = {}
4900summary_info += {'VirGL support':     virgl}
4901summary_info += {'Rutabaga support':  rutabaga}
4902summary(summary_info, bool_yn: true, section: 'Graphics backends')
4903
4904# Audio backends
4905summary_info = {}
4906if host_os not in ['darwin', 'haiku', 'windows']
4907  summary_info += {'OSS support':     oss}
4908  summary_info += {'sndio support':   sndio}
4909elif host_os == 'darwin'
4910  summary_info += {'CoreAudio support': coreaudio}
4911elif host_os == 'windows'
4912  summary_info += {'DirectSound support': dsound}
4913endif
4914if host_os == 'linux'
4915  summary_info += {'ALSA support':    alsa}
4916  summary_info += {'PulseAudio support': pulse}
4917endif
4918summary_info += {'PipeWire support':  pipewire}
4919summary_info += {'JACK support':      jack}
4920summary(summary_info, bool_yn: true, section: 'Audio backends')
4921
4922# Network backends
4923summary_info = {}
4924if host_os == 'darwin'
4925  summary_info += {'vmnet.framework support': vmnet}
4926endif
4927summary_info += {'AF_XDP support':    libxdp}
4928summary_info += {'slirp support':     slirp}
4929summary_info += {'vde support':       vde}
4930summary_info += {'netmap support':    have_netmap}
4931summary_info += {'l2tpv3 support':    have_l2tpv3}
4932summary(summary_info, bool_yn: true, section: 'Network backends')
4933
4934# Libraries
4935summary_info = {}
4936summary_info += {'libtasn1':          tasn1}
4937summary_info += {'PAM':               pam}
4938summary_info += {'iconv support':     iconv}
4939summary_info += {'blkio support':     blkio}
4940summary_info += {'curl support':      curl}
4941summary_info += {'Multipath support': mpathpersist}
4942summary_info += {'Linux AIO support': libaio}
4943summary_info += {'Linux io_uring support': linux_io_uring}
4944summary_info += {'ATTR/XATTR support': libattr}
4945summary_info += {'RDMA support':      rdma}
4946summary_info += {'fdt support':       fdt_opt == 'internal' ? 'internal' : fdt}
4947summary_info += {'libcap-ng support': libcap_ng}
4948summary_info += {'bpf support':       libbpf}
4949summary_info += {'rbd support':       rbd}
4950summary_info += {'smartcard support': cacard}
4951summary_info += {'U2F support':       u2f}
4952summary_info += {'libusb':            libusb}
4953summary_info += {'usb net redir':     usbredir}
4954summary_info += {'OpenGL support (epoxy)': opengl}
4955summary_info += {'GBM':               gbm}
4956summary_info += {'libiscsi support':  libiscsi}
4957summary_info += {'libnfs support':    libnfs}
4958if host_os == 'windows'
4959  if have_ga
4960    summary_info += {'QGA VSS support':   have_qga_vss}
4961  endif
4962endif
4963summary_info += {'seccomp support':   seccomp}
4964summary_info += {'GlusterFS support': glusterfs}
4965summary_info += {'hv-balloon support': hv_balloon}
4966summary_info += {'TPM support':       have_tpm}
4967summary_info += {'libssh support':    libssh}
4968summary_info += {'lzo support':       lzo}
4969summary_info += {'snappy support':    snappy}
4970summary_info += {'bzip2 support':     libbzip2}
4971summary_info += {'lzfse support':     liblzfse}
4972summary_info += {'zstd support':      zstd}
4973summary_info += {'Query Processing Library support': qpl}
4974summary_info += {'UADK Library support': uadk}
4975summary_info += {'qatzip support':    qatzip}
4976summary_info += {'NUMA host support': numa}
4977summary_info += {'capstone':          capstone}
4978summary_info += {'libpmem support':   libpmem}
4979summary_info += {'libdaxctl support': libdaxctl}
4980summary_info += {'libcbor support':   libcbor}
4981summary_info += {'libudev':           libudev}
4982# Dummy dependency, keep .found()
4983summary_info += {'FUSE lseek':        fuse_lseek.found()}
4984summary_info += {'selinux':           selinux}
4985summary_info += {'libdw':             libdw}
4986if host_os == 'freebsd'
4987  summary_info += {'libinotify-kqueue': inotify}
4988endif
4989if host_os == 'darwin'
4990  summary_info += {'ParavirtualizedGraphics support': pvg}
4991endif
4992summary_info += {'valgrind':          valgrind}
4993summary(summary_info, bool_yn: true, section: 'Dependencies')
4994
4995if host_arch == 'unknown'
4996  message()
4997  warning('UNSUPPORTED HOST CPU')
4998  message()
4999  message('Support for CPU host architecture ' + cpu + ' is not currently')
5000  message('maintained. The QEMU project does not guarantee that QEMU will')
5001  message('compile or work on this host CPU. You can help by volunteering')
5002  message('to maintain it and providing a build host for our continuous')
5003  message('integration setup.')
5004  if have_tcg
5005    message()
5006    message('configure has succeeded and you can continue to build, but')
5007    message('QEMU will use a slow interpreter to emulate the target CPU.')
5008  endif
5009elif host_long_bits < 64
5010  message()
5011  warning('DEPRECATED HOST CPU')
5012  message()
5013  message('Support for 32-bit CPU host architecture ' + cpu + ' is going')
5014  message('to be dropped in a future QEMU release.')
5015endif
5016
5017if not supported_oses.contains(host_os)
5018  message()
5019  warning('UNSUPPORTED HOST OS')
5020  message()
5021  message('Support for host OS ' + host_os + 'is not currently maintained.')
5022  message('configure has succeeded and you can continue to build, but')
5023  message('the QEMU project does not guarantee that QEMU will compile or')
5024  message('work on this operating system. You can help by volunteering')
5025  message('to maintain it and providing a build host for our continuous')
5026  message('integration setup. This will ensure that future versions of QEMU')
5027  message('will keep working on ' + host_os + '.')
5028endif
5029
5030if host_arch == 'unknown' or not supported_oses.contains(host_os)
5031  message()
5032  message('If you want to help supporting QEMU on this platform, please')
5033  message('contact the developers at qemu-devel@nongnu.org.')
5034endif
5035
5036actually_reloc = get_option('relocatable')
5037# check if get_relocated_path() is actually able to relocate paths
5038if get_option('relocatable') and \
5039  not (get_option('prefix') / get_option('bindir')).startswith(get_option('prefix') / '')
5040  message()
5041  warning('bindir not included within prefix, the installation will not be relocatable.')
5042  actually_reloc = false
5043endif
5044if not actually_reloc and (host_os == 'windows' or get_option('relocatable'))
5045  if host_os == 'windows'
5046    message()
5047    warning('Windows installs should usually be relocatable.')
5048  endif
5049  message()
5050  message('QEMU will have to be installed under ' + get_option('prefix') + '.')
5051  message('Use --disable-relocatable to remove this warning.')
5052endif
5053