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