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