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