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