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