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