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