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