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