xref: /openbmc/qemu/meson.build (revision c4fa97c7f216fc80b09a5d32be847ff8d502cba6)
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  .require(gio.found(), error_message: 'passt requires gio') \
1291  .allowed()
1292
1293vde = not_found
1294if not get_option('vde').auto() or have_system or have_tools
1295  vde = cc.find_library('vdeplug', has_headers: ['libvdeplug.h'],
1296                           required: get_option('vde'))
1297endif
1298if vde.found() and not cc.links('''
1299   #include <libvdeplug.h>
1300   int main(void)
1301   {
1302     struct vde_open_args a = {0, 0, 0};
1303     char s[] = "";
1304     vde_open(s, s, &a);
1305     return 0;
1306   }''', dependencies: vde)
1307  vde = not_found
1308  if get_option('cap_ng').enabled()
1309    error('could not link libvdeplug')
1310  else
1311    warning('could not link libvdeplug, disabling')
1312  endif
1313endif
1314
1315pulse = not_found
1316if not get_option('pa').auto() or (host_os == 'linux' and have_system)
1317  pulse = dependency('libpulse', required: get_option('pa'),
1318                     method: 'pkg-config')
1319endif
1320alsa = not_found
1321if not get_option('alsa').auto() or (host_os == 'linux' and have_system)
1322  alsa = dependency('alsa', required: get_option('alsa'),
1323                    method: 'pkg-config')
1324endif
1325jack = not_found
1326if not get_option('jack').auto() or have_system
1327  jack = dependency('jack', required: get_option('jack'),
1328                    method: 'pkg-config')
1329endif
1330pipewire = not_found
1331if not get_option('pipewire').auto() or (host_os == 'linux' and have_system)
1332  pipewire = dependency('libpipewire-0.3', version: '>=0.3.60',
1333                    required: get_option('pipewire'),
1334                    method: 'pkg-config')
1335endif
1336sndio = not_found
1337if not get_option('sndio').auto() or have_system
1338  sndio = dependency('sndio', required: get_option('sndio'),
1339                    method: 'pkg-config')
1340endif
1341
1342spice_protocol = not_found
1343if not get_option('spice_protocol').auto() or have_system
1344  spice_protocol = dependency('spice-protocol', version: '>=0.14.0',
1345                              required: get_option('spice_protocol'),
1346                              method: 'pkg-config')
1347endif
1348spice = not_found
1349if get_option('spice') \
1350             .disable_auto_if(not have_system) \
1351             .require(pixman.found(),
1352                      error_message: 'cannot enable SPICE if pixman is not available') \
1353             .allowed()
1354  spice = dependency('spice-server', version: '>=0.14.0',
1355                     required: get_option('spice'),
1356                     method: 'pkg-config')
1357endif
1358spice_headers = spice.partial_dependency(compile_args: true, includes: true)
1359
1360rt = cc.find_library('rt', required: false)
1361
1362libiscsi = not_found
1363if not get_option('libiscsi').auto() or have_block
1364  libiscsi = dependency('libiscsi', version: '>=1.9.0',
1365                         required: get_option('libiscsi'),
1366                         method: 'pkg-config')
1367endif
1368zstd = not_found
1369if not get_option('zstd').auto() or have_block
1370  zstd = dependency('libzstd', version: '>=1.4.0',
1371                    required: get_option('zstd'),
1372                    method: 'pkg-config')
1373endif
1374qpl = not_found
1375if not get_option('qpl').auto() or have_system
1376  qpl = dependency('qpl', version: '>=1.5.0',
1377                    required: get_option('qpl'),
1378                    method: 'pkg-config')
1379endif
1380uadk = not_found
1381if not get_option('uadk').auto() or have_system
1382  libwd = dependency('libwd', version: '>=2.6',
1383                      required: get_option('uadk'),
1384                      method: 'pkg-config')
1385  libwd_comp = dependency('libwd_comp', version: '>=2.6',
1386                           required: get_option('uadk'),
1387                           method: 'pkg-config')
1388  if libwd.found() and libwd_comp.found()
1389     uadk = declare_dependency(dependencies: [libwd, libwd_comp])
1390  endif
1391endif
1392
1393qatzip = not_found
1394if not get_option('qatzip').auto() or have_system
1395  qatzip = dependency('qatzip', version: '>=1.1.2',
1396                      required: get_option('qatzip'),
1397                      method: 'pkg-config')
1398endif
1399
1400virgl = not_found
1401
1402have_vhost_user_gpu = have_tools and host_os == 'linux' and pixman.found()
1403if not get_option('virglrenderer').auto() or have_system or have_vhost_user_gpu
1404  virgl = dependency('virglrenderer',
1405                     method: 'pkg-config',
1406                     required: get_option('virglrenderer'))
1407endif
1408rutabaga = not_found
1409if not get_option('rutabaga_gfx').auto() or have_system or have_vhost_user_gpu
1410  rutabaga = dependency('rutabaga_gfx_ffi',
1411                         method: 'pkg-config',
1412                         required: get_option('rutabaga_gfx'))
1413endif
1414blkio = not_found
1415if not get_option('blkio').auto() or have_block
1416  blkio = dependency('blkio',
1417                     method: 'pkg-config',
1418                     required: get_option('blkio'))
1419endif
1420curl = not_found
1421if not get_option('curl').auto() or have_block
1422  curl = dependency('libcurl', version: '>=7.29.0',
1423                    method: 'pkg-config',
1424                    required: get_option('curl'))
1425endif
1426libudev = not_found
1427if host_os == 'linux' and (have_system or have_tools)
1428  libudev = dependency('libudev',
1429                       method: 'pkg-config',
1430                       required: get_option('libudev'))
1431endif
1432igvm = not_found
1433if not get_option('igvm').auto() or have_system
1434  igvm = dependency('igvm', version: '>= 0.3.0',
1435                    method: 'pkg-config',
1436                    required: get_option('igvm'))
1437endif
1438
1439mpathlibs = [libudev]
1440mpathpersist = not_found
1441if host_os == 'linux' and have_tools and get_option('mpath').allowed()
1442  mpath_test_source = '''
1443    #include <libudev.h>
1444    #include <mpath_persist.h>
1445    unsigned mpath_mx_alloc_len = 1024;
1446    int logsink;
1447    static struct config *multipath_conf;
1448    extern struct udev *udev;
1449    extern struct config *get_multipath_config(void);
1450    extern void put_multipath_config(struct config *conf);
1451    struct udev *udev;
1452    struct config *get_multipath_config(void) { return multipath_conf; }
1453    void put_multipath_config(struct config *conf) { }
1454    int main(void) {
1455        udev = udev_new();
1456        multipath_conf = mpath_lib_init();
1457        return 0;
1458    }'''
1459  libmpathpersist = cc.find_library('mpathpersist',
1460                                    required: get_option('mpath'))
1461  if libmpathpersist.found()
1462    mpathlibs += libmpathpersist
1463    if get_option('prefer_static')
1464      mpathlibs += cc.find_library('devmapper',
1465                                     required: get_option('mpath'))
1466    endif
1467    mpathlibs += cc.find_library('multipath',
1468                                 required: get_option('mpath'))
1469    foreach lib: mpathlibs
1470      if not lib.found()
1471        mpathlibs = []
1472        break
1473      endif
1474    endforeach
1475    if mpathlibs.length() == 0
1476      msg = 'Dependencies missing for libmpathpersist'
1477    elif cc.links(mpath_test_source, dependencies: mpathlibs)
1478      mpathpersist = declare_dependency(dependencies: mpathlibs)
1479    else
1480      msg = 'Cannot detect libmpathpersist API'
1481    endif
1482    if not mpathpersist.found()
1483      if get_option('mpath').enabled()
1484        error(msg)
1485      else
1486        warning(msg + ', disabling')
1487      endif
1488    endif
1489  endif
1490endif
1491
1492iconv = not_found
1493curses = not_found
1494if have_system and get_option('curses').allowed()
1495  curses_test = '''
1496    #ifdef __APPLE__
1497    #define _XOPEN_SOURCE_EXTENDED 1
1498    #endif
1499    #include <locale.h>
1500    #include <curses.h>
1501    #include <wchar.h>
1502    int main(void) {
1503      wchar_t wch = L'w';
1504      setlocale(LC_ALL, "");
1505      resize_term(0, 0);
1506      addwstr(L"wide chars\n");
1507      addnwstr(&wch, 1);
1508      add_wch(WACS_DEGREE);
1509      return 0;
1510    }'''
1511
1512  curses_dep_list = host_os == 'windows' ? ['ncurses', 'ncursesw'] : ['ncursesw']
1513  curses = dependency(curses_dep_list,
1514                      required: false,
1515                      method: 'pkg-config')
1516  msg = get_option('curses').enabled() ? 'curses library not found' : ''
1517  curses_compile_args = ['-DNCURSES_WIDECHAR=1']
1518  if curses.found()
1519    if cc.links(curses_test, args: curses_compile_args, dependencies: [curses])
1520      curses = declare_dependency(compile_args: curses_compile_args, dependencies: [curses],
1521                                  version: curses.version())
1522    else
1523      msg = 'curses package not usable'
1524      curses = not_found
1525    endif
1526  endif
1527  if not curses.found()
1528    has_curses_h = cc.has_header('curses.h', args: curses_compile_args)
1529    if host_os != 'windows' and not has_curses_h
1530      message('Trying with /usr/include/ncursesw')
1531      curses_compile_args += ['-I/usr/include/ncursesw']
1532      has_curses_h = cc.has_header('curses.h', args: curses_compile_args)
1533    endif
1534    if has_curses_h
1535      curses_libname_list = (host_os == 'windows' ? ['pdcurses'] : ['ncursesw', 'cursesw'])
1536      foreach curses_libname : curses_libname_list
1537        libcurses = cc.find_library(curses_libname,
1538                                    required: false)
1539        if libcurses.found()
1540          if cc.links(curses_test, args: curses_compile_args, dependencies: libcurses)
1541            curses = declare_dependency(compile_args: curses_compile_args,
1542                                        dependencies: [libcurses])
1543            break
1544          else
1545            msg = 'curses library not usable'
1546          endif
1547        endif
1548      endforeach
1549    endif
1550  endif
1551  if get_option('iconv').allowed()
1552    foreach link_args : [ ['-liconv'], [] ]
1553      # Programs will be linked with glib and this will bring in libiconv on FreeBSD.
1554      # We need to use libiconv if available because mixing libiconv's headers with
1555      # the system libc does not work.
1556      # However, without adding glib to the dependencies -L/usr/local/lib will not be
1557      # included in the command line and libiconv will not be found.
1558      if cc.links('''
1559        #include <iconv.h>
1560        int main(void) {
1561          iconv_t conv = iconv_open("WCHAR_T", "UCS-2");
1562          return conv != (iconv_t) -1;
1563        }''', args: link_args, dependencies: glib)
1564        iconv = declare_dependency(link_args: link_args, dependencies: glib)
1565        break
1566      endif
1567    endforeach
1568  endif
1569  if curses.found() and not iconv.found()
1570    if get_option('iconv').enabled()
1571      error('iconv not available')
1572    endif
1573    msg = 'iconv required for curses UI but not available'
1574    curses = not_found
1575  endif
1576  if not curses.found() and msg != ''
1577    if get_option('curses').enabled()
1578      error(msg)
1579    else
1580      warning(msg + ', disabling')
1581    endif
1582  endif
1583endif
1584
1585brlapi = not_found
1586if not get_option('brlapi').auto() or have_system
1587  brlapi = cc.find_library('brlapi', has_headers: ['brlapi.h'],
1588                         required: get_option('brlapi'))
1589  if brlapi.found() and not cc.links('''
1590    #include <brlapi.h>
1591    #include <stddef.h>
1592    int main(void) {
1593      return brlapi__openConnection(NULL, NULL, NULL) == BRLAPI_INVALID_FILE_DESCRIPTOR;
1594    }''', dependencies: brlapi)
1595    brlapi = not_found
1596    if get_option('brlapi').enabled()
1597      error('could not link brlapi')
1598    else
1599      warning('could not link brlapi, disabling')
1600    endif
1601  endif
1602endif
1603
1604sdl = not_found
1605if not get_option('sdl').auto() or have_system
1606  sdl = dependency('sdl2', required: get_option('sdl'))
1607  sdl_image = not_found
1608endif
1609if sdl.found()
1610  # Some versions of SDL have problems with -Wundef
1611  if not cc.compiles('''
1612                     #include <SDL.h>
1613                     #include <SDL_syswm.h>
1614                     int main(int argc, char *argv[]) { return 0; }
1615                     ''', dependencies: sdl, args: '-Werror=undef')
1616    sdl = declare_dependency(compile_args: '-Wno-undef',
1617                             dependencies: sdl,
1618                             version: sdl.version())
1619  endif
1620  sdl_image = dependency('SDL2_image', required: get_option('sdl_image'),
1621                         method: 'pkg-config')
1622else
1623  if get_option('sdl_image').enabled()
1624    error('sdl-image required, but SDL was @0@'.format(
1625          get_option('sdl').disabled() ? 'disabled' : 'not found'))
1626  endif
1627  sdl_image = not_found
1628endif
1629
1630rbd = not_found
1631if not get_option('rbd').auto() or have_block
1632  librados = cc.find_library('rados', required: get_option('rbd'))
1633  librbd = cc.find_library('rbd', has_headers: ['rbd/librbd.h'],
1634                           required: get_option('rbd'))
1635  if librados.found() and librbd.found()
1636    if cc.links('''
1637      #include <stdio.h>
1638      #include <rbd/librbd.h>
1639      int main(void) {
1640        rados_t cluster;
1641        rados_create(&cluster, NULL);
1642        #if LIBRBD_VERSION_CODE < LIBRBD_VERSION(1, 12, 0)
1643        #error
1644        #endif
1645        return 0;
1646      }''', dependencies: [librbd, librados])
1647      rbd = declare_dependency(dependencies: [librbd, librados])
1648    elif get_option('rbd').enabled()
1649      error('librbd >= 1.12.0 required')
1650    else
1651      warning('librbd >= 1.12.0 not found, disabling')
1652    endif
1653  endif
1654endif
1655
1656glusterfs = not_found
1657glusterfs_ftruncate_has_stat = false
1658glusterfs_iocb_has_stat = false
1659if not get_option('glusterfs').auto() or have_block
1660  glusterfs = dependency('glusterfs-api', version: '>=3',
1661                         required: get_option('glusterfs'),
1662                         method: 'pkg-config')
1663  if glusterfs.found()
1664    glusterfs_ftruncate_has_stat = cc.links('''
1665      #include <glusterfs/api/glfs.h>
1666
1667      int
1668      main(void)
1669      {
1670          /* new glfs_ftruncate() passes two additional args */
1671          return glfs_ftruncate(NULL, 0, NULL, NULL);
1672      }
1673    ''', dependencies: glusterfs)
1674    glusterfs_iocb_has_stat = cc.links('''
1675      #include <glusterfs/api/glfs.h>
1676
1677      /* new glfs_io_cbk() passes two additional glfs_stat structs */
1678      static void
1679      glusterfs_iocb(glfs_fd_t *fd, ssize_t ret, struct glfs_stat *prestat, struct glfs_stat *poststat, void *data)
1680      {}
1681
1682      int
1683      main(void)
1684      {
1685          glfs_io_cbk iocb = &glusterfs_iocb;
1686          iocb(NULL, 0 , NULL, NULL, NULL);
1687          return 0;
1688      }
1689    ''', dependencies: glusterfs)
1690  endif
1691endif
1692
1693hv_balloon = false
1694if get_option('hv_balloon').allowed() and have_system
1695  if cc.links('''
1696    #include <string.h>
1697    #include <gmodule.h>
1698    int main(void) {
1699        GTree *tree;
1700
1701        tree = g_tree_new((GCompareFunc)strcmp);
1702        (void)g_tree_node_first(tree);
1703        g_tree_destroy(tree);
1704        return 0;
1705    }
1706  ''', dependencies: glib)
1707    hv_balloon = true
1708  else
1709    if get_option('hv_balloon').enabled()
1710      error('could not enable hv-balloon, update your glib')
1711    else
1712      warning('could not find glib support for hv-balloon, disabling')
1713    endif
1714  endif
1715endif
1716
1717libssh = not_found
1718if not get_option('libssh').auto() or have_block
1719  libssh = dependency('libssh', version: '>=0.8.7',
1720                    method: 'pkg-config',
1721                    required: get_option('libssh'))
1722endif
1723
1724libbzip2 = not_found
1725if not get_option('bzip2').auto() or have_block
1726  libbzip2 = cc.find_library('bz2', has_headers: ['bzlib.h'],
1727                             required: get_option('bzip2'))
1728  if libbzip2.found() and not cc.links('''
1729     #include <bzlib.h>
1730     int main(void) { BZ2_bzlibVersion(); return 0; }''', dependencies: libbzip2)
1731    libbzip2 = not_found
1732    if get_option('bzip2').enabled()
1733      error('could not link libbzip2')
1734    else
1735      warning('could not link libbzip2, disabling')
1736    endif
1737  endif
1738endif
1739
1740liblzfse = not_found
1741if not get_option('lzfse').auto() or have_block
1742  liblzfse = cc.find_library('lzfse', has_headers: ['lzfse.h'],
1743                             required: get_option('lzfse'))
1744endif
1745if liblzfse.found() and not cc.links('''
1746   #include <lzfse.h>
1747   int main(void) { lzfse_decode_scratch_size(); return 0; }''', dependencies: liblzfse)
1748  liblzfse = not_found
1749  if get_option('lzfse').enabled()
1750    error('could not link liblzfse')
1751  else
1752    warning('could not link liblzfse, disabling')
1753  endif
1754endif
1755
1756oss = not_found
1757if get_option('oss').allowed() and have_system
1758  if not cc.has_header('sys/soundcard.h')
1759    # not found
1760  elif host_os == 'netbsd'
1761    oss = cc.find_library('ossaudio', required: get_option('oss'))
1762  else
1763    oss = declare_dependency()
1764  endif
1765
1766  if not oss.found()
1767    if get_option('oss').enabled()
1768      error('OSS not found')
1769    endif
1770  endif
1771endif
1772dsound = not_found
1773if not get_option('dsound').auto() or (host_os == 'windows' and have_system)
1774  if cc.has_header('dsound.h')
1775    dsound = declare_dependency(link_args: ['-lole32', '-ldxguid'])
1776  endif
1777
1778  if not dsound.found()
1779    if get_option('dsound').enabled()
1780      error('DirectSound not found')
1781    endif
1782  endif
1783endif
1784
1785coreaudio = not_found
1786if not get_option('coreaudio').auto() or (host_os == 'darwin' and have_system)
1787  coreaudio = dependency('appleframeworks', modules: 'CoreAudio',
1788                         required: get_option('coreaudio'))
1789endif
1790
1791opengl = not_found
1792if not get_option('opengl').auto() or have_system or have_vhost_user_gpu
1793  epoxy = dependency('epoxy', method: 'pkg-config',
1794                      required: get_option('opengl'))
1795  if cc.has_header('epoxy/egl.h', dependencies: epoxy)
1796    opengl = epoxy
1797  elif get_option('opengl').enabled()
1798    error('epoxy/egl.h not found')
1799  endif
1800endif
1801gbm = not_found
1802if (have_system or have_tools) and (virgl.found() or opengl.found())
1803  gbm = dependency('gbm', method: 'pkg-config', required: false)
1804endif
1805have_vhost_user_gpu = have_vhost_user_gpu and virgl.found() and opengl.found() and gbm.found()
1806
1807libcbor = not_found
1808if not get_option('libcbor').auto() or have_system
1809  libcbor = dependency('libcbor', version: '>=0.7.0',
1810                       required: get_option('libcbor'))
1811endif
1812
1813gnutls = not_found
1814gnutls_crypto = not_found
1815gnutls_bug1717_workaround = false
1816if get_option('gnutls').enabled() or (get_option('gnutls').auto() and have_system)
1817  # For general TLS support our min gnutls matches
1818  # that implied by our platform support matrix
1819  #
1820  # For the crypto backends, we look for a newer
1821  # gnutls:
1822  #
1823  #   Version 3.6.8  is needed to get XTS
1824  #   Version 3.6.13 is needed to get PBKDF
1825  #   Version 3.6.14 is needed to get HW accelerated XTS
1826  #
1827  # If newer enough gnutls isn't available, we can
1828  # still use a different crypto backend to satisfy
1829  # the platform support requirements
1830  gnutls_crypto = dependency('gnutls', version: '>=3.6.14',
1831                             method: 'pkg-config',
1832                             required: false)
1833  if gnutls_crypto.found()
1834    gnutls = gnutls_crypto
1835  else
1836    # Our min version if all we need is TLS
1837    gnutls = dependency('gnutls', version: '>=3.5.18',
1838                        method: 'pkg-config',
1839                        required: get_option('gnutls'))
1840  endif
1841
1842  #if gnutls.found() and not get_option('gnutls-bug1717-workaround').disabled()
1843    # XXX: when bug 1717 is resolved, add logic to probe for
1844    # the GNUTLS fixed version number to handle the 'auto' case
1845  #  gnutls_bug1717_workaround = true
1846  #endif
1847endif
1848
1849# We prefer use of gnutls for crypto, unless the options
1850# explicitly asked for nettle or gcrypt.
1851#
1852# If gnutls isn't available for crypto, then we'll prefer
1853# gcrypt over nettle for performance reasons.
1854gcrypt = not_found
1855nettle = not_found
1856hogweed = not_found
1857crypto_sm4 = not_found
1858crypto_sm3 = not_found
1859xts = 'none'
1860
1861if get_option('nettle').enabled() and get_option('gcrypt').enabled()
1862  error('Only one of gcrypt & nettle can be enabled')
1863endif
1864
1865# Explicit nettle/gcrypt request, so ignore gnutls for crypto
1866if get_option('nettle').enabled() or get_option('gcrypt').enabled()
1867  gnutls_crypto = not_found
1868endif
1869
1870if not gnutls_crypto.found()
1871  if (not get_option('gcrypt').auto() or have_system) and not get_option('nettle').enabled()
1872    gcrypt = dependency('libgcrypt', version: '>=1.8',
1873                        required: get_option('gcrypt'))
1874    # Debian has removed -lgpg-error from libgcrypt-config
1875    # as it "spreads unnecessary dependencies" which in
1876    # turn breaks static builds...
1877    if gcrypt.found() and get_option('prefer_static')
1878      gcrypt = declare_dependency(dependencies:
1879        [gcrypt,
1880         cc.find_library('gpg-error', required: true)],
1881        version: gcrypt.version())
1882    endif
1883    crypto_sm4 = gcrypt
1884    # SM4 ALG is available in libgcrypt >= 1.9
1885    if gcrypt.found() and not cc.links('''
1886      #include <gcrypt.h>
1887      int main(void) {
1888        gcry_cipher_hd_t handler;
1889        gcry_cipher_open(&handler, GCRY_CIPHER_SM4, GCRY_CIPHER_MODE_ECB, 0);
1890        return 0;
1891      }''', dependencies: gcrypt)
1892      crypto_sm4 = not_found
1893    endif
1894    crypto_sm3 = gcrypt
1895    # SM3 ALG is available in libgcrypt >= 1.9
1896    if gcrypt.found() and not cc.links('''
1897      #include <gcrypt.h>
1898      int main(void) {
1899        gcry_md_hd_t handler;
1900        gcry_md_open(&handler, GCRY_MD_SM3, 0);
1901        return 0;
1902      }''', dependencies: gcrypt)
1903      crypto_sm3 = not_found
1904    endif
1905  endif
1906  if (not get_option('nettle').auto() or have_system) and not gcrypt.found()
1907    nettle = dependency('nettle', version: '>=3.4',
1908                        method: 'pkg-config',
1909                        required: get_option('nettle'))
1910    if nettle.found() and not cc.has_header('nettle/xts.h', dependencies: nettle)
1911      xts = 'private'
1912    endif
1913    crypto_sm4 = nettle
1914    # SM4 ALG is available in nettle >= 3.9
1915    if nettle.found() and not cc.links('''
1916      #include <nettle/sm4.h>
1917      int main(void) {
1918        struct sm4_ctx ctx;
1919        unsigned char key[16] = {0};
1920        sm4_set_encrypt_key(&ctx, key);
1921        return 0;
1922      }''', dependencies: nettle)
1923      crypto_sm4 = not_found
1924    endif
1925    crypto_sm3 = nettle
1926    # SM3 ALG is available in nettle >= 3.8
1927    if nettle.found() and not cc.links('''
1928      #include <nettle/sm3.h>
1929      #include <nettle/hmac.h>
1930      int main(void) {
1931      struct sm3_ctx ctx;
1932      struct hmac_sm3_ctx hmac_ctx;
1933      unsigned char data[64] = {0};
1934      unsigned char output[32];
1935
1936      // SM3 hash function test
1937      sm3_init(&ctx);
1938      sm3_update(&ctx, 64, data);
1939      sm3_digest(&ctx, 32, data);
1940
1941      // HMAC-SM3 test
1942      hmac_sm3_set_key(&hmac_ctx, 32, data);
1943      hmac_sm3_update(&hmac_ctx, 64, data);
1944      hmac_sm3_digest(&hmac_ctx, 32, output);
1945
1946      return 0;
1947      }''', dependencies: nettle)
1948      crypto_sm3 = not_found
1949    endif
1950  endif
1951endif
1952
1953capstone = not_found
1954if not get_option('capstone').auto() or have_system or have_user
1955  capstone = dependency('capstone', version: '>=3.0.5',
1956                        method: 'pkg-config',
1957                        required: get_option('capstone'))
1958
1959  # Some versions of capstone have broken pkg-config file
1960  # that reports a wrong -I path, causing the #include to
1961  # fail later. If the system has such a broken version
1962  # do not use it.
1963  if capstone.found() and not cc.compiles('#include <capstone.h>',
1964                                          dependencies: [capstone])
1965    capstone = not_found
1966    if get_option('capstone').enabled()
1967      error('capstone requested, but it does not appear to work')
1968    endif
1969  endif
1970endif
1971
1972gmp = dependency('gmp', required: false, method: 'pkg-config')
1973if nettle.found() and gmp.found()
1974  hogweed = dependency('hogweed', version: '>=3.4',
1975                       method: 'pkg-config',
1976                       required: get_option('nettle'))
1977endif
1978
1979
1980gtk = not_found
1981gtkx11 = not_found
1982vte = not_found
1983have_gtk_clipboard = get_option('gtk_clipboard').enabled()
1984
1985if get_option('gtk') \
1986             .disable_auto_if(not have_system) \
1987             .require(pixman.found(),
1988                      error_message: 'cannot enable GTK if pixman is not available') \
1989             .allowed()
1990  gtk = dependency('gtk+-3.0', version: '>=3.22.0',
1991                   method: 'pkg-config',
1992                   required: get_option('gtk'))
1993  if gtk.found()
1994    gtkx11 = dependency('gtk+-x11-3.0', version: '>=3.22.0',
1995                        method: 'pkg-config',
1996                        required: false)
1997    gtk = declare_dependency(dependencies: [gtk, gtkx11],
1998                             version: gtk.version())
1999
2000    if not get_option('vte').auto() or have_system
2001      vte = dependency('vte-2.91',
2002                       method: 'pkg-config',
2003                       required: get_option('vte'))
2004    endif
2005  elif have_gtk_clipboard
2006    error('GTK clipboard requested, but GTK not found')
2007  endif
2008endif
2009
2010x11 = not_found
2011if gtkx11.found()
2012  x11 = dependency('x11', method: 'pkg-config', required: gtkx11.found())
2013endif
2014png = not_found
2015if get_option('png').allowed() and have_system
2016   png = dependency('libpng', version: '>=1.6.34', required: get_option('png'),
2017                    method: 'pkg-config')
2018endif
2019vnc = not_found
2020jpeg = not_found
2021sasl = not_found
2022if get_option('vnc') \
2023             .disable_auto_if(not have_system) \
2024             .require(pixman.found(),
2025                      error_message: 'cannot enable VNC if pixman is not available') \
2026             .allowed()
2027  vnc = declare_dependency() # dummy dependency
2028  jpeg = dependency('libjpeg', required: get_option('vnc_jpeg'),
2029                    method: 'pkg-config')
2030  sasl = cc.find_library('sasl2', has_headers: ['sasl/sasl.h'],
2031                         required: get_option('vnc_sasl'))
2032  if sasl.found()
2033    sasl = declare_dependency(dependencies: sasl,
2034                              compile_args: '-DSTRUCT_IOVEC_DEFINED')
2035  endif
2036endif
2037
2038pam = not_found
2039if not get_option('auth_pam').auto() or have_system
2040  pam = cc.find_library('pam', has_headers: ['security/pam_appl.h'],
2041                        required: get_option('auth_pam'))
2042endif
2043if pam.found() and not cc.links('''
2044   #include <stddef.h>
2045   #include <security/pam_appl.h>
2046   int main(void) {
2047     const char *service_name = "qemu";
2048     const char *user = "frank";
2049     const struct pam_conv pam_conv = { 0 };
2050     pam_handle_t *pamh = NULL;
2051     pam_start(service_name, user, &pam_conv, &pamh);
2052     return 0;
2053   }''', dependencies: pam)
2054  pam = not_found
2055  if get_option('auth_pam').enabled()
2056    error('could not link libpam')
2057  else
2058    warning('could not link libpam, disabling')
2059  endif
2060endif
2061
2062snappy = not_found
2063if not get_option('snappy').auto() or have_system
2064  snappy = cc.find_library('snappy', has_headers: ['snappy-c.h'],
2065                           required: get_option('snappy'))
2066endif
2067if snappy.found() and not cc.links('''
2068   #include <snappy-c.h>
2069   int main(void) { snappy_max_compressed_length(4096); return 0; }''', dependencies: snappy)
2070  snappy = not_found
2071  if get_option('snappy').enabled()
2072    error('could not link libsnappy')
2073  else
2074    warning('could not link libsnappy, disabling')
2075  endif
2076endif
2077
2078lzo = not_found
2079if not get_option('lzo').auto() or have_system
2080  lzo = cc.find_library('lzo2', has_headers: ['lzo/lzo1x.h'],
2081                        required: get_option('lzo'))
2082endif
2083if lzo.found() and not cc.links('''
2084   #include <lzo/lzo1x.h>
2085   int main(void) { lzo_version(); return 0; }''', dependencies: lzo)
2086  lzo = not_found
2087  if get_option('lzo').enabled()
2088    error('could not link liblzo2')
2089  else
2090    warning('could not link liblzo2, disabling')
2091  endif
2092endif
2093
2094numa = not_found
2095if not get_option('numa').auto() or have_system or have_tools
2096  numa = cc.find_library('numa', has_headers: ['numa.h'],
2097                              required: get_option('numa'))
2098endif
2099if numa.found() and not cc.links('''
2100   #include <numa.h>
2101   int main(void) { return numa_available(); }
2102   ''', dependencies: numa)
2103  numa = not_found
2104  if get_option('numa').enabled()
2105    error('could not link numa')
2106  else
2107    warning('could not link numa, disabling')
2108  endif
2109endif
2110
2111fdt = not_found
2112fdt_opt = get_option('fdt')
2113if fdt_opt == 'enabled' and get_option('wrap_mode') == 'nodownload'
2114  fdt_opt = 'system'
2115endif
2116if fdt_opt in ['enabled', 'system'] or (fdt_opt == 'auto' and have_system)
2117  fdt = cc.find_library('fdt', required: fdt_opt == 'system')
2118  if fdt.found() and cc.links('''
2119     #include <libfdt.h>
2120     #include <libfdt_env.h>
2121     int main(void) { fdt_find_max_phandle(NULL, NULL); return 0; }''',
2122       dependencies: fdt)
2123    fdt_opt = 'system'
2124  elif fdt_opt != 'system'
2125    fdt_opt = get_option('wrap_mode') == 'nodownload' ? 'disabled' : 'internal'
2126    fdt = not_found
2127  else
2128    error('system libfdt is too old (1.5.1 or newer required)')
2129  endif
2130endif
2131if fdt_opt == 'internal'
2132  assert(not fdt.found())
2133  libfdt_proj = subproject('dtc', required: true,
2134                           default_options: ['tools=false',  'yaml=disabled',
2135                                             'python=disabled', 'default_library=static'])
2136  fdt = libfdt_proj.get_variable('libfdt_dep')
2137endif
2138
2139rdma = not_found
2140if not get_option('rdma').auto() or have_system
2141  rdma_libs = [cc.find_library('rdmacm', has_headers: ['rdma/rdma_cma.h'],
2142                               required: get_option('rdma')),
2143               cc.find_library('ibverbs', required: get_option('rdma'))]
2144  rdma = declare_dependency(dependencies: rdma_libs)
2145  foreach lib: rdma_libs
2146    if not lib.found()
2147      rdma = not_found
2148    endif
2149  endforeach
2150endif
2151
2152cacard = not_found
2153if not get_option('smartcard').auto() or have_system
2154  cacard = dependency('libcacard', required: get_option('smartcard'),
2155                      version: '>=2.5.1', method: 'pkg-config')
2156endif
2157u2f = not_found
2158if not get_option('u2f').auto() or have_system
2159  u2f = dependency('u2f-emu', required: get_option('u2f'),
2160                   method: 'pkg-config')
2161endif
2162canokey = not_found
2163if not get_option('canokey').auto() or have_system
2164  canokey = dependency('canokey-qemu', required: get_option('canokey'),
2165                   method: 'pkg-config')
2166endif
2167usbredir = not_found
2168if not get_option('usb_redir').auto() or have_system
2169  usbredir = dependency('libusbredirparser-0.5', required: get_option('usb_redir'),
2170                        version: '>=0.6', method: 'pkg-config')
2171endif
2172libusb = not_found
2173if not get_option('libusb').auto() or have_system
2174  libusb = dependency('libusb-1.0', required: get_option('libusb'),
2175                      version: '>=1.0.13', method: 'pkg-config')
2176endif
2177
2178libpmem = not_found
2179if not get_option('libpmem').auto() or have_system
2180  libpmem = dependency('libpmem', required: get_option('libpmem'),
2181                       method: 'pkg-config')
2182endif
2183libdaxctl = not_found
2184if not get_option('libdaxctl').auto() or have_system
2185  libdaxctl = dependency('libdaxctl', required: get_option('libdaxctl'),
2186                         version: '>=57', method: 'pkg-config')
2187endif
2188tasn1 = not_found
2189if gnutls.found()
2190  tasn1 = dependency('libtasn1',
2191                     required: false,
2192                     method: 'pkg-config')
2193endif
2194keyutils = not_found
2195if not get_option('libkeyutils').auto() or have_block
2196  keyutils = dependency('libkeyutils', required: get_option('libkeyutils'),
2197                        method: 'pkg-config')
2198endif
2199
2200has_gettid = cc.has_function('gettid')
2201
2202# libselinux
2203selinux = dependency('libselinux',
2204                     required: get_option('selinux'),
2205                     method: 'pkg-config')
2206
2207# Malloc tests
2208
2209malloc = []
2210if get_option('malloc') == 'system'
2211  has_malloc_trim = \
2212    get_option('malloc_trim').allowed() and \
2213    cc.has_function('malloc_trim', prefix: '#include <malloc.h>')
2214else
2215  has_malloc_trim = false
2216  malloc = cc.find_library(get_option('malloc'), required: true)
2217endif
2218if not has_malloc_trim and get_option('malloc_trim').enabled()
2219  if get_option('malloc') == 'system'
2220    error('malloc_trim not available on this platform.')
2221  else
2222    error('malloc_trim not available with non-libc memory allocator')
2223  endif
2224endif
2225
2226osdep_prefix = '''
2227  #ifndef _GNU_SOURCE
2228  #define _GNU_SOURCE
2229  #endif
2230
2231  #include <stddef.h>
2232  #include <sys/types.h>
2233
2234  #include <string.h>
2235  #include <limits.h>
2236  /* Put unistd.h before time.h as that triggers localtime_r/gmtime_r
2237   * function availability on recentish Mingw-w64 platforms. */
2238  #include <unistd.h>
2239  #include <time.h>
2240  #include <errno.h>
2241  #include <fcntl.h>
2242'''
2243
2244have_vhost_user_blk_server = get_option('vhost_user_blk_server') \
2245  .require(host_os == 'linux',
2246           error_message: 'vhost_user_blk_server requires linux') \
2247  .require(have_vhost_user,
2248           error_message: 'vhost_user_blk_server requires vhost-user support') \
2249  .disable_auto_if(not have_tools and not have_system) \
2250  .allowed()
2251
2252if get_option('fuse').disabled() and get_option('fuse_lseek').enabled()
2253  error('Cannot enable fuse-lseek while fuse is disabled')
2254endif
2255
2256fuse = dependency('fuse3', required: get_option('fuse'),
2257                  version: '>=3.1', method: 'pkg-config')
2258
2259fuse_lseek = not_found
2260if get_option('fuse_lseek').allowed()
2261  if fuse.version().version_compare('>=3.8')
2262    # Dummy dependency
2263    fuse_lseek = declare_dependency()
2264  elif get_option('fuse_lseek').enabled()
2265    if fuse.found()
2266      error('fuse-lseek requires libfuse >=3.8, found ' + fuse.version())
2267    else
2268      error('fuse-lseek requires libfuse, which was not found')
2269    endif
2270  endif
2271endif
2272
2273have_libvduse = (host_os == 'linux')
2274if get_option('libvduse').enabled()
2275    if host_os != 'linux'
2276        error('libvduse requires linux')
2277    endif
2278elif get_option('libvduse').disabled()
2279    have_libvduse = false
2280endif
2281
2282have_vduse_blk_export = (have_libvduse and host_os == 'linux')
2283if get_option('vduse_blk_export').enabled()
2284    if host_os != 'linux'
2285        error('vduse_blk_export requires linux')
2286    elif not have_libvduse
2287        error('vduse_blk_export requires libvduse support')
2288    endif
2289elif get_option('vduse_blk_export').disabled()
2290    have_vduse_blk_export = false
2291endif
2292
2293# libbpf
2294bpf_version = '1.1.0'
2295libbpf = dependency('libbpf', version: '>=' + bpf_version, required: get_option('bpf'), method: 'pkg-config')
2296if libbpf.found() and not cc.links('''
2297   #include <bpf/libbpf.h>
2298   #include <linux/bpf.h>
2299   int main(void)
2300   {
2301     // check flag availability
2302     int flag = BPF_F_MMAPABLE;
2303     bpf_object__destroy_skeleton(NULL);
2304     return 0;
2305   }''', dependencies: libbpf)
2306  libbpf = not_found
2307  if get_option('bpf').enabled()
2308    error('libbpf skeleton/mmaping test failed')
2309  else
2310    warning('libbpf skeleton/mmaping test failed, disabling')
2311  endif
2312endif
2313
2314# libxdp
2315libxdp = not_found
2316if not get_option('af_xdp').auto() or have_system
2317    if libbpf.found()
2318        libxdp = dependency('libxdp', required: get_option('af_xdp'),
2319                            version: '>=1.4.0', method: 'pkg-config')
2320    else
2321        if get_option('af_xdp').enabled()
2322            error('libxdp requested, but libbpf is not available')
2323        endif
2324    endif
2325endif
2326
2327# libdw
2328libdw = not_found
2329if not get_option('libdw').auto() or \
2330        (not get_option('prefer_static') and (have_system or have_user))
2331    libdw = dependency('libdw',
2332                       method: 'pkg-config',
2333                       required: get_option('libdw'))
2334endif
2335
2336#################
2337# config-host.h #
2338#################
2339
2340config_host_data = configuration_data()
2341
2342config_host_data.set('CONFIG_HAVE_RUST', have_rust)
2343audio_drivers_selected = []
2344if have_system
2345  audio_drivers_available = {
2346    'alsa': alsa.found(),
2347    'coreaudio': coreaudio.found(),
2348    'dsound': dsound.found(),
2349    'jack': jack.found(),
2350    'oss': oss.found(),
2351    'pa': pulse.found(),
2352    'pipewire': pipewire.found(),
2353    'sdl': sdl.found(),
2354    'sndio': sndio.found(),
2355  }
2356  foreach k, v: audio_drivers_available
2357    config_host_data.set('CONFIG_AUDIO_' + k.to_upper(), v)
2358  endforeach
2359
2360  # Default to native drivers first, OSS second, SDL third
2361  audio_drivers_priority = \
2362    [ 'pa', 'coreaudio', 'dsound', 'sndio', 'oss' ] + \
2363    (host_os == 'linux' ? [] : [ 'sdl' ])
2364  audio_drivers_default = []
2365  foreach k: audio_drivers_priority
2366    if audio_drivers_available[k]
2367      audio_drivers_default += k
2368    endif
2369  endforeach
2370
2371  foreach k: get_option('audio_drv_list')
2372    if k == 'default'
2373      audio_drivers_selected += audio_drivers_default
2374    elif not audio_drivers_available[k]
2375      error('Audio driver "@0@" not available.'.format(k))
2376    else
2377      audio_drivers_selected += k
2378    endif
2379  endforeach
2380endif
2381config_host_data.set('CONFIG_AUDIO_DRIVERS',
2382                     '"' + '", "'.join(audio_drivers_selected) + '", ')
2383
2384have_host_block_device = (host_os != 'darwin' or
2385    cc.has_header('IOKit/storage/IOMedia.h'))
2386
2387dbus_display = get_option('dbus_display') \
2388  .require(gio.version().version_compare('>=2.64'),
2389           error_message: '-display dbus requires glib>=2.64') \
2390  .require(gdbus_codegen.found(),
2391           error_message: gdbus_codegen_error.format('-display dbus')) \
2392  .allowed()
2393
2394have_virtfs = get_option('virtfs') \
2395    .require(host_os == 'linux' or host_os == 'darwin',
2396             error_message: 'virtio-9p (virtfs) requires Linux or macOS') \
2397    .require(host_os == 'linux' or cc.has_function('pthread_fchdir_np'),
2398             error_message: 'virtio-9p (virtfs) on macOS requires the presence of pthread_fchdir_np') \
2399    .require(host_os == 'darwin' or libattr.found(),
2400             error_message: 'virtio-9p (virtfs) on Linux requires libattr-devel') \
2401    .disable_auto_if(not have_tools and not have_system) \
2402    .allowed()
2403
2404qga_fsfreeze = false
2405qga_fstrim = false
2406if host_os == 'linux'
2407    if cc.has_header_symbol('linux/fs.h', 'FIFREEZE')
2408        qga_fsfreeze = true
2409    endif
2410    if cc.has_header_symbol('linux/fs.h', 'FITRIM')
2411        qga_fstrim = true
2412    endif
2413elif host_os == 'freebsd' and cc.has_header_symbol('ufs/ffs/fs.h', 'UFSSUSPEND')
2414    qga_fsfreeze = true
2415endif
2416
2417if get_option('block_drv_ro_whitelist') == ''
2418  config_host_data.set('CONFIG_BDRV_RO_WHITELIST', '')
2419else
2420  config_host_data.set('CONFIG_BDRV_RO_WHITELIST',
2421        '"' + get_option('block_drv_ro_whitelist').replace(',', '", "') + '", ')
2422endif
2423if get_option('block_drv_rw_whitelist') == ''
2424  config_host_data.set('CONFIG_BDRV_RW_WHITELIST', '')
2425else
2426  config_host_data.set('CONFIG_BDRV_RW_WHITELIST',
2427        '"' + get_option('block_drv_rw_whitelist').replace(',', '", "') + '", ')
2428endif
2429
2430foreach k : get_option('trace_backends')
2431  config_host_data.set('CONFIG_TRACE_' + k.to_upper(), true)
2432endforeach
2433config_host_data.set_quoted('CONFIG_TRACE_FILE', get_option('trace_file'))
2434config_host_data.set_quoted('CONFIG_TLS_PRIORITY', get_option('tls_priority'))
2435if iasl.found()
2436  config_host_data.set_quoted('CONFIG_IASL', iasl.full_path())
2437endif
2438config_host_data.set_quoted('CONFIG_BINDIR', get_option('prefix') / get_option('bindir'))
2439config_host_data.set_quoted('CONFIG_PREFIX', get_option('prefix'))
2440config_host_data.set_quoted('CONFIG_QEMU_CONFDIR', get_option('prefix') / qemu_confdir)
2441config_host_data.set_quoted('CONFIG_QEMU_DATADIR', get_option('prefix') / qemu_datadir)
2442config_host_data.set_quoted('CONFIG_QEMU_DESKTOPDIR', get_option('prefix') / qemu_desktopdir)
2443
2444qemu_firmwarepath = ''
2445foreach k : get_option('qemu_firmwarepath')
2446  qemu_firmwarepath += '"' + get_option('prefix') / k + '", '
2447endforeach
2448config_host_data.set('CONFIG_QEMU_FIRMWAREPATH', qemu_firmwarepath)
2449
2450config_host_data.set_quoted('CONFIG_QEMU_HELPERDIR', get_option('prefix') / get_option('libexecdir'))
2451config_host_data.set_quoted('CONFIG_QEMU_ICONDIR', get_option('prefix') / qemu_icondir)
2452config_host_data.set_quoted('CONFIG_QEMU_LOCALEDIR', get_option('prefix') / get_option('localedir'))
2453config_host_data.set_quoted('CONFIG_QEMU_LOCALSTATEDIR', get_option('prefix') / get_option('localstatedir'))
2454config_host_data.set_quoted('CONFIG_QEMU_MODDIR', get_option('prefix') / qemu_moddir)
2455config_host_data.set_quoted('CONFIG_SYSCONFDIR', get_option('prefix') / get_option('sysconfdir'))
2456
2457if enable_modules
2458  config_host_data.set('CONFIG_STAMP', run_command(
2459      meson.current_source_dir() / 'scripts/qemu-stamp.py',
2460      meson.project_version(), get_option('pkgversion'), '--',
2461      meson.current_source_dir() / 'configure',
2462      capture: true, check: true).stdout().strip())
2463endif
2464
2465have_slirp_smbd = get_option('slirp_smbd') \
2466  .require(host_os != 'windows', error_message: 'Host smbd not supported on this platform.') \
2467  .allowed()
2468if have_slirp_smbd
2469  smbd_path = get_option('smbd')
2470  if smbd_path == ''
2471    smbd_path = (host_os == 'sunos' ? '/usr/sfw/sbin/smbd' : '/usr/sbin/smbd')
2472  endif
2473  config_host_data.set_quoted('CONFIG_SMBD_COMMAND', smbd_path)
2474endif
2475
2476config_host_data.set('HOST_' + host_arch.to_upper(), 1)
2477
2478kvm_targets_c = '""'
2479if get_option('kvm').allowed() and host_os == 'linux'
2480  kvm_targets_c = '"' + '" ,"'.join(kvm_targets) + '"'
2481endif
2482config_host_data.set('CONFIG_KVM_TARGETS', kvm_targets_c)
2483
2484if get_option('module_upgrades') and not enable_modules
2485  error('Cannot enable module-upgrades as modules are not enabled')
2486endif
2487config_host_data.set('CONFIG_MODULE_UPGRADES', get_option('module_upgrades'))
2488
2489config_host_data.set('CONFIG_ATTR', libattr.found())
2490config_host_data.set('CONFIG_BDRV_WHITELIST_TOOLS', get_option('block_drv_whitelist_in_tools'))
2491config_host_data.set('CONFIG_BRLAPI', brlapi.found())
2492config_host_data.set('CONFIG_BSD', host_os in bsd_oses)
2493config_host_data.set('CONFIG_FREEBSD', host_os == 'freebsd')
2494config_host_data.set('CONFIG_CAPSTONE', capstone.found())
2495config_host_data.set('CONFIG_COCOA', cocoa.found())
2496config_host_data.set('CONFIG_DARWIN', host_os == 'darwin')
2497config_host_data.set('CONFIG_FDT', fdt.found())
2498config_host_data.set('CONFIG_FUZZ', get_option('fuzzing'))
2499config_host_data.set('CONFIG_GCOV', get_option('b_coverage'))
2500config_host_data.set('CONFIG_LIBUDEV', libudev.found())
2501config_host_data.set('CONFIG_LINUX', host_os == 'linux')
2502config_host_data.set('CONFIG_POSIX', host_os != 'windows')
2503config_host_data.set('CONFIG_WIN32', host_os == 'windows')
2504config_host_data.set('CONFIG_LZO', lzo.found())
2505config_host_data.set('CONFIG_MPATH', mpathpersist.found())
2506config_host_data.set('CONFIG_BLKIO', blkio.found())
2507if blkio.found()
2508  config_host_data.set('CONFIG_BLKIO_VHOST_VDPA_FD',
2509                       blkio.version().version_compare('>=1.3.0'))
2510  config_host_data.set('CONFIG_BLKIO_WRITE_ZEROS_FUA',
2511                       blkio.version().version_compare('>=1.4.0'))
2512endif
2513config_host_data.set('CONFIG_CURL', curl.found())
2514config_host_data.set('CONFIG_CURSES', curses.found())
2515config_host_data.set('CONFIG_GBM', gbm.found())
2516config_host_data.set('CONFIG_GIO', gio.found())
2517config_host_data.set('CONFIG_GLUSTERFS', glusterfs.found())
2518if glusterfs.found()
2519  config_host_data.set('CONFIG_GLUSTERFS_XLATOR_OPT', glusterfs.version().version_compare('>=4'))
2520  config_host_data.set('CONFIG_GLUSTERFS_DISCARD', glusterfs.version().version_compare('>=5'))
2521  config_host_data.set('CONFIG_GLUSTERFS_FALLOCATE', glusterfs.version().version_compare('>=6'))
2522  config_host_data.set('CONFIG_GLUSTERFS_ZEROFILL', glusterfs.version().version_compare('>=6'))
2523  config_host_data.set('CONFIG_GLUSTERFS_FTRUNCATE_HAS_STAT', glusterfs_ftruncate_has_stat)
2524  config_host_data.set('CONFIG_GLUSTERFS_IOCB_HAS_STAT', glusterfs_iocb_has_stat)
2525endif
2526config_host_data.set('CONFIG_GTK', gtk.found())
2527config_host_data.set('CONFIG_VTE', vte.found())
2528config_host_data.set('CONFIG_GTK_CLIPBOARD', have_gtk_clipboard)
2529config_host_data.set('CONFIG_HEXAGON_IDEF_PARSER', get_option('hexagon_idef_parser'))
2530config_host_data.set('CONFIG_LIBATTR', have_old_libattr)
2531config_host_data.set('CONFIG_LIBCAP_NG', libcap_ng.found())
2532config_host_data.set('CONFIG_EBPF', libbpf.found())
2533config_host_data.set('CONFIG_AF_XDP', libxdp.found())
2534config_host_data.set('CONFIG_LIBDAXCTL', libdaxctl.found())
2535config_host_data.set('CONFIG_LIBISCSI', libiscsi.found())
2536config_host_data.set('CONFIG_LIBNFS', libnfs.found())
2537config_host_data.set('CONFIG_LIBSSH', libssh.found())
2538config_host_data.set('CONFIG_LINUX_AIO', libaio.found())
2539config_host_data.set('CONFIG_LINUX_IO_URING', linux_io_uring.found())
2540config_host_data.set('CONFIG_LIBPMEM', libpmem.found())
2541config_host_data.set('CONFIG_MODULES', enable_modules)
2542config_host_data.set('CONFIG_NUMA', numa.found())
2543if numa.found()
2544  config_host_data.set('HAVE_NUMA_HAS_PREFERRED_MANY',
2545                       cc.has_function('numa_has_preferred_many',
2546                                       dependencies: numa))
2547endif
2548config_host_data.set('CONFIG_OPENGL', opengl.found())
2549config_host_data.set('CONFIG_PLUGIN', get_option('plugins'))
2550config_host_data.set('CONFIG_RBD', rbd.found())
2551config_host_data.set('CONFIG_RDMA', rdma.found())
2552config_host_data.set('CONFIG_RELOCATABLE', get_option('relocatable'))
2553config_host_data.set('CONFIG_SAFESTACK', get_option('safe_stack'))
2554config_host_data.set('CONFIG_SDL', sdl.found())
2555config_host_data.set('CONFIG_SDL_IMAGE', sdl_image.found())
2556config_host_data.set('CONFIG_SECCOMP', seccomp.found())
2557if seccomp.found()
2558  config_host_data.set('CONFIG_SECCOMP_SYSRAWRC', seccomp_has_sysrawrc)
2559endif
2560config_host_data.set('CONFIG_PIXMAN', pixman.found())
2561config_host_data.set('CONFIG_PASST', enable_passt)
2562config_host_data.set('CONFIG_SLIRP', slirp.found())
2563config_host_data.set('CONFIG_SNAPPY', snappy.found())
2564config_host_data.set('CONFIG_SOLARIS', host_os == 'sunos')
2565if have_tcg
2566  config_host_data.set('CONFIG_TCG', 1)
2567  config_host_data.set('CONFIG_TCG_INTERPRETER', tcg_arch == 'tci')
2568endif
2569config_host_data.set('CONFIG_TPM', have_tpm)
2570config_host_data.set('CONFIG_TSAN', get_option('tsan'))
2571config_host_data.set('CONFIG_USB_LIBUSB', libusb.found())
2572config_host_data.set('CONFIG_VDE', vde.found())
2573config_host_data.set('CONFIG_VHOST', have_vhost)
2574config_host_data.set('CONFIG_VHOST_NET', have_vhost_net)
2575config_host_data.set('CONFIG_VHOST_NET_USER', have_vhost_net_user)
2576config_host_data.set('CONFIG_VHOST_NET_VDPA', have_vhost_net_vdpa)
2577config_host_data.set('CONFIG_VHOST_KERNEL', have_vhost_kernel)
2578config_host_data.set('CONFIG_VHOST_USER', have_vhost_user)
2579config_host_data.set('CONFIG_VHOST_CRYPTO', have_vhost_user_crypto)
2580config_host_data.set('CONFIG_VHOST_VDPA', have_vhost_vdpa)
2581config_host_data.set('CONFIG_VMNET', vmnet.found())
2582config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', have_vhost_user_blk_server)
2583config_host_data.set('CONFIG_VDUSE_BLK_EXPORT', have_vduse_blk_export)
2584config_host_data.set('CONFIG_PNG', png.found())
2585config_host_data.set('CONFIG_VNC', vnc.found())
2586config_host_data.set('CONFIG_VNC_JPEG', jpeg.found())
2587config_host_data.set('CONFIG_VNC_SASL', sasl.found())
2588if virgl.found()
2589  config_host_data.set('VIRGL_VERSION_MAJOR', virgl.version().split('.')[0])
2590endif
2591config_host_data.set('CONFIG_VIRTFS', have_virtfs)
2592config_host_data.set('CONFIG_VTE', vte.found())
2593config_host_data.set('CONFIG_XKBCOMMON', xkbcommon.found())
2594config_host_data.set('CONFIG_KEYUTILS', keyutils.found())
2595config_host_data.set('CONFIG_GETTID', has_gettid)
2596config_host_data.set('CONFIG_GNUTLS', gnutls.found())
2597config_host_data.set('CONFIG_GNUTLS_CRYPTO', gnutls_crypto.found())
2598config_host_data.set('CONFIG_GNUTLS_BUG1717_WORKAROUND', gnutls_bug1717_workaround)
2599config_host_data.set('CONFIG_TASN1', tasn1.found())
2600config_host_data.set('CONFIG_GCRYPT', gcrypt.found())
2601config_host_data.set('CONFIG_NETTLE', nettle.found())
2602config_host_data.set('CONFIG_CRYPTO_SM4', crypto_sm4.found())
2603config_host_data.set('CONFIG_CRYPTO_SM3', crypto_sm3.found())
2604config_host_data.set('CONFIG_HOGWEED', hogweed.found())
2605config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private')
2606config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim)
2607config_host_data.set('CONFIG_ZSTD', zstd.found())
2608config_host_data.set('CONFIG_QPL', qpl.found())
2609config_host_data.set('CONFIG_UADK', uadk.found())
2610config_host_data.set('CONFIG_QATZIP', qatzip.found())
2611config_host_data.set('CONFIG_FUSE', fuse.found())
2612config_host_data.set('CONFIG_FUSE_LSEEK', fuse_lseek.found())
2613config_host_data.set('CONFIG_SPICE_PROTOCOL', spice_protocol.found())
2614if spice_protocol.found()
2615config_host_data.set('CONFIG_SPICE_PROTOCOL_MAJOR', spice_protocol.version().split('.')[0])
2616config_host_data.set('CONFIG_SPICE_PROTOCOL_MINOR', spice_protocol.version().split('.')[1])
2617config_host_data.set('CONFIG_SPICE_PROTOCOL_MICRO', spice_protocol.version().split('.')[2])
2618endif
2619config_host_data.set('CONFIG_SPICE', spice.found())
2620config_host_data.set('CONFIG_X11', x11.found())
2621config_host_data.set('CONFIG_DBUS_DISPLAY', dbus_display)
2622config_host_data.set('CONFIG_CFI', get_option('cfi'))
2623config_host_data.set('CONFIG_SELINUX', selinux.found())
2624config_host_data.set('CONFIG_XEN_BACKEND', xen.found())
2625config_host_data.set('CONFIG_LIBDW', libdw.found())
2626config_host_data.set('CONFIG_IGVM', igvm.found())
2627if xen.found()
2628  # protect from xen.version() having less than three components
2629  xen_version = xen.version().split('.') + ['0', '0']
2630  xen_ctrl_version = xen_version[0] + \
2631    ('0' + xen_version[1]).substring(-2) + \
2632    ('0' + xen_version[2]).substring(-2)
2633  config_host_data.set('CONFIG_XEN_CTRL_INTERFACE_VERSION', xen_ctrl_version)
2634endif
2635config_host_data.set('QEMU_VERSION', '"@0@"'.format(meson.project_version()))
2636config_host_data.set('QEMU_VERSION_MAJOR', meson.project_version().split('.')[0])
2637config_host_data.set('QEMU_VERSION_MINOR', meson.project_version().split('.')[1])
2638config_host_data.set('QEMU_VERSION_MICRO', meson.project_version().split('.')[2])
2639
2640config_host_data.set_quoted('CONFIG_HOST_DSOSUF', host_dsosuf)
2641config_host_data.set('HAVE_HOST_BLOCK_DEVICE', have_host_block_device)
2642
2643have_coroutine_pool = get_option('coroutine_pool')
2644if get_option('debug_stack_usage') and have_coroutine_pool
2645  message('Disabling coroutine pool to measure stack usage')
2646  have_coroutine_pool = false
2647endif
2648config_host_data.set('CONFIG_COROUTINE_POOL', have_coroutine_pool)
2649config_host_data.set('CONFIG_DEBUG_GRAPH_LOCK', get_option('debug_graph_lock'))
2650config_host_data.set('CONFIG_DEBUG_MUTEX', get_option('debug_mutex'))
2651config_host_data.set('CONFIG_DEBUG_STACK_USAGE', get_option('debug_stack_usage'))
2652config_host_data.set('CONFIG_DEBUG_TCG', get_option('debug_tcg'))
2653config_host_data.set('CONFIG_DEBUG_REMAP', get_option('debug_remap'))
2654config_host_data.set('CONFIG_QOM_CAST_DEBUG', get_option('qom_cast_debug'))
2655config_host_data.set('CONFIG_REPLICATION', get_option('replication').allowed())
2656config_host_data.set('CONFIG_FSFREEZE', qga_fsfreeze)
2657config_host_data.set('CONFIG_FSTRIM', qga_fstrim)
2658
2659# has_header
2660config_host_data.set('CONFIG_EPOLL', cc.has_header('sys/epoll.h'))
2661config_host_data.set('CONFIG_LINUX_MAGIC_H', cc.has_header('linux/magic.h'))
2662valgrind = false
2663if get_option('valgrind').allowed()
2664    if cc.has_header('valgrind/valgrind.h')
2665        valgrind = true
2666    else
2667        if get_option('valgrind').enabled()
2668            error('valgrind requested but valgrind.h not found')
2669        endif
2670    endif
2671endif
2672config_host_data.set('CONFIG_VALGRIND_H', valgrind)
2673config_host_data.set('HAVE_BTRFS_H', cc.has_header('linux/btrfs.h'))
2674config_host_data.set('HAVE_DRM_H', cc.has_header('libdrm/drm.h'))
2675config_host_data.set('HAVE_OPENAT2_H', cc.has_header('linux/openat2.h'))
2676config_host_data.set('HAVE_PTY_H', cc.has_header('pty.h'))
2677config_host_data.set('HAVE_SYS_DISK_H', cc.has_header('sys/disk.h'))
2678config_host_data.set('HAVE_SYS_IOCCOM_H', cc.has_header('sys/ioccom.h'))
2679config_host_data.set('HAVE_SYS_KCOV_H', cc.has_header('sys/kcov.h'))
2680if host_os == 'windows'
2681  config_host_data.set('HAVE_AFUNIX_H', cc.has_header('afunix.h'))
2682endif
2683
2684# has_function
2685config_host_data.set('CONFIG_CLOSE_RANGE', cc.has_function('close_range'))
2686config_host_data.set('CONFIG_ACCEPT4', cc.has_function('accept4'))
2687config_host_data.set('CONFIG_CLOCK_ADJTIME', cc.has_function('clock_adjtime'))
2688config_host_data.set('CONFIG_DUP3', cc.has_function('dup3'))
2689config_host_data.set('CONFIG_FALLOCATE', cc.has_function('fallocate'))
2690config_host_data.set('CONFIG_POSIX_FALLOCATE', cc.has_function('posix_fallocate'))
2691config_host_data.set('CONFIG_SCHED_GETCPU', cc.has_function('sched_getcpu', prefix: '#include <sched.h>'))
2692# Note that we need to specify prefix: here to avoid incorrectly
2693# thinking that Windows has posix_memalign()
2694config_host_data.set('CONFIG_POSIX_MEMALIGN', cc.has_function('posix_memalign', prefix: '#include <stdlib.h>'))
2695config_host_data.set('CONFIG_ALIGNED_MALLOC', cc.has_function('_aligned_malloc'))
2696config_host_data.set('CONFIG_VALLOC', cc.has_function('valloc'))
2697config_host_data.set('CONFIG_MEMALIGN', cc.has_function('memalign'))
2698config_host_data.set('CONFIG_PPOLL', cc.has_function('ppoll'))
2699config_host_data.set('CONFIG_PREADV', cc.has_function('preadv', prefix: '#include <sys/uio.h>'))
2700config_host_data.set('CONFIG_PTHREAD_FCHDIR_NP', cc.has_function('pthread_fchdir_np'))
2701config_host_data.set('CONFIG_SENDFILE', cc.has_function('sendfile'))
2702config_host_data.set('CONFIG_SETNS', cc.has_function('setns') and cc.has_function('unshare'))
2703config_host_data.set('CONFIG_SYNCFS', cc.has_function('syncfs'))
2704config_host_data.set('CONFIG_SYNC_FILE_RANGE', cc.has_function('sync_file_range'))
2705config_host_data.set('CONFIG_TIMERFD', cc.has_function('timerfd_create'))
2706config_host_data.set('CONFIG_GETLOADAVG', cc.has_function('getloadavg'))
2707config_host_data.set('HAVE_COPY_FILE_RANGE', cc.has_function('copy_file_range'))
2708config_host_data.set('HAVE_GETIFADDRS', cc.has_function('getifaddrs'))
2709config_host_data.set('HAVE_GLIB_WITH_SLICE_ALLOCATOR', glib_has_gslice)
2710config_host_data.set('HAVE_GLIB_WITH_ALIGNED_ALLOC', glib_has_aligned_alloc)
2711config_host_data.set('HAVE_OPENPTY', cc.has_function('openpty', dependencies: util))
2712config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul', prefix: osdep_prefix))
2713config_host_data.set('HAVE_SYSTEM_FUNCTION', cc.has_function('system', prefix: '#include <stdlib.h>'))
2714if rbd.found()
2715  config_host_data.set('HAVE_RBD_NAMESPACE_EXISTS',
2716                       cc.has_function('rbd_namespace_exists',
2717                                       dependencies: rbd,
2718                                       prefix: '#include <rbd/librbd.h>'))
2719endif
2720if rdma.found()
2721  config_host_data.set('HAVE_IBV_ADVISE_MR',
2722                       cc.has_function('ibv_advise_mr',
2723                                       dependencies: rdma,
2724                                       prefix: '#include <infiniband/verbs.h>'))
2725endif
2726
2727have_asan_fiber = false
2728if get_option('asan') and \
2729   not cc.has_function('__sanitizer_start_switch_fiber',
2730                         args: '-fsanitize=address',
2731                         prefix: '#include <sanitizer/asan_interface.h>')
2732  warning('Missing ASAN due to missing fiber annotation interface')
2733  warning('Without code annotation, the report may be inferior.')
2734else
2735  have_asan_fiber = true
2736endif
2737config_host_data.set('CONFIG_ASAN_IFACE_FIBER', have_asan_fiber)
2738
2739have_inotify_init = cc.has_header_symbol('sys/inotify.h', 'inotify_init')
2740have_inotify_init1 = cc.has_header_symbol('sys/inotify.h', 'inotify_init1')
2741inotify = not_found
2742if (have_inotify_init or have_inotify_init1) and host_os == 'freebsd'
2743  # libinotify-kqueue
2744  inotify = cc.find_library('inotify')
2745  if have_inotify_init
2746    have_inotify_init = inotify.found()
2747  endif
2748  if have_inotify_init1
2749    have_inotify_init1 = inotify.found()
2750  endif
2751endif
2752config_host_data.set('CONFIG_INOTIFY', have_inotify_init)
2753config_host_data.set('CONFIG_INOTIFY1', have_inotify_init1)
2754
2755# has_header_symbol
2756config_host_data.set('CONFIG_BLKZONED',
2757                     cc.has_header_symbol('linux/blkzoned.h', 'BLKOPENZONE'))
2758config_host_data.set('CONFIG_EPOLL_CREATE1',
2759                     cc.has_header_symbol('sys/epoll.h', 'epoll_create1'))
2760config_host_data.set('CONFIG_FALLOCATE_PUNCH_HOLE',
2761                     cc.has_header_symbol('linux/falloc.h', 'FALLOC_FL_PUNCH_HOLE') and
2762                     cc.has_header_symbol('linux/falloc.h', 'FALLOC_FL_KEEP_SIZE'))
2763config_host_data.set('CONFIG_FALLOCATE_ZERO_RANGE',
2764                     cc.has_header_symbol('linux/falloc.h', 'FALLOC_FL_ZERO_RANGE'))
2765config_host_data.set('CONFIG_FIEMAP',
2766                     cc.has_header('linux/fiemap.h') and
2767                     cc.has_header_symbol('linux/fs.h', 'FS_IOC_FIEMAP'))
2768config_host_data.set('CONFIG_GETCPU',
2769                     cc.has_header_symbol('sched.h', 'getcpu', prefix: osdep_prefix))
2770config_host_data.set('CONFIG_GETRANDOM',
2771                     cc.has_function('getrandom') and
2772                     cc.has_header_symbol('sys/random.h', 'GRND_NONBLOCK'))
2773config_host_data.set('CONFIG_PRCTL_PR_SET_TIMERSLACK',
2774                     cc.has_header_symbol('sys/prctl.h', 'PR_SET_TIMERSLACK'))
2775config_host_data.set('CONFIG_RTNETLINK',
2776                     cc.has_header_symbol('linux/rtnetlink.h', 'IFLA_PROTO_DOWN'))
2777config_host_data.set('CONFIG_SYSMACROS',
2778                     cc.has_header_symbol('sys/sysmacros.h', 'makedev'))
2779config_host_data.set('HAVE_OPTRESET',
2780                     cc.has_header_symbol('getopt.h', 'optreset'))
2781config_host_data.set('HAVE_IPPROTO_MPTCP',
2782                     cc.has_header_symbol('netinet/in.h', 'IPPROTO_MPTCP'))
2783if libaio.found()
2784  config_host_data.set('HAVE_IO_PREP_PWRITEV2',
2785                       cc.has_header_symbol('libaio.h', 'io_prep_pwritev2'))
2786endif
2787if linux_io_uring.found()
2788  config_host_data.set('HAVE_IO_URING_PREP_WRITEV2',
2789                       cc.has_header_symbol('liburing.h', 'io_uring_prep_writev2'))
2790endif
2791config_host_data.set('HAVE_TCP_KEEPCNT',
2792                     cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPCNT') or
2793                     cc.compiles('''
2794                     #include <ws2tcpip.h>
2795                     #ifndef TCP_KEEPCNT
2796                     #error
2797                     #endif
2798                     int main(void) { return 0; }''',
2799                     name: 'Win32 TCP_KEEPCNT'))
2800# On Darwin TCP_KEEPIDLE is available under different name, TCP_KEEPALIVE.
2801# https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/bsd/man/man4/tcp.4#L172
2802config_host_data.set('HAVE_TCP_KEEPIDLE',
2803                     cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPIDLE') or
2804                     cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPALIVE') or
2805                     cc.compiles('''
2806                     #include <ws2tcpip.h>
2807                     #ifndef TCP_KEEPIDLE
2808                     #error
2809                     #endif
2810                     int main(void) { return 0; }''',
2811                     name: 'Win32 TCP_KEEPIDLE'))
2812config_host_data.set('HAVE_TCP_KEEPINTVL',
2813                     cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPINTVL') or
2814                     cc.compiles('''
2815                     #include <ws2tcpip.h>
2816                     #ifndef TCP_KEEPINTVL
2817                     #error
2818                     #endif
2819                     int main(void) { return 0; }''',
2820                     name: 'Win32 TCP_KEEPINTVL'))
2821
2822# has_member
2823config_host_data.set('HAVE_SIGEV_NOTIFY_THREAD_ID',
2824                     cc.has_member('struct sigevent', 'sigev_notify_thread_id',
2825                                   prefix: '#include <signal.h>'))
2826config_host_data.set('HAVE_STRUCT_STAT_ST_ATIM',
2827                     cc.has_member('struct stat', 'st_atim',
2828                                   prefix: '#include <sys/stat.h>'))
2829config_host_data.set('HAVE_BLK_ZONE_REP_CAPACITY',
2830                     cc.has_member('struct blk_zone', 'capacity',
2831                                   prefix: '#include <linux/blkzoned.h>'))
2832
2833# has_type
2834config_host_data.set('CONFIG_IOVEC',
2835                     cc.has_type('struct iovec',
2836                                 prefix: '#include <sys/uio.h>'))
2837config_host_data.set('HAVE_UTMPX',
2838                     cc.has_type('struct utmpx',
2839                                 prefix: '#include <utmpx.h>'))
2840
2841config_host_data.set('CONFIG_EVENTFD', cc.links('''
2842  #include <sys/eventfd.h>
2843  int main(void) { return eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); }'''))
2844config_host_data.set('CONFIG_FDATASYNC', cc.links(osdep_prefix + '''
2845  int main(void) {
2846  #if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
2847  return fdatasync(0);
2848  #else
2849  #error Not supported
2850  #endif
2851  }'''))
2852
2853has_madvise = cc.links(osdep_prefix + '''
2854  #include <sys/mman.h>
2855  int main(void) { return madvise(NULL, 0, MADV_DONTNEED); }''')
2856missing_madvise_proto = false
2857if has_madvise
2858  # Some platforms (illumos and Solaris before Solaris 11) provide madvise()
2859  # but forget to prototype it. In this case, has_madvise will be true (the
2860  # test program links despite a compile warning). To detect the
2861  # missing-prototype case, we try again with a definitely-bogus prototype.
2862  # This will only compile if the system headers don't provide the prototype;
2863  # otherwise the conflicting prototypes will cause a compiler error.
2864  missing_madvise_proto = cc.links(osdep_prefix + '''>
2865    #include <sys/mman.h>
2866    extern int madvise(int);
2867    int main(void) { return madvise(0); }''')
2868endif
2869config_host_data.set('CONFIG_MADVISE', has_madvise)
2870config_host_data.set('HAVE_MADVISE_WITHOUT_PROTOTYPE', missing_madvise_proto)
2871
2872config_host_data.set('CONFIG_MEMFD', cc.links(osdep_prefix + '''
2873  #include <sys/mman.h>
2874  int main(void) { return memfd_create("foo", MFD_ALLOW_SEALING); }'''))
2875config_host_data.set('CONFIG_OPEN_BY_HANDLE', cc.links(osdep_prefix + '''
2876  #if !defined(AT_EMPTY_PATH)
2877  # error missing definition
2878  #else
2879  int main(void) { struct file_handle fh; return open_by_handle_at(0, &fh, 0); }
2880  #endif'''))
2881
2882# On Darwin posix_madvise() has the same return semantics as plain madvise(),
2883# i.e. errno is set and -1 is returned. That's not really how POSIX defines the
2884# function. On the flip side, it has madvise() which is preferred anyways.
2885if host_os != 'darwin'
2886  config_host_data.set('CONFIG_POSIX_MADVISE', cc.links(osdep_prefix + '''
2887    #include <sys/mman.h>
2888    int main(void) { return posix_madvise(NULL, 0, POSIX_MADV_DONTNEED); }'''))
2889endif
2890
2891config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_W_TID', cc.links(osdep_prefix + '''
2892  #include <pthread.h>
2893
2894  static void *f(void *p) { return NULL; }
2895  int main(void)
2896  {
2897    pthread_t thread;
2898    pthread_create(&thread, 0, f, 0);
2899    pthread_setname_np(thread, "QEMU");
2900    return 0;
2901  }''', dependencies: threads))
2902config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_WO_TID', cc.links(osdep_prefix + '''
2903  #include <pthread.h>
2904
2905  static void *f(void *p) { pthread_setname_np("QEMU"); return NULL; }
2906  int main(void)
2907  {
2908    pthread_t thread;
2909    pthread_create(&thread, 0, f, 0);
2910    return 0;
2911  }''', dependencies: threads))
2912config_host_data.set('CONFIG_PTHREAD_SET_NAME_NP', cc.links(osdep_prefix + '''
2913  #include <pthread.h>
2914  #include <pthread_np.h>
2915
2916  static void *f(void *p) { return NULL; }
2917  int main(void)
2918  {
2919    pthread_t thread;
2920    pthread_create(&thread, 0, f, 0);
2921    pthread_set_name_np(thread, "QEMU");
2922    return 0;
2923  }''', dependencies: threads))
2924config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(osdep_prefix + '''
2925  #include <pthread.h>
2926
2927  int main(void)
2928  {
2929    pthread_condattr_t attr
2930    pthread_condattr_init(&attr);
2931    pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
2932    return 0;
2933  }''', dependencies: threads))
2934config_host_data.set('CONFIG_PTHREAD_AFFINITY_NP', cc.links(osdep_prefix + '''
2935  #include <pthread.h>
2936
2937  static void *f(void *p) { return NULL; }
2938  int main(void)
2939  {
2940    int setsize = CPU_ALLOC_SIZE(64);
2941    pthread_t thread;
2942    cpu_set_t *cpuset;
2943    pthread_create(&thread, 0, f, 0);
2944    cpuset = CPU_ALLOC(64);
2945    CPU_ZERO_S(setsize, cpuset);
2946    pthread_setaffinity_np(thread, setsize, cpuset);
2947    pthread_getaffinity_np(thread, setsize, cpuset);
2948    CPU_FREE(cpuset);
2949    return 0;
2950  }''', dependencies: threads))
2951config_host_data.set('CONFIG_SIGNALFD', cc.links(osdep_prefix + '''
2952  #include <sys/signalfd.h>
2953  int main(void) { return signalfd(-1, NULL, SFD_CLOEXEC); }'''))
2954config_host_data.set('CONFIG_SPLICE', cc.links(osdep_prefix + '''
2955  int main(void)
2956  {
2957    int len, fd = 0;
2958    len = tee(STDIN_FILENO, STDOUT_FILENO, INT_MAX, SPLICE_F_NONBLOCK);
2959    splice(STDIN_FILENO, NULL, fd, NULL, len, SPLICE_F_MOVE);
2960    return 0;
2961  }'''))
2962
2963config_host_data.set('HAVE_MLOCKALL', cc.links(osdep_prefix + '''
2964  #include <sys/mman.h>
2965  int main(void) {
2966    return mlockall(MCL_FUTURE);
2967  }'''))
2968
2969config_host_data.set('HAVE_MLOCK_ONFAULT', cc.links(osdep_prefix + '''
2970  #include <sys/mman.h>
2971  int main(void) {
2972      return mlockall(MCL_FUTURE | MCL_ONFAULT);
2973  }'''))
2974
2975have_l2tpv3 = false
2976if get_option('l2tpv3').allowed() and have_system
2977  have_l2tpv3 = cc.has_type('struct mmsghdr',
2978    prefix: osdep_prefix + '''
2979      #include <sys/socket.h>
2980      #include <linux/ip.h>''')
2981endif
2982config_host_data.set('CONFIG_L2TPV3', have_l2tpv3)
2983
2984have_netmap = false
2985if get_option('netmap').allowed() and have_system
2986  have_netmap = cc.compiles('''
2987    #include <inttypes.h>
2988    #include <net/if.h>
2989    #include <net/netmap.h>
2990    #include <net/netmap_user.h>
2991    #if (NETMAP_API < 11) || (NETMAP_API > 15)
2992    #error
2993    #endif
2994    int main(void) { return 0; }''')
2995  if not have_netmap and get_option('netmap').enabled()
2996    error('Netmap headers not available')
2997  endif
2998endif
2999config_host_data.set('CONFIG_NETMAP', have_netmap)
3000
3001# Work around a system header bug with some kernel/XFS header
3002# versions where they both try to define 'struct fsxattr':
3003# xfs headers will not try to redefine structs from linux headers
3004# if this macro is set.
3005config_host_data.set('HAVE_FSXATTR', cc.links('''
3006  #include <linux/fs.h>
3007  struct fsxattr foo;
3008  int main(void) {
3009    return 0;
3010  }'''))
3011
3012# Some versions of Mac OS X incorrectly define SIZE_MAX
3013config_host_data.set('HAVE_BROKEN_SIZE_MAX', not cc.compiles('''
3014    #include <stdint.h>
3015    #include <stdio.h>
3016    int main(void) {
3017        return printf("%zu", SIZE_MAX);
3018    }''', args: ['-Werror']))
3019
3020# See if 64-bit atomic operations are supported.
3021# Note that without __atomic builtins, we can only
3022# assume atomic loads/stores max at pointer size.
3023config_host_data.set('CONFIG_ATOMIC64', cc.links('''
3024  #include <stdint.h>
3025  int main(void)
3026  {
3027    uint64_t x = 0, y = 0;
3028    y = __atomic_load_n(&x, __ATOMIC_RELAXED);
3029    __atomic_store_n(&x, y, __ATOMIC_RELAXED);
3030    __atomic_compare_exchange_n(&x, &y, x, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
3031    __atomic_exchange_n(&x, y, __ATOMIC_RELAXED);
3032    __atomic_fetch_add(&x, y, __ATOMIC_RELAXED);
3033    return 0;
3034  }''', args: qemu_isa_flags))
3035
3036# has_int128_type is set to false on Emscripten to avoid errors by libffi
3037# during runtime.
3038has_int128_type = host_os != 'emscripten' and cc.compiles('''
3039  __int128_t a;
3040  __uint128_t b;
3041  int main(void) { b = a; }''')
3042config_host_data.set('CONFIG_INT128_TYPE', has_int128_type)
3043
3044has_int128 = has_int128_type and cc.links('''
3045  __int128_t a;
3046  __uint128_t b;
3047  int main (void) {
3048    a = a + b;
3049    b = a * b;
3050    a = a * a;
3051    return 0;
3052  }''')
3053config_host_data.set('CONFIG_INT128', has_int128)
3054
3055if has_int128_type
3056  # "do we have 128-bit atomics which are handled inline and specifically not
3057  # via libatomic". The reason we can't use libatomic is documented in the
3058  # comment starting "GCC is a house divided" in include/qemu/atomic128.h.
3059  # We only care about these operations on 16-byte aligned pointers, so
3060  # force 16-byte alignment of the pointer, which may be greater than
3061  # __alignof(unsigned __int128) for the host.
3062  atomic_test_128 = '''
3063    int main(int ac, char **av) {
3064      __uint128_t *p = __builtin_assume_aligned(av[ac - 1], 16);
3065      p[1] = __atomic_load_n(&p[0], __ATOMIC_RELAXED);
3066      __atomic_store_n(&p[2], p[3], __ATOMIC_RELAXED);
3067      __atomic_compare_exchange_n(&p[4], &p[5], p[6], 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
3068      return 0;
3069    }'''
3070  has_atomic128 = cc.links(atomic_test_128, args: qemu_isa_flags)
3071
3072  config_host_data.set('CONFIG_ATOMIC128', has_atomic128)
3073
3074  if not has_atomic128
3075    # Even with __builtin_assume_aligned, the above test may have failed
3076    # without optimization enabled.  Try again with optimizations locally
3077    # enabled for the function.  See
3078    #   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107389
3079    has_atomic128_opt = cc.links('__attribute__((optimize("O1")))' + atomic_test_128,
3080                                 args: qemu_isa_flags)
3081    config_host_data.set('CONFIG_ATOMIC128_OPT', has_atomic128_opt)
3082
3083    if not has_atomic128_opt
3084      config_host_data.set('CONFIG_CMPXCHG128', cc.links('''
3085        int main(void)
3086        {
3087          __uint128_t x = 0, y = 0;
3088          __sync_val_compare_and_swap_16(&x, y, x);
3089          return 0;
3090        }
3091      ''', args: qemu_isa_flags))
3092    endif
3093  endif
3094endif
3095
3096config_host_data.set('CONFIG_GETAUXVAL', cc.links(osdep_prefix + '''
3097  #include <sys/auxv.h>
3098  int main(void) {
3099    return getauxval(AT_HWCAP) == 0;
3100  }'''))
3101
3102config_host_data.set('CONFIG_ELF_AUX_INFO', cc.links(osdep_prefix + '''
3103  #include <sys/auxv.h>
3104  int main(void) {
3105    unsigned long hwcap = 0;
3106    elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap));
3107    return hwcap;
3108  }'''))
3109
3110config_host_data.set('CONFIG_USBFS', have_linux_user and cc.compiles('''
3111  #include <linux/usbdevice_fs.h>
3112
3113  #ifndef USBDEVFS_GET_CAPABILITIES
3114  #error "USBDEVFS_GET_CAPABILITIES undefined"
3115  #endif
3116
3117  #ifndef USBDEVFS_DISCONNECT_CLAIM
3118  #error "USBDEVFS_DISCONNECT_CLAIM undefined"
3119  #endif
3120
3121  int main(void) { return 0; }'''))
3122
3123have_keyring = get_option('keyring') \
3124  .require(host_os == 'linux', error_message: 'keyring is only available on Linux') \
3125  .require(cc.compiles('''
3126    #include <errno.h>
3127    #include <asm/unistd.h>
3128    #include <linux/keyctl.h>
3129    #include <sys/syscall.h>
3130    #include <unistd.h>
3131    int main(void) {
3132        return syscall(__NR_keyctl, KEYCTL_READ, 0, NULL, NULL, 0);
3133    }'''), error_message: 'keyctl syscall not available on this system').allowed()
3134config_host_data.set('CONFIG_SECRET_KEYRING', have_keyring)
3135
3136have_cpuid_h = cc.links('''
3137  #include <cpuid.h>
3138  int main(void) {
3139    unsigned a, b, c, d;
3140    unsigned max = __get_cpuid_max(0, 0);
3141
3142    if (max >= 1) {
3143        __cpuid(1, a, b, c, d);
3144    }
3145
3146    if (max >= 7) {
3147        __cpuid_count(7, 0, a, b, c, d);
3148    }
3149
3150    return 0;
3151  }''')
3152config_host_data.set('CONFIG_CPUID_H', have_cpuid_h)
3153
3154# Don't bother to advertise asm/hwprobe.h for old versions that do
3155# not contain RISCV_HWPROBE_EXT_ZBA.
3156config_host_data.set('CONFIG_ASM_HWPROBE_H',
3157                     cc.has_header_symbol('asm/hwprobe.h',
3158                                          'RISCV_HWPROBE_EXT_ZBA'))
3159
3160if have_cpuid_h
3161  have_avx2 = cc.links('''
3162    #include <immintrin.h>
3163    static int __attribute__((target("avx2"))) bar(void *a) {
3164      __m256i x = *(__m256i *)a;
3165      return _mm256_testz_si256(x, x);
3166    }
3167    int main(int argc, char *argv[]) { return bar(argv[argc - 1]); }
3168  ''')
3169  have_avx512bw = cc.links('''
3170    #include <immintrin.h>
3171    static int __attribute__((target("avx512bw"))) bar(void *a) {
3172      __m512i *x = a;
3173      __m512i res= _mm512_abs_epi8(*x);
3174      return res[1];
3175    }
3176    int main(int argc, char *argv[]) { return bar(argv[0]); }
3177  ''')
3178  if get_option('x86_version') >= '3' and not have_avx2
3179    error('Cannot enable AVX optimizations due to missing intrinsics')
3180  elif get_option('x86_version') >= '4' and not have_avx512bw
3181    error('Cannot enable AVX512 optimizations due to missing intrinsics')
3182  endif
3183else
3184  have_avx2 = false
3185  have_avx512bw = false
3186  if get_option('x86_version') >= '3'
3187    error('Cannot enable AVX optimizations due to missing cpuid.h')
3188  endif
3189endif
3190config_host_data.set('CONFIG_AVX2_OPT', have_avx2)
3191config_host_data.set('CONFIG_AVX512BW_OPT', have_avx512bw)
3192
3193# For both AArch64 and AArch32, detect if builtins are available.
3194config_host_data.set('CONFIG_ARM_AES_BUILTIN', cc.compiles('''
3195    #include <arm_neon.h>
3196    #ifndef __ARM_FEATURE_AES
3197    __attribute__((target("+crypto")))
3198    #endif
3199    void foo(uint8x16_t *p) { *p = vaesmcq_u8(*p); }
3200  '''))
3201
3202if get_option('membarrier').disabled()
3203  have_membarrier = false
3204elif host_os == 'windows'
3205  have_membarrier = true
3206elif host_os == 'linux'
3207  have_membarrier = cc.compiles('''
3208    #include <linux/membarrier.h>
3209    #include <sys/syscall.h>
3210    #include <unistd.h>
3211    #include <stdlib.h>
3212    int main(void) {
3213        syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
3214        syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0);
3215        exit(0);
3216    }''')
3217endif
3218config_host_data.set('CONFIG_MEMBARRIER', get_option('membarrier') \
3219  .require(have_membarrier, error_message: 'membarrier system call not available') \
3220  .allowed())
3221
3222have_afalg = get_option('crypto_afalg') \
3223  .require(cc.compiles(osdep_prefix + '''
3224    #include <sys/socket.h>
3225    #include <linux/if_alg.h>
3226    int main(void) {
3227      int sock;
3228      sock = socket(AF_ALG, SOCK_SEQPACKET, 0);
3229      return sock;
3230    }
3231  '''), error_message: 'AF_ALG requested but could not be detected').allowed()
3232config_host_data.set('CONFIG_AF_ALG', have_afalg)
3233
3234config_host_data.set('CONFIG_AF_VSOCK', cc.has_header_symbol(
3235  'linux/vm_sockets.h', 'AF_VSOCK',
3236  prefix: '#include <sys/socket.h>',
3237))
3238
3239have_vss = false
3240have_vss_sdk = false # old xp/2003 SDK
3241if host_os == 'windows' and 'cpp' in all_languages
3242  have_vss = cxx.compiles('''
3243    #define __MIDL_user_allocate_free_DEFINED__
3244    #include <vss.h>
3245    int main(void) { return VSS_CTX_BACKUP; }''')
3246  have_vss_sdk = cxx.has_header('vscoordint.h')
3247endif
3248config_host_data.set('HAVE_VSS_SDK', have_vss_sdk)
3249
3250# Older versions of MinGW do not import _lock_file and _unlock_file properly.
3251# This was fixed for v6.0.0 with commit b48e3ac8969d.
3252if host_os == 'windows'
3253  config_host_data.set('HAVE__LOCK_FILE', cc.links('''
3254    #include <stdio.h>
3255    int main(void) {
3256      _lock_file(NULL);
3257      _unlock_file(NULL);
3258      return 0;
3259    }''', name: '_lock_file and _unlock_file'))
3260endif
3261
3262if spice.found()
3263  config_host_data.set('HAVE_SPICE_QXL_GL_SCANOUT2',
3264    cc.has_function('spice_qxl_gl_scanout2', dependencies: spice))
3265endif
3266
3267if host_os == 'windows'
3268  mingw_has_setjmp_longjmp = cc.links('''
3269    #include <setjmp.h>
3270    int main(void) {
3271      /*
3272       * These functions are not available in setjmp header, but may be
3273       * available at link time, from libmingwex.a.
3274       */
3275      extern int __mingw_setjmp(jmp_buf);
3276      extern void __attribute__((noreturn)) __mingw_longjmp(jmp_buf, int);
3277      jmp_buf env;
3278      __mingw_setjmp(env);
3279      __mingw_longjmp(env, 0);
3280    }
3281  ''', name: 'mingw setjmp and longjmp')
3282
3283  if cpu == 'aarch64' and not mingw_has_setjmp_longjmp
3284    error('mingw must provide setjmp/longjmp for windows-arm64')
3285  endif
3286endif
3287
3288# Detect host pointer size for the target configuration loop.
3289host_long_bits = cc.sizeof('void *') * 8
3290
3291########################
3292# Target configuration #
3293########################
3294
3295minikconf = find_program('scripts/minikconf.py')
3296
3297config_all_accel = {}
3298config_all_devices = {}
3299config_devices_mak_list = []
3300config_devices_h = {}
3301config_target_h = {}
3302config_target_mak = {}
3303config_base_arch_mak = {}
3304
3305disassemblers = {
3306  'alpha' : ['CONFIG_ALPHA_DIS'],
3307  'avr' : ['CONFIG_AVR_DIS'],
3308  'hexagon' : ['CONFIG_HEXAGON_DIS'],
3309  'hppa' : ['CONFIG_HPPA_DIS'],
3310  'i386' : ['CONFIG_I386_DIS'],
3311  'x86_64' : ['CONFIG_I386_DIS'],
3312  'm68k' : ['CONFIG_M68K_DIS'],
3313  'microblaze' : ['CONFIG_MICROBLAZE_DIS'],
3314  'mips' : ['CONFIG_MIPS_DIS'],
3315  'or1k' : ['CONFIG_OPENRISC_DIS'],
3316  'ppc' : ['CONFIG_PPC_DIS'],
3317  'riscv' : ['CONFIG_RISCV_DIS'],
3318  'rx' : ['CONFIG_RX_DIS'],
3319  's390' : ['CONFIG_S390_DIS'],
3320  'sh4' : ['CONFIG_SH4_DIS'],
3321  'sparc' : ['CONFIG_SPARC_DIS'],
3322  'xtensa' : ['CONFIG_XTENSA_DIS'],
3323  'loongarch' : ['CONFIG_LOONGARCH_DIS'],
3324}
3325
3326have_ivshmem = config_host_data.get('CONFIG_EVENTFD')
3327host_kconfig = \
3328  (get_option('fuzzing') ? ['CONFIG_FUZZ=y'] : []) + \
3329  (have_tpm ? ['CONFIG_TPM=y'] : []) + \
3330  (pixman.found() ? ['CONFIG_PIXMAN=y'] : []) + \
3331  (spice.found() ? ['CONFIG_SPICE=y'] : []) + \
3332  (have_ivshmem ? ['CONFIG_IVSHMEM=y'] : []) + \
3333  (opengl.found() ? ['CONFIG_OPENGL=y'] : []) + \
3334  (libcbor.found() ? ['CONFIG_LIBCBOR=y'] : []) + \
3335  (gnutls.found() ? ['CONFIG_GNUTLS=y'] : []) + \
3336  (x11.found() ? ['CONFIG_X11=y'] : []) + \
3337  (fdt.found() ? ['CONFIG_FDT=y'] : []) + \
3338  (have_vhost_user ? ['CONFIG_VHOST_USER=y'] : []) + \
3339  (have_vhost_vdpa ? ['CONFIG_VHOST_VDPA=y'] : []) + \
3340  (have_vhost_kernel ? ['CONFIG_VHOST_KERNEL=y'] : []) + \
3341  (have_virtfs ? ['CONFIG_VIRTFS=y'] : []) + \
3342  (host_os == 'linux' ? ['CONFIG_LINUX=y'] : []) + \
3343  (multiprocess_allowed ? ['CONFIG_MULTIPROCESS_ALLOWED=y'] : []) + \
3344  (vfio_user_server_allowed ? ['CONFIG_VFIO_USER_SERVER_ALLOWED=y'] : []) + \
3345  (hv_balloon ? ['CONFIG_HV_BALLOON_POSSIBLE=y'] : []) + \
3346  (have_rust ? ['CONFIG_HAVE_RUST=y'] : [])
3347
3348ignored = [ 'TARGET_XML_FILES', 'TARGET_ABI_DIR', 'TARGET_ARCH' ]
3349
3350default_targets = 'CONFIG_DEFAULT_TARGETS' in config_host
3351actual_target_dirs = []
3352fdt_required = []
3353foreach target : target_dirs
3354  config_target = { 'TARGET_NAME': target.split('-')[0] }
3355  if target.endswith('linux-user')
3356    if host_os != 'linux'
3357      if default_targets
3358        continue
3359      endif
3360      error('Target @0@ is only available on a Linux host'.format(target))
3361    endif
3362    config_target += { 'CONFIG_LINUX_USER': 'y' }
3363  elif target.endswith('bsd-user')
3364    if host_os not in bsd_oses
3365      if default_targets
3366        continue
3367      endif
3368      error('Target @0@ is only available on a BSD host'.format(target))
3369    endif
3370    config_target += { 'CONFIG_BSD_USER': 'y' }
3371  elif target.endswith('softmmu')
3372    config_target += { 'CONFIG_SYSTEM_ONLY': 'y' }
3373    config_target += { 'CONFIG_SOFTMMU': 'y' }
3374  endif
3375  if target.endswith('-user')
3376    config_target += {
3377      'CONFIG_USER_ONLY': 'y',
3378      'CONFIG_QEMU_INTERP_PREFIX':
3379        get_option('interp_prefix').replace('%M', config_target['TARGET_NAME']),
3380      'CONFIG_QEMU_RTSIG_MAP': get_option('rtsig_map'),
3381    }
3382  endif
3383
3384  config_target += keyval.load('configs/targets' / target + '.mak')
3385
3386  target_kconfig = []
3387  foreach sym: accelerators
3388    # Disallow 64-bit on 32-bit emulation and virtualization
3389    if host_long_bits < config_target['TARGET_LONG_BITS'].to_int()
3390      continue
3391    endif
3392    if sym == 'CONFIG_TCG' or target in accelerator_targets.get(sym, [])
3393      config_target += { sym: 'y' }
3394      config_all_accel += { sym: 'y' }
3395      target_kconfig += [ sym + '=y' ]
3396    endif
3397  endforeach
3398  if target_kconfig.length() == 0
3399    if default_targets
3400      continue
3401    endif
3402    error('No accelerator available for target @0@'.format(target))
3403  endif
3404
3405  if 'TARGET_NEED_FDT' in config_target and not fdt.found()
3406    if default_targets
3407      warning('Disabling ' + target + ' due to missing libfdt')
3408    else
3409      fdt_required += target
3410    endif
3411    continue
3412  endif
3413
3414  actual_target_dirs += target
3415
3416  # Add default keys
3417  config_target += { 'TARGET_' + config_target['TARGET_ARCH'].to_upper(): 'y' }
3418  if 'TARGET_BASE_ARCH' not in config_target
3419    config_target += {'TARGET_BASE_ARCH': config_target['TARGET_ARCH']}
3420  endif
3421  if 'TARGET_ABI_DIR' not in config_target
3422    config_target += {'TARGET_ABI_DIR': config_target['TARGET_ARCH']}
3423  endif
3424  if 'TARGET_BIG_ENDIAN' not in config_target
3425    config_target += {'TARGET_BIG_ENDIAN': 'n'}
3426  endif
3427
3428  foreach k, v: disassemblers
3429    if host_arch.startswith(k) or config_target['TARGET_BASE_ARCH'].startswith(k)
3430      foreach sym: v
3431        config_target += { sym: 'y' }
3432      endforeach
3433    endif
3434  endforeach
3435
3436  config_target_data = configuration_data()
3437  foreach k, v: config_target
3438    if not k.startswith('TARGET_') and not k.startswith('CONFIG_')
3439      # do nothing
3440    elif ignored.contains(k)
3441      # do nothing
3442    elif k == 'TARGET_BASE_ARCH'
3443      # Note that TARGET_BASE_ARCH ends up in config-target.h but it is
3444      # not used to select files from sourcesets.
3445      config_target_data.set('TARGET_' + v.to_upper(), 1)
3446    elif k == 'TARGET_NAME' or k == 'CONFIG_QEMU_INTERP_PREFIX'
3447      config_target_data.set_quoted(k, v)
3448    elif v == 'y'
3449      config_target_data.set(k, 1)
3450    elif v == 'n'
3451      config_target_data.set(k, 0)
3452    else
3453      config_target_data.set(k, v)
3454    endif
3455  endforeach
3456  config_target_data.set('QEMU_ARCH',
3457                         'QEMU_ARCH_' + config_target['TARGET_BASE_ARCH'].to_upper())
3458  config_target_h += {target: configure_file(output: target + '-config-target.h',
3459                                               configuration: config_target_data)}
3460
3461  if target.endswith('-softmmu')
3462    target_kconfig += 'CONFIG_' + config_target['TARGET_ARCH'].to_upper() + '=y'
3463    target_kconfig += 'CONFIG_TARGET_BIG_ENDIAN=' + config_target['TARGET_BIG_ENDIAN']
3464
3465    # PVG is not cross-architecture.  Use accelerator_targets as a proxy to
3466    # figure out which target can support PVG on this host
3467    if pvg.found() and target in accelerator_targets.get('CONFIG_HVF', [])
3468      target_kconfig += 'CONFIG_MAC_PVG=y'
3469    endif
3470
3471    config_input = meson.get_external_property(target, 'default')
3472    config_devices_mak = target + '-config-devices.mak'
3473    config_devices_mak = configure_file(
3474      input: ['configs/devices' / target / config_input + '.mak', 'Kconfig'],
3475      output: config_devices_mak,
3476      depfile: config_devices_mak + '.d',
3477      capture: true,
3478      command: [minikconf,
3479                get_option('default_devices') ? '--defconfig' : '--allnoconfig',
3480                config_devices_mak, '@DEPFILE@', '@INPUT@',
3481                host_kconfig, target_kconfig])
3482
3483    config_devices_data = configuration_data()
3484    config_devices = keyval.load(config_devices_mak)
3485    foreach k, v: config_devices
3486      config_devices_data.set(k, 1)
3487    endforeach
3488    config_devices_mak_list += config_devices_mak
3489    config_devices_h += {target: configure_file(output: target + '-config-devices.h',
3490                                                configuration: config_devices_data)}
3491    config_target += config_devices
3492    config_all_devices += config_devices
3493  endif
3494  config_target_mak += {target: config_target}
3495
3496  # build a merged config for all targets with the same TARGET_BASE_ARCH
3497  target_base_arch = config_target['TARGET_BASE_ARCH']
3498  config_base_arch = config_base_arch_mak.get(target_base_arch, {}) + config_target
3499  config_base_arch_mak += {target_base_arch: config_base_arch}
3500endforeach
3501target_dirs = actual_target_dirs
3502
3503target_configs_h = []
3504foreach target: target_dirs
3505  target_configs_h += config_target_h[target]
3506  target_configs_h += config_devices_h.get(target, [])
3507endforeach
3508genh += custom_target('config-poison.h',
3509                      input: [target_configs_h],
3510                      output: 'config-poison.h',
3511                      capture: true,
3512                      command: [find_program('scripts/make-config-poison.sh'),
3513                                target_configs_h])
3514
3515if fdt_required.length() > 0
3516  error('fdt disabled but required by targets ' + ', '.join(fdt_required))
3517endif
3518
3519###############
3520# Subprojects #
3521###############
3522
3523libvfio_user_dep = not_found
3524if have_system and vfio_user_server_allowed
3525  libvfio_user_proj = subproject('libvfio-user', required: true)
3526  libvfio_user_dep = libvfio_user_proj.get_variable('libvfio_user_dep')
3527endif
3528
3529vhost_user = not_found
3530if host_os == 'linux' and have_vhost_user
3531  libvhost_user = subproject('libvhost-user')
3532  vhost_user = libvhost_user.get_variable('vhost_user_dep')
3533endif
3534
3535libvduse = not_found
3536if have_libvduse
3537  libvduse_proj = subproject('libvduse')
3538  libvduse = libvduse_proj.get_variable('libvduse_dep')
3539endif
3540
3541#####################
3542# Generated sources #
3543#####################
3544
3545config_host_h = configure_file(output: 'config-host.h', configuration: config_host_data)
3546genh += config_host_h
3547
3548hxtool = find_program('scripts/hxtool')
3549shaderinclude = find_program('scripts/shaderinclude.py')
3550qapi_gen = find_program('scripts/qapi-gen.py')
3551qapi_gen_depends = [ meson.current_source_dir() / 'scripts/qapi/__init__.py',
3552                     meson.current_source_dir() / 'scripts/qapi/commands.py',
3553                     meson.current_source_dir() / 'scripts/qapi/common.py',
3554                     meson.current_source_dir() / 'scripts/qapi/error.py',
3555                     meson.current_source_dir() / 'scripts/qapi/events.py',
3556                     meson.current_source_dir() / 'scripts/qapi/expr.py',
3557                     meson.current_source_dir() / 'scripts/qapi/gen.py',
3558                     meson.current_source_dir() / 'scripts/qapi/introspect.py',
3559                     meson.current_source_dir() / 'scripts/qapi/main.py',
3560                     meson.current_source_dir() / 'scripts/qapi/parser.py',
3561                     meson.current_source_dir() / 'scripts/qapi/schema.py',
3562                     meson.current_source_dir() / 'scripts/qapi/source.py',
3563                     meson.current_source_dir() / 'scripts/qapi/types.py',
3564                     meson.current_source_dir() / 'scripts/qapi/features.py',
3565                     meson.current_source_dir() / 'scripts/qapi/visit.py',
3566                     meson.current_source_dir() / 'scripts/qapi-gen.py'
3567]
3568
3569tracetool = [
3570  python, files('scripts/tracetool.py'),
3571   '--backend=' + ','.join(get_option('trace_backends'))
3572]
3573tracetool_depends = files(
3574  'scripts/tracetool/backend/log.py',
3575  'scripts/tracetool/backend/__init__.py',
3576  'scripts/tracetool/backend/dtrace.py',
3577  'scripts/tracetool/backend/ftrace.py',
3578  'scripts/tracetool/backend/simple.py',
3579  'scripts/tracetool/backend/syslog.py',
3580  'scripts/tracetool/backend/ust.py',
3581  'scripts/tracetool/format/ust_events_c.py',
3582  'scripts/tracetool/format/ust_events_h.py',
3583  'scripts/tracetool/format/__init__.py',
3584  'scripts/tracetool/format/d.py',
3585  'scripts/tracetool/format/simpletrace_stap.py',
3586  'scripts/tracetool/format/c.py',
3587  'scripts/tracetool/format/h.py',
3588  'scripts/tracetool/format/log_stap.py',
3589  'scripts/tracetool/format/stap.py',
3590  'scripts/tracetool/__init__.py',
3591)
3592
3593qemu_version_cmd = [find_program('scripts/qemu-version.sh'),
3594                    meson.current_source_dir(),
3595                    get_option('pkgversion'), meson.project_version()]
3596qemu_version = custom_target('qemu-version.h',
3597                             output: 'qemu-version.h',
3598                             command: qemu_version_cmd,
3599                             capture: true,
3600                             build_by_default: true,
3601                             build_always_stale: true)
3602genh += qemu_version
3603
3604hxdep = []
3605hx_headers = [
3606  ['qemu-options.hx', 'qemu-options.def'],
3607  ['qemu-img-cmds.hx', 'qemu-img-cmds.h'],
3608]
3609if have_system
3610  hx_headers += [
3611    ['hmp-commands.hx', 'hmp-commands.h'],
3612    ['hmp-commands-info.hx', 'hmp-commands-info.h'],
3613  ]
3614endif
3615foreach d : hx_headers
3616  hxdep += custom_target(d[1],
3617                input: files(d[0]),
3618                output: d[1],
3619                capture: true,
3620                command: [hxtool, '-h', '@INPUT0@'])
3621endforeach
3622genh += hxdep
3623
3624###############
3625# Trace files #
3626###############
3627
3628# TODO: add each directory to the subdirs from its own meson.build, once
3629# we have those
3630trace_events_subdirs = [
3631  'crypto',
3632  'qapi',
3633  'qom',
3634  'monitor',
3635  'util',
3636  'gdbstub',
3637]
3638if have_linux_user
3639  trace_events_subdirs += [ 'linux-user' ]
3640endif
3641if have_bsd_user
3642  trace_events_subdirs += [ 'bsd-user' ]
3643endif
3644if have_block
3645  trace_events_subdirs += [
3646    'authz',
3647    'block',
3648    'chardev',
3649    'io',
3650    'nbd',
3651    'scsi',
3652  ]
3653endif
3654if have_system
3655  trace_events_subdirs += [
3656    'accel/hvf',
3657    'accel/kvm',
3658    'audio',
3659    'backends',
3660    'backends/tpm',
3661    'ebpf',
3662    'hw/9pfs',
3663    'hw/acpi',
3664    'hw/adc',
3665    'hw/alpha',
3666    'hw/arm',
3667    'hw/audio',
3668    'hw/block',
3669    'hw/char',
3670    'hw/display',
3671    'hw/dma',
3672    'hw/fsi',
3673    'hw/hyperv',
3674    'hw/i2c',
3675    'hw/i3c',
3676    'hw/i386',
3677    'hw/i386/xen',
3678    'hw/i386/kvm',
3679    'hw/ide',
3680    'hw/input',
3681    'hw/intc',
3682    'hw/isa',
3683    'hw/mem',
3684    'hw/mips',
3685    'hw/misc',
3686    'hw/misc/macio',
3687    'hw/net',
3688    'hw/net/can',
3689    'hw/nubus',
3690    'hw/nvme',
3691    'hw/nvram',
3692    'hw/pci',
3693    'hw/pci-host',
3694    'hw/ppc',
3695    'hw/rtc',
3696    'hw/riscv',
3697    'hw/s390x',
3698    'hw/scsi',
3699    'hw/sd',
3700    'hw/sensor',
3701    'hw/sh4',
3702    'hw/sparc',
3703    'hw/sparc64',
3704    'hw/ssi',
3705    'hw/timer',
3706    'hw/tpm',
3707    'hw/uefi',
3708    'hw/ufs',
3709    'hw/usb',
3710    'hw/vfio',
3711    'hw/vfio-user',
3712    'hw/virtio',
3713    'hw/vmapple',
3714    'hw/watchdog',
3715    'hw/xen',
3716    'hw/gpio',
3717    'migration',
3718    'net',
3719    'system',
3720    'ui',
3721    'hw/remote',
3722  ]
3723endif
3724if have_system or have_user
3725  trace_events_subdirs += [
3726    'accel/tcg',
3727    'hw/core',
3728    'target/arm',
3729    'target/arm/hvf',
3730    'target/hppa',
3731    'target/i386',
3732    'target/i386/kvm',
3733    'target/loongarch',
3734    'target/mips/tcg',
3735    'target/ppc',
3736    'target/riscv',
3737    'target/s390x',
3738    'target/s390x/kvm',
3739    'target/sparc',
3740  ]
3741endif
3742
3743###################
3744# Collect sources #
3745###################
3746
3747authz_ss = ss.source_set()
3748blockdev_ss = ss.source_set()
3749block_ss = ss.source_set()
3750chardev_ss = ss.source_set()
3751common_ss = ss.source_set()
3752crypto_ss = ss.source_set()
3753hwcore_ss = ss.source_set()
3754io_ss = ss.source_set()
3755qmp_ss = ss.source_set()
3756qom_ss = ss.source_set()
3757system_ss = ss.source_set()
3758specific_fuzz_ss = ss.source_set()
3759specific_ss = ss.source_set()
3760rust_devices_ss = ss.source_set()
3761stub_ss = ss.source_set()
3762trace_ss = ss.source_set()
3763user_ss = ss.source_set()
3764util_ss = ss.source_set()
3765
3766# accel modules
3767qtest_module_ss = ss.source_set()
3768
3769modules = {}
3770target_modules = {}
3771plugin_modules = []
3772hw_arch = {}
3773target_arch = {}
3774target_system_arch = {}
3775target_user_arch = {}
3776hw_common_arch = {}
3777target_common_arch = {}
3778target_common_system_arch = {}
3779
3780# NOTE: the trace/ subdirectory needs the qapi_trace_events variable
3781# that is filled in by qapi/.
3782subdir('qapi')
3783subdir('qobject')
3784subdir('stubs')
3785subdir('trace')
3786subdir('util')
3787subdir('qom')
3788subdir('authz')
3789subdir('crypto')
3790subdir('ui')
3791subdir('gdbstub')
3792if have_system
3793  subdir('hw')
3794else
3795  subdir('hw/core')
3796endif
3797
3798if enable_modules
3799  libmodulecommon = static_library('module-common', files('module-common.c') + genh, pic: true, c_args: '-DBUILD_DSO')
3800  modulecommon = declare_dependency(objects: libmodulecommon.extract_all_objects(recursive: false), compile_args: '-DBUILD_DSO')
3801endif
3802
3803qom_ss = qom_ss.apply({})
3804libqom = static_library('qom', qom_ss.sources() + genh,
3805                        dependencies: [qom_ss.dependencies()],
3806                        build_by_default: false)
3807qom = declare_dependency(objects: libqom.extract_all_objects(recursive: false),
3808                         dependencies: qom_ss.dependencies())
3809
3810event_loop_base = files('event-loop-base.c')
3811event_loop_base = static_library('event-loop-base',
3812                                 sources: event_loop_base + genh,
3813                                 build_by_default: false)
3814event_loop_base = declare_dependency(objects: event_loop_base.extract_all_objects(recursive: false),
3815                                     dependencies: [qom])
3816
3817stub_ss = stub_ss.apply({})
3818
3819util_ss.add_all(trace_ss)
3820util_ss = util_ss.apply({})
3821libqemuutil = static_library('qemuutil',
3822                             build_by_default: false,
3823                             sources: util_ss.sources() + stub_ss.sources() + genh,
3824                             dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc])
3825qemuutil_deps = [event_loop_base]
3826if host_os != 'windows'
3827  qemuutil_deps += [rt]
3828endif
3829qemuutil = declare_dependency(link_with: libqemuutil,
3830                              sources: genh + version_res,
3831                              dependencies: qemuutil_deps)
3832
3833if have_system or have_user
3834  decodetree = generator(find_program('scripts/decodetree.py'),
3835                         output: 'decode-@BASENAME@.c.inc',
3836                         arguments: ['@INPUT@', '@EXTRA_ARGS@', '-o', '@OUTPUT@'])
3837  subdir('libdecnumber')
3838  subdir('target')
3839endif
3840
3841subdir('audio')
3842subdir('io')
3843subdir('chardev')
3844subdir('fsdev')
3845subdir('dump')
3846
3847if have_block
3848  block_ss.add(files(
3849    'block.c',
3850    'blockjob.c',
3851    'job.c',
3852    'qemu-io-cmds.c',
3853  ))
3854  if config_host_data.get('CONFIG_REPLICATION')
3855    block_ss.add(files('replication.c'))
3856  endif
3857
3858  subdir('nbd')
3859  subdir('scsi')
3860  subdir('block')
3861
3862  blockdev_ss.add(files(
3863    'blockdev.c',
3864    'blockdev-nbd.c',
3865    'iothread.c',
3866    'job-qmp.c',
3867  ))
3868
3869  # os-posix.c contains POSIX-specific functions used by qemu-storage-daemon,
3870  # os-win32.c does not
3871  if host_os == 'windows'
3872    system_ss.add(files('os-win32.c'))
3873  elif host_os == 'emscripten'
3874    blockdev_ss.add(files('os-wasm.c'))
3875  else
3876    blockdev_ss.add(files('os-posix.c'))
3877  endif
3878endif
3879
3880common_ss.add(files('cpu-common.c'))
3881specific_ss.add(files('cpu-target.c'))
3882
3883subdir('system')
3884
3885# Work around a gcc bug/misfeature wherein constant propagation looks
3886# through an alias:
3887#   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99696
3888# to guess that a const variable is always zero.  Without lto, this is
3889# impossible, as the alias is restricted to page-vary-common.c.  Indeed,
3890# without lto, not even the alias is required -- we simply use different
3891# declarations in different compilation units.
3892pagevary = files('page-vary-common.c')
3893if get_option('b_lto')
3894  pagevary_flags = ['-fno-lto']
3895  if get_option('cfi')
3896    pagevary_flags += '-fno-sanitize=cfi-icall'
3897  endif
3898  pagevary = static_library('page-vary-common', sources: pagevary + genh,
3899                            c_args: pagevary_flags)
3900  pagevary = declare_dependency(link_with: pagevary)
3901endif
3902common_ss.add(pagevary)
3903specific_ss.add(files('page-target.c', 'page-vary-target.c'))
3904
3905common_ss.add(files('target-info.c'))
3906specific_ss.add(files('target-info-stub.c'))
3907
3908subdir('backends')
3909subdir('disas')
3910subdir('migration')
3911subdir('monitor')
3912subdir('net')
3913subdir('replay')
3914subdir('semihosting')
3915subdir('stats')
3916subdir('tcg')
3917subdir('fpu')
3918subdir('accel')
3919subdir('plugins')
3920subdir('ebpf')
3921
3922if 'CONFIG_TCG' in config_all_accel
3923  subdir('contrib/plugins')
3924endif
3925
3926common_user_inc = []
3927
3928subdir('common-user')
3929subdir('bsd-user')
3930subdir('linux-user')
3931
3932# needed for fuzzing binaries
3933subdir('tests/qtest/libqos')
3934subdir('tests/qtest/fuzz')
3935
3936# accel modules
3937target_modules += { 'accel' : { 'qtest': qtest_module_ss }}
3938
3939##############################################
3940# Internal static_libraries and dependencies #
3941##############################################
3942
3943modinfo_collect = find_program('scripts/modinfo-collect.py')
3944modinfo_generate = find_program('scripts/modinfo-generate.py')
3945modinfo_files = []
3946
3947block_mods = []
3948system_mods = []
3949emulator_modules = []
3950foreach d, list : modules
3951  if not (d == 'block' ? have_block : have_system)
3952    continue
3953  endif
3954
3955  foreach m, module_ss : list
3956    if enable_modules
3957      module_ss.add(modulecommon)
3958      module_ss = module_ss.apply(config_all_devices, strict: false)
3959      sl = static_library(d + '-' + m, [genh, module_ss.sources()],
3960                          dependencies: module_ss.dependencies(), pic: true)
3961      if d == 'block'
3962        block_mods += sl
3963      else
3964        system_mods += sl
3965      endif
3966      emulator_modules += shared_module(sl.name(),
3967                    name_prefix: '',
3968                    objects: sl.extract_all_objects(recursive: false),
3969                    dependencies: module_ss.dependencies(),
3970                    install: true,
3971                    install_dir: qemu_moddir)
3972      if module_ss.sources() != []
3973        modinfo_files += custom_target(d + '-' + m + '.modinfo',
3974                                       output: d + '-' + m + '.modinfo',
3975                                       input: sl.extract_all_objects(recursive: true),
3976                                       capture: true,
3977                                       command: [modinfo_collect, '@INPUT@'])
3978      endif
3979    else
3980      if d == 'block'
3981        block_ss.add_all(module_ss)
3982      else
3983        system_ss.add_all(module_ss)
3984      endif
3985    endif
3986  endforeach
3987endforeach
3988
3989foreach d, list : target_modules
3990  foreach m, module_ss : list
3991    if enable_modules
3992      module_ss.add(modulecommon)
3993      foreach target : target_dirs
3994        if target.endswith('-softmmu')
3995          config_target = config_target_mak[target]
3996          target_inc = [include_directories('target' / config_target['TARGET_BASE_ARCH'])]
3997          c_args = ['-DCOMPILING_PER_TARGET',
3998                    '-DCONFIG_TARGET="@0@-config-target.h"'.format(target),
3999                    '-DCONFIG_DEVICES="@0@-config-devices.h"'.format(target)]
4000          target_module_ss = module_ss.apply(config_target, strict: false)
4001          if target_module_ss.sources() != []
4002            module_name = d + '-' + m + '-' + config_target['TARGET_NAME']
4003            sl = static_library(module_name,
4004                                [genh, target_module_ss.sources()],
4005                                dependencies: target_module_ss.dependencies(),
4006                                include_directories: target_inc,
4007                                c_args: c_args,
4008                                pic: true)
4009            system_mods += sl
4010            emulator_modules += shared_module(sl.name(),
4011                    name_prefix: '',
4012                    objects: sl.extract_all_objects(recursive: false),
4013                    dependencies: target_module_ss.dependencies(),
4014                    install: true,
4015                    install_dir: qemu_moddir)
4016            modinfo_files += custom_target(module_name + '.modinfo',
4017                                           output: module_name + '.modinfo',
4018                                           input: sl.extract_all_objects(recursive: true),
4019                                           capture: true,
4020                                           command: [modinfo_collect, '--target', target, '@INPUT@'])
4021          endif
4022        endif
4023      endforeach
4024    else
4025      specific_ss.add_all(module_ss)
4026    endif
4027  endforeach
4028endforeach
4029
4030if enable_modules
4031  foreach target : target_dirs
4032    if target.endswith('-softmmu')
4033      config_target = config_target_mak[target]
4034      config_devices_mak = target + '-config-devices.mak'
4035      modinfo_src = custom_target('modinfo-' + target + '.c',
4036                                  output: 'modinfo-' + target + '.c',
4037                                  input: modinfo_files,
4038                                  command: [modinfo_generate, '--devices', config_devices_mak, '@INPUT@'],
4039                                  capture: true)
4040
4041      modinfo_lib = static_library('modinfo-' + target + '.c', modinfo_src)
4042      modinfo_dep = declare_dependency(link_with: modinfo_lib)
4043
4044      arch = config_target['TARGET_NAME'] == 'sparc64' ? 'sparc64' : config_target['TARGET_BASE_ARCH']
4045      hw_arch[arch].add(modinfo_dep)
4046    endif
4047  endforeach
4048
4049  if emulator_modules.length() > 0
4050    alias_target('modules', emulator_modules)
4051  endif
4052endif
4053
4054nm = find_program('nm')
4055undefsym = find_program('scripts/undefsym.py')
4056block_syms = custom_target('block.syms', output: 'block.syms',
4057                             input: [libqemuutil, block_mods],
4058                             capture: true,
4059                             command: [undefsym, nm, '@INPUT@'])
4060qemu_syms = custom_target('qemu.syms', output: 'qemu.syms',
4061                             input: [libqemuutil, system_mods],
4062                             capture: true,
4063                             command: [undefsym, nm, '@INPUT@'])
4064
4065authz_ss = authz_ss.apply({})
4066libauthz = static_library('authz', authz_ss.sources() + genh,
4067                          dependencies: [authz_ss.dependencies()],
4068                          build_by_default: false)
4069
4070authz = declare_dependency(objects: libauthz.extract_all_objects(recursive: false),
4071                           dependencies: [authz_ss.dependencies(), qom])
4072
4073crypto_ss = crypto_ss.apply({})
4074libcrypto = static_library('crypto', crypto_ss.sources() + genh,
4075                           dependencies: [crypto_ss.dependencies()],
4076                           build_by_default: false)
4077
4078crypto = declare_dependency(objects: libcrypto.extract_all_objects(recursive: false),
4079                            dependencies: [crypto_ss.dependencies(), authz, qom])
4080
4081io_ss = io_ss.apply({})
4082libio = static_library('io', io_ss.sources() + genh,
4083                       dependencies: [io_ss.dependencies()],
4084                       link_with: libqemuutil,
4085                       build_by_default: false)
4086
4087io = declare_dependency(objects: libio.extract_all_objects(recursive: false),
4088                        dependencies: [io_ss.dependencies(), crypto, qom])
4089
4090libmigration = static_library('migration', sources: migration_files + genh,
4091                              build_by_default: false)
4092migration = declare_dependency(objects: libmigration.extract_all_objects(recursive: false),
4093                               dependencies: [qom, io])
4094system_ss.add(migration)
4095
4096block_ss = block_ss.apply({})
4097libblock = static_library('block', block_ss.sources() + genh,
4098                          dependencies: block_ss.dependencies(),
4099                          build_by_default: false)
4100
4101block = declare_dependency(objects: libblock.extract_all_objects(recursive: false),
4102                           dependencies: [block_ss.dependencies(), crypto, io])
4103
4104blockdev_ss = blockdev_ss.apply({})
4105libblockdev = static_library('blockdev', blockdev_ss.sources() + genh,
4106                             dependencies: blockdev_ss.dependencies(),
4107                             build_by_default: false)
4108
4109blockdev = declare_dependency(objects: libblockdev.extract_all_objects(recursive: false),
4110                              dependencies: [blockdev_ss.dependencies(), block, event_loop_base])
4111
4112qmp_ss = qmp_ss.apply({})
4113libqmp = static_library('qmp', qmp_ss.sources() + genh,
4114                        dependencies: qmp_ss.dependencies(),
4115                        build_by_default: false)
4116
4117qmp = declare_dependency(objects: libqmp.extract_all_objects(recursive: false),
4118                         dependencies: qmp_ss.dependencies())
4119
4120libchardev = static_library('chardev', chardev_ss.sources() + genh,
4121                            dependencies: chardev_ss.dependencies(),
4122                            build_by_default: false)
4123
4124chardev = declare_dependency(objects: libchardev.extract_all_objects(recursive: false),
4125                             dependencies: [chardev_ss.dependencies(), io])
4126
4127hwcore_ss = hwcore_ss.apply({})
4128libhwcore = static_library('hwcore', sources: hwcore_ss.sources() + genh,
4129                           build_by_default: false)
4130hwcore = declare_dependency(objects: libhwcore.extract_all_objects(recursive: false))
4131common_ss.add(hwcore)
4132
4133###########
4134# Targets #
4135###########
4136
4137system_ss.add(authz, blockdev, chardev, crypto, io, qmp)
4138common_ss.add(qom, qemuutil)
4139
4140libuser = static_library('user',
4141                         user_ss.all_sources() + genh,
4142                         c_args: ['-DCONFIG_USER_ONLY',
4143                                  '-DCOMPILING_SYSTEM_VS_USER'],
4144                         include_directories: common_user_inc,
4145                         dependencies: user_ss.all_dependencies(),
4146                         build_by_default: false)
4147
4148libsystem = static_library('system',
4149                           system_ss.all_sources() + genh,
4150                           c_args: ['-DCONFIG_SOFTMMU',
4151                                    '-DCOMPILING_SYSTEM_VS_USER'],
4152                           dependencies: system_ss.all_dependencies(),
4153                           build_by_default: false)
4154
4155# Note that this library is never used directly (only through extract_objects)
4156# and is not built by default; therefore, source files not used by the build
4157# configuration will be in build.ninja, but are never built by default.
4158common_all = static_library('common',
4159                            build_by_default: false,
4160                            sources: common_ss.all_sources() + genh,
4161                            implicit_include_directories: false,
4162                            dependencies: common_ss.all_dependencies())
4163
4164# construct common libraries per base architecture
4165target_common_arch_libs = {}
4166target_common_system_arch_libs = {}
4167foreach target_base_arch, config_base_arch : config_base_arch_mak
4168  target_inc = [include_directories('target' / target_base_arch)]
4169  inc = [common_user_inc + target_inc]
4170
4171  target_common = common_ss.apply(config_base_arch, strict: false)
4172  target_system = system_ss.apply(config_base_arch, strict: false)
4173  target_user = user_ss.apply(config_base_arch, strict: false)
4174  common_deps = []
4175  system_deps = []
4176  user_deps = []
4177  foreach dep: target_common.dependencies()
4178    common_deps += dep.partial_dependency(compile_args: true, includes: true)
4179  endforeach
4180  foreach dep: target_system.dependencies()
4181    system_deps += dep.partial_dependency(compile_args: true, includes: true)
4182  endforeach
4183  foreach dep: target_user.dependencies()
4184    user_deps += dep.partial_dependency(compile_args: true, includes: true)
4185  endforeach
4186
4187  # prevent common code to access cpu compile time definition,
4188  # but still allow access to cpu.h
4189  target_c_args = ['-DCPU_DEFS_H']
4190  target_system_c_args = target_c_args + ['-DCOMPILING_SYSTEM_VS_USER', '-DCONFIG_SOFTMMU']
4191
4192  if target_base_arch in target_common_arch
4193    src = target_common_arch[target_base_arch]
4194    lib = static_library(
4195      'common_' + target_base_arch,
4196      build_by_default: false,
4197      sources: src.all_sources() + genh,
4198      include_directories: inc,
4199      c_args: target_c_args,
4200      dependencies: src.all_dependencies() + common_deps +
4201                    system_deps + user_deps)
4202    target_common_arch_libs += {target_base_arch: lib}
4203  endif
4204
4205  # merge hw_common_arch in target_common_system_arch
4206  if target_base_arch in hw_common_arch
4207    hw_src = hw_common_arch[target_base_arch]
4208    if target_base_arch in target_common_system_arch
4209      target_common_system_arch[target_base_arch].add_all(hw_src)
4210    else
4211      target_common_system_arch += {target_base_arch: hw_src}
4212    endif
4213  endif
4214
4215  if target_base_arch in target_common_system_arch
4216    src = target_common_system_arch[target_base_arch]
4217    lib = static_library(
4218      'system_' + target_base_arch,
4219      build_by_default: false,
4220      sources: src.all_sources() + genh,
4221      include_directories: inc,
4222      c_args: target_system_c_args,
4223      dependencies: src.all_dependencies() + common_deps + system_deps)
4224    target_common_system_arch_libs += {target_base_arch: lib}
4225  endif
4226endforeach
4227
4228if have_rust
4229  bindings_incdir = include_directories('.', 'include')
4230  # We would like to use --generate-cstr, but it is only available
4231  # starting with bindgen 0.66.0.  The oldest supported versions
4232  # is 0.60.x (Debian 12 has 0.60.1) which introduces --allowlist-file.
4233  bindgen_args_common = [
4234    '--disable-header-comment',
4235    '--raw-line', '// @generated',
4236    '--ctypes-prefix', 'std::os::raw',
4237    '--generate-block',
4238    '--impl-debug',
4239    '--no-doc-comments',
4240    '--with-derive-default',
4241    '--no-layout-tests',
4242    '--no-prepend-enum-name',
4243    '--allowlist-file', meson.project_source_root() + '/include/.*',
4244    '--allowlist-file', meson.project_source_root() + '/.*',
4245    '--allowlist-file', meson.project_build_root() + '/.*'
4246    ]
4247  if not rustfmt.found()
4248    if bindgen.version().version_compare('<0.65.0')
4249      bindgen_args_common += ['--no-rustfmt-bindings']
4250    else
4251      bindgen_args_common += ['--formatter', 'none']
4252    endif
4253  endif
4254  if bindgen.version().version_compare('>=0.66.0')
4255    bindgen_args_common += ['--rust-target', '1.59']
4256  endif
4257  if bindgen.version().version_compare('<0.61.0')
4258    # default in 0.61+
4259    bindgen_args_common += ['--size_t-is-usize']
4260  else
4261    bindgen_args_common += ['--merge-extern-blocks']
4262  endif
4263  subdir('rust')
4264endif
4265
4266
4267feature_to_c = find_program('scripts/feature_to_c.py')
4268rust_root_crate = find_program('scripts/rust/rust_root_crate.sh')
4269
4270if host_os == 'darwin'
4271  entitlement = find_program('scripts/entitlement.sh')
4272endif
4273
4274traceable = []
4275emulators = {}
4276foreach target : target_dirs
4277  config_target = config_target_mak[target]
4278  target_name = config_target['TARGET_NAME']
4279  target_base_arch = config_target['TARGET_BASE_ARCH']
4280  arch_srcs = [config_target_h[target]]
4281  arch_deps = []
4282  c_args = ['-DCOMPILING_PER_TARGET',
4283            '-DCONFIG_TARGET="@0@-config-target.h"'.format(target),
4284  ]
4285  link_args = emulator_link_args
4286
4287  target_inc = [include_directories('target' / config_target['TARGET_BASE_ARCH'])]
4288  if host_os == 'linux'
4289    target_inc += include_directories('linux-headers', is_system: true)
4290  endif
4291  if target.endswith('-softmmu')
4292    target_type='system'
4293    t = target_system_arch[target_base_arch].apply(config_target, strict: false)
4294    arch_srcs += t.sources()
4295    arch_deps += t.dependencies()
4296
4297    hw_dir = target_name == 'sparc64' ? 'sparc64' : target_base_arch
4298    if hw_arch.has_key(hw_dir)
4299      hw = hw_arch[hw_dir].apply(config_target, strict: false)
4300      arch_srcs += hw.sources()
4301      arch_deps += hw.dependencies()
4302    endif
4303
4304    c_args += ['-DCONFIG_DEVICES="@0@-config-devices.h"'.format(target)]
4305    arch_srcs += config_devices_h[target]
4306    link_args += ['@block.syms', '@qemu.syms']
4307  else
4308    abi = config_target['TARGET_ABI_DIR']
4309    target_type='user'
4310    target_inc += common_user_inc
4311    if target_base_arch in target_user_arch
4312      t = target_user_arch[target_base_arch].apply(config_target, strict: false)
4313      arch_srcs += t.sources()
4314      arch_deps += t.dependencies()
4315    endif
4316    if 'CONFIG_LINUX_USER' in config_target
4317      base_dir = 'linux-user'
4318    endif
4319    if 'CONFIG_BSD_USER' in config_target
4320      base_dir = 'bsd-user'
4321      target_inc += include_directories('bsd-user/' / host_os)
4322      target_inc += include_directories('bsd-user/host/' / host_arch)
4323      dir = base_dir / abi
4324      arch_srcs += files(dir / 'signal.c', dir / 'target_arch_cpu.c')
4325    endif
4326    target_inc += include_directories(
4327      base_dir,
4328      base_dir / abi,
4329    )
4330    if 'CONFIG_LINUX_USER' in config_target
4331      dir = base_dir / abi
4332      arch_srcs += files(dir / 'signal.c', dir / 'cpu_loop.c')
4333      if config_target.has_key('TARGET_SYSTBL_ABI')
4334        arch_srcs += \
4335          syscall_nr_generators[abi].process(base_dir / abi / config_target['TARGET_SYSTBL'],
4336                                             extra_args : config_target['TARGET_SYSTBL_ABI'])
4337      endif
4338    endif
4339  endif
4340
4341  if 'TARGET_XML_FILES' in config_target
4342    gdbstub_xml = custom_target(target + '-gdbstub-xml.c',
4343                                output: target + '-gdbstub-xml.c',
4344                                input: files(config_target['TARGET_XML_FILES'].split()),
4345                                command: [feature_to_c, '@INPUT@'],
4346                                capture: true)
4347    arch_srcs += gdbstub_xml
4348  endif
4349
4350  t = target_arch[target_base_arch].apply(config_target, strict: false)
4351  arch_srcs += t.sources()
4352  arch_deps += t.dependencies()
4353
4354  target_common = common_ss.apply(config_target, strict: false)
4355  objects = [common_all.extract_objects(target_common.sources())]
4356  arch_deps += target_common.dependencies()
4357  if target_base_arch in target_common_arch_libs
4358    src = target_common_arch[target_base_arch].apply(config_target, strict: false)
4359    lib = target_common_arch_libs[target_base_arch]
4360    objects += lib.extract_objects(src.sources())
4361    arch_deps += src.dependencies()
4362  endif
4363  if target_type == 'system'
4364    src = system_ss.apply(config_target, strict: false)
4365    objects += libsystem.extract_objects(src.sources())
4366    arch_deps += src.dependencies()
4367  endif
4368  if target_type == 'user'
4369    src = user_ss.apply(config_target, strict: false)
4370    objects += libuser.extract_objects(src.sources())
4371    arch_deps += src.dependencies()
4372  endif
4373  if target_type == 'system' and target_base_arch in target_common_system_arch_libs
4374    src = target_common_system_arch[target_base_arch].apply(config_target, strict: false)
4375    lib = target_common_system_arch_libs[target_base_arch]
4376    objects += lib.extract_objects(src.sources())
4377    arch_deps += src.dependencies()
4378  endif
4379
4380  target_specific = specific_ss.apply(config_target, strict: false)
4381  arch_srcs += target_specific.sources()
4382  arch_deps += target_specific.dependencies()
4383
4384  if have_rust and target_type == 'system'
4385    target_rust = rust_devices_ss.apply(config_target, strict: false)
4386    crates = []
4387    foreach dep : target_rust.dependencies()
4388      crates += dep.get_variable('crate')
4389    endforeach
4390    if crates.length() > 0
4391      rlib_rs = custom_target('rust_' + target.underscorify() + '.rs',
4392                              output: 'rust_' + target.underscorify() + '.rs',
4393                              command: [rust_root_crate, crates],
4394                              capture: true,
4395                              build_by_default: true,
4396                              build_always_stale: true)
4397      rlib = static_library('rust_' + target.underscorify(),
4398                            structured_sources([], {'.': rlib_rs}),
4399                            dependencies: target_rust.dependencies(),
4400                            override_options: ['rust_std=2021', 'build.rust_std=2021'],
4401                            rust_abi: 'c')
4402      arch_deps += declare_dependency(link_whole: [rlib])
4403    endif
4404  endif
4405
4406  # allow using headers from the dependencies but do not include the sources,
4407  # because this emulator only needs those in "objects".  For external
4408  # dependencies, the full dependency is included below in the executable.
4409  lib_deps = []
4410  foreach dep : arch_deps
4411    lib_deps += dep.partial_dependency(compile_args: true, includes: true)
4412  endforeach
4413
4414  lib = static_library('qemu-' + target,
4415                 sources: arch_srcs + genh,
4416                 dependencies: lib_deps,
4417                 objects: objects,
4418                 include_directories: target_inc,
4419                 c_args: c_args,
4420                 build_by_default: false)
4421
4422  if target.endswith('-softmmu')
4423    execs = [{
4424      'name': 'qemu-system-' + target_name,
4425      'win_subsystem': 'console',
4426      'sources': files('system/main.c'),
4427      'dependencies': [sdl]
4428    }]
4429    if host_os == 'windows' and (sdl.found() or gtk.found())
4430      execs += [{
4431        'name': 'qemu-system-' + target_name + 'w',
4432        'win_subsystem': 'windows',
4433        'sources': files('system/main.c'),
4434        'dependencies': [sdl]
4435      }]
4436    endif
4437    if get_option('fuzzing')
4438      specific_fuzz = specific_fuzz_ss.apply(config_target, strict: false)
4439      execs += [{
4440        'name': 'qemu-fuzz-' + target_name,
4441        'win_subsystem': 'console',
4442        'sources': specific_fuzz.sources(),
4443        'dependencies': specific_fuzz.dependencies(),
4444      }]
4445    endif
4446  else
4447    execs = [{
4448      'name': 'qemu-' + target_name,
4449      'win_subsystem': 'console',
4450      'sources': [],
4451      'dependencies': []
4452    }]
4453  endif
4454  foreach exe: execs
4455    exe_name = exe['name']
4456    if host_os == 'darwin'
4457      exe_name += '-unsigned'
4458    endif
4459
4460    emulator = executable(exe_name, exe['sources'],
4461               install: true,
4462               c_args: c_args,
4463               dependencies: arch_deps + exe['dependencies'],
4464               objects: lib.extract_all_objects(recursive: true),
4465               link_depends: [block_syms, qemu_syms],
4466               link_args: link_args,
4467               win_subsystem: exe['win_subsystem'])
4468
4469    if host_os == 'darwin'
4470      icon = 'pc-bios/qemu.rsrc'
4471      build_input = [emulator, files(icon)]
4472      install_input = [
4473        get_option('bindir') / exe_name,
4474        meson.current_source_dir() / icon
4475      ]
4476      if 'CONFIG_HVF' in config_target
4477        entitlements = 'accel/hvf/entitlements.plist'
4478        build_input += files(entitlements)
4479        install_input += meson.current_source_dir() / entitlements
4480      endif
4481
4482      emulators += {exe['name'] : custom_target(exe['name'],
4483                   input: build_input,
4484                   output: exe['name'],
4485                   command: [entitlement, '@OUTPUT@', '@INPUT@'])
4486      }
4487
4488      meson.add_install_script(entitlement, '--install',
4489                               get_option('bindir') / exe['name'],
4490                               install_input)
4491    else
4492      emulators += {exe['name']: emulator}
4493    endif
4494
4495    traceable += [{
4496      'exe': exe['name'],
4497      'probe-prefix': 'qemu.' + target_type + '.' + target_name,
4498    }]
4499
4500  endforeach
4501endforeach
4502
4503# Other build targets
4504
4505if get_option('plugins')
4506  install_headers('include/qemu/qemu-plugin.h')
4507  if host_os == 'windows'
4508    # On windows, we want to deliver the qemu_plugin_api.lib file in the qemu installer,
4509    # so that plugin authors can compile against it.
4510    install_data(win32_qemu_plugin_api_lib, install_dir: 'lib')
4511  endif
4512endif
4513
4514subdir('qga')
4515
4516# Don't build qemu-keymap if xkbcommon is not explicitly enabled
4517# when we don't build tools or system
4518if xkbcommon.found()
4519  # used for the update-keymaps target, so include rules even if !have_tools
4520  qemu_keymap = executable('qemu-keymap', files('qemu-keymap.c', 'ui/input-keymap.c') + genh,
4521                           dependencies: [qemuutil, xkbcommon], install: have_tools)
4522endif
4523
4524if have_tools
4525  qemu_img = executable('qemu-img', [files('qemu-img.c'), hxdep],
4526             link_args: '@block.syms', link_depends: block_syms,
4527             dependencies: [authz, block, crypto, io, qom, qemuutil], install: true)
4528  qemu_io = executable('qemu-io', files('qemu-io.c'),
4529             link_args: '@block.syms', link_depends: block_syms,
4530             dependencies: [block, qemuutil], install: true)
4531  qemu_nbd = executable('qemu-nbd', files('qemu-nbd.c'),
4532               link_args: '@block.syms', link_depends: block_syms,
4533               dependencies: [blockdev, qemuutil, selinux],
4534               install: true)
4535
4536  subdir('storage-daemon')
4537
4538  foreach exe: [ 'qemu-img', 'qemu-io', 'qemu-nbd', 'qemu-storage-daemon']
4539    traceable += [{
4540      'exe': exe,
4541      'probe-prefix': 'qemu.' + exe.substring(5).replace('-', '_')
4542    }]
4543  endforeach
4544
4545  subdir('contrib/elf2dmp')
4546
4547  executable('qemu-edid', files('qemu-edid.c', 'hw/display/edid-generate.c'),
4548             dependencies: [qemuutil, rt],
4549             install: true)
4550
4551  if have_vhost_user
4552    subdir('contrib/vhost-user-blk')
4553    subdir('contrib/vhost-user-gpu')
4554    subdir('contrib/vhost-user-input')
4555    subdir('contrib/vhost-user-scsi')
4556  endif
4557
4558  if host_os == 'linux'
4559    executable('qemu-bridge-helper', files('qemu-bridge-helper.c'),
4560               dependencies: [qemuutil, libcap_ng],
4561               install: true,
4562               install_dir: get_option('libexecdir'))
4563
4564    executable('qemu-pr-helper', files('scsi/qemu-pr-helper.c', 'scsi/utils.c'),
4565               dependencies: [authz, crypto, io, qom, qemuutil,
4566                              libcap_ng, mpathpersist],
4567               install: true)
4568
4569    if cpu in ['x86', 'x86_64']
4570      executable('qemu-vmsr-helper', files('tools/i386/qemu-vmsr-helper.c'),
4571               dependencies: [authz, crypto, io, qom, qemuutil,
4572                              libcap_ng, mpathpersist],
4573               install: true)
4574    endif
4575  endif
4576
4577  if have_ivshmem
4578    subdir('contrib/ivshmem-client')
4579    subdir('contrib/ivshmem-server')
4580  endif
4581endif
4582
4583if stap.found()
4584  foreach t: traceable
4585    foreach stp: [
4586      {'ext': '.stp-build', 'fmt': 'stap', 'bin': meson.current_build_dir() / t['exe'], 'install': false},
4587      {'ext': '.stp', 'fmt': 'stap', 'bin': get_option('prefix') / get_option('bindir') / t['exe'], 'install': true},
4588      {'ext': '-simpletrace.stp', 'fmt': 'simpletrace-stap', 'bin': '', 'install': true},
4589      {'ext': '-log.stp', 'fmt': 'log-stap', 'bin': '', 'install': true},
4590    ]
4591      cmd = [
4592        tracetool, '--group=all', '--format=' + stp['fmt'],
4593        '--binary=' + stp['bin'],
4594        '--probe-prefix=' + t['probe-prefix'],
4595        '@INPUT@', '@OUTPUT@'
4596      ]
4597
4598      custom_target(t['exe'] + stp['ext'],
4599                    input: trace_events_all,
4600                    output: t['exe'] + stp['ext'],
4601                    install: stp['install'],
4602                    install_dir: get_option('datadir') / 'systemtap/tapset',
4603                    command: cmd,
4604                    depend_files: tracetool_depends)
4605    endforeach
4606  endforeach
4607endif
4608
4609subdir('scripts')
4610subdir('tools')
4611subdir('pc-bios')
4612subdir('docs')
4613# Tests are disabled on emscripten because they rely on host features that aren't
4614# supported by emscripten (e.g. fork and unix socket).
4615if host_os != 'emscripten'
4616  subdir('tests')
4617endif
4618if gtk.found()
4619  subdir('po')
4620endif
4621
4622if host_machine.system() == 'windows'
4623  nsis_cmd = [
4624    find_program('scripts/nsis.py'),
4625    '@OUTPUT@',
4626    get_option('prefix'),
4627    meson.current_source_dir(),
4628    glib_pc.get_variable('bindir'),
4629    host_machine.cpu(),
4630    '--',
4631    '-DDISPLAYVERSION=' + meson.project_version(),
4632  ]
4633  if build_docs
4634    nsis_cmd += '-DCONFIG_DOCUMENTATION=y'
4635  endif
4636  if gtk.found()
4637    nsis_cmd += '-DCONFIG_GTK=y'
4638  endif
4639
4640  nsis = custom_target('nsis',
4641                       output: 'qemu-setup-' + meson.project_version() + '.exe',
4642                       input: files('qemu.nsi'),
4643                       build_always_stale: true,
4644                       command: nsis_cmd + ['@INPUT@'])
4645  alias_target('installer', nsis)
4646endif
4647
4648#########################
4649# Configuration summary #
4650#########################
4651
4652# Build environment
4653summary_info = {}
4654summary_info += {'Build directory':   meson.current_build_dir()}
4655summary_info += {'Source path':       meson.current_source_dir()}
4656summary_info += {'Download dependencies': get_option('wrap_mode') != 'nodownload'}
4657summary(summary_info, bool_yn: true, section: 'Build environment')
4658
4659# Directories
4660summary_info += {'Install prefix':    get_option('prefix')}
4661summary_info += {'BIOS directory':    qemu_datadir}
4662pathsep = host_os == 'windows' ? ';' : ':'
4663summary_info += {'firmware path':     pathsep.join(get_option('qemu_firmwarepath'))}
4664summary_info += {'binary directory':  get_option('prefix') / get_option('bindir')}
4665summary_info += {'library directory': get_option('prefix') / get_option('libdir')}
4666summary_info += {'module directory':  qemu_moddir}
4667summary_info += {'libexec directory': get_option('prefix') / get_option('libexecdir')}
4668summary_info += {'include directory': get_option('prefix') / get_option('includedir')}
4669summary_info += {'config directory':  get_option('prefix') / get_option('sysconfdir')}
4670if host_os != 'windows'
4671  summary_info += {'local state directory': get_option('prefix') / get_option('localstatedir')}
4672  summary_info += {'Manual directory':      get_option('prefix') / get_option('mandir')}
4673else
4674  summary_info += {'local state directory': 'queried at runtime'}
4675endif
4676summary_info += {'Doc directory':     get_option('prefix') / get_option('docdir')}
4677summary(summary_info, bool_yn: true, section: 'Directories')
4678
4679# Host binaries
4680summary_info = {}
4681summary_info += {'python':            '@0@ (version: @1@)'.format(python.full_path(), python.language_version())}
4682summary_info += {'sphinx-build':      sphinx_build}
4683
4684# FIXME: the [binaries] section of machine files, which can be probed
4685# with find_program(), would be great for passing gdb and genisoimage
4686# paths from configure to Meson.  However, there seems to be no way to
4687# hide a program (for example if gdb is too old).
4688if config_host.has_key('GDB')
4689  summary_info += {'gdb':             config_host['GDB']}
4690endif
4691summary_info += {'iasl':              iasl}
4692summary_info += {'genisoimage':       config_host['GENISOIMAGE']}
4693if host_os == 'windows' and have_ga
4694  summary_info += {'wixl':            wixl}
4695endif
4696if slirp.found() and have_system
4697  summary_info += {'smbd':            have_slirp_smbd ? smbd_path : false}
4698endif
4699summary(summary_info, bool_yn: true, section: 'Host binaries')
4700
4701# Configurable features
4702summary_info = {}
4703summary_info += {'Documentation':     build_docs}
4704summary_info += {'system-mode emulation': have_system}
4705summary_info += {'user-mode emulation': have_user}
4706summary_info += {'block layer':       have_block}
4707summary_info += {'Install blobs':     get_option('install_blobs')}
4708summary_info += {'module support':    enable_modules}
4709if enable_modules
4710  summary_info += {'alternative module path': get_option('module_upgrades')}
4711endif
4712summary_info += {'fuzzing support':   get_option('fuzzing')}
4713if have_system
4714  summary_info += {'Audio drivers':     ' '.join(audio_drivers_selected)}
4715endif
4716summary_info += {'Trace backends':    ','.join(get_option('trace_backends'))}
4717if 'simple' in get_option('trace_backends')
4718  summary_info += {'Trace output file': get_option('trace_file') + '-<pid>'}
4719endif
4720summary_info += {'QOM debugging':     get_option('qom_cast_debug')}
4721summary_info += {'Relocatable install': get_option('relocatable')}
4722summary_info += {'vhost-kernel support': have_vhost_kernel}
4723summary_info += {'vhost-net support': have_vhost_net}
4724summary_info += {'vhost-user support': have_vhost_user}
4725summary_info += {'vhost-user-crypto support': have_vhost_user_crypto}
4726summary_info += {'vhost-user-blk server support': have_vhost_user_blk_server}
4727summary_info += {'vhost-vdpa support': have_vhost_vdpa}
4728summary_info += {'build guest agent': have_ga}
4729summary(summary_info, bool_yn: true, section: 'Configurable features')
4730
4731# Compilation information
4732summary_info = {}
4733summary_info += {'host CPU':          cpu}
4734summary_info += {'host endianness':   build_machine.endian()}
4735summary_info += {'C compiler':        ' '.join(meson.get_compiler('c').cmd_array())}
4736summary_info += {'Host C compiler':   ' '.join(meson.get_compiler('c', native: true).cmd_array())}
4737if 'cpp' in all_languages
4738  summary_info += {'C++ compiler':    ' '.join(meson.get_compiler('cpp').cmd_array())}
4739else
4740  summary_info += {'C++ compiler':      false}
4741endif
4742if 'objc' in all_languages
4743  summary_info += {'Objective-C compiler': ' '.join(meson.get_compiler('objc').cmd_array())}
4744else
4745  summary_info += {'Objective-C compiler': false}
4746endif
4747summary_info += {'Rust support':      have_rust}
4748if have_rust
4749  summary_info += {'Rust target':     config_host['RUST_TARGET_TRIPLE']}
4750  summary_info += {'rustc':           ' '.join(rustc.cmd_array())}
4751  summary_info += {'rustc version':   rustc.version()}
4752  summary_info += {'rustdoc':         rustdoc}
4753  summary_info += {'bindgen':         bindgen.full_path()}
4754  summary_info += {'bindgen version': bindgen.version()}
4755endif
4756option_cflags = (get_option('debug') ? ['-g'] : [])
4757if get_option('optimization') != 'plain'
4758  option_cflags += ['-O' + get_option('optimization')]
4759endif
4760summary_info += {'CFLAGS':            ' '.join(get_option('c_args') + option_cflags)}
4761if 'cpp' in all_languages
4762  summary_info += {'CXXFLAGS':        ' '.join(get_option('cpp_args') + option_cflags)}
4763endif
4764if 'objc' in all_languages
4765  summary_info += {'OBJCFLAGS':       ' '.join(get_option('objc_args') + option_cflags)}
4766endif
4767link_args = get_option('c_link_args')
4768if link_args.length() > 0
4769  summary_info += {'LDFLAGS':         ' '.join(link_args)}
4770endif
4771summary_info += {'QEMU_CFLAGS':       ' '.join(qemu_common_flags + qemu_cflags)}
4772if 'cpp' in all_languages
4773  summary_info += {'QEMU_CXXFLAGS':     ' '.join(qemu_common_flags + qemu_cxxflags)}
4774endif
4775if 'objc' in all_languages
4776  summary_info += {'QEMU_OBJCFLAGS':    ' '.join(qemu_common_flags)}
4777endif
4778summary_info += {'QEMU_LDFLAGS':      ' '.join(qemu_ldflags)}
4779summary_info += {'link-time optimization (LTO)': get_option('b_lto')}
4780summary_info += {'PIE':               get_option('b_pie')}
4781summary_info += {'static build':      get_option('prefer_static')}
4782summary_info += {'malloc trim support': has_malloc_trim}
4783summary_info += {'membarrier':        have_membarrier}
4784summary_info += {'debug graph lock':  get_option('debug_graph_lock')}
4785summary_info += {'debug stack usage': get_option('debug_stack_usage')}
4786summary_info += {'mutex debugging':   get_option('debug_mutex')}
4787summary_info += {'memory allocator':  get_option('malloc')}
4788summary_info += {'avx2 optimization': config_host_data.get('CONFIG_AVX2_OPT')}
4789summary_info += {'avx512bw optimization': config_host_data.get('CONFIG_AVX512BW_OPT')}
4790summary_info += {'gcov':              get_option('b_coverage')}
4791summary_info += {'thread sanitizer':  get_option('tsan')}
4792summary_info += {'CFI support':       get_option('cfi')}
4793if get_option('cfi')
4794  summary_info += {'CFI debug support': get_option('cfi_debug')}
4795endif
4796summary_info += {'strip binaries':    get_option('strip')}
4797summary_info += {'sparse':            sparse}
4798summary_info += {'mingw32 support':   host_os == 'windows'}
4799summary(summary_info, bool_yn: true, section: 'Compilation')
4800
4801# snarf the cross-compilation information for tests
4802summary_info = {}
4803have_cross = false
4804foreach target: target_dirs
4805  tcg_mak = meson.current_build_dir() / 'tests/tcg' / target / 'config-target.mak'
4806  if fs.exists(tcg_mak)
4807    config_cross_tcg = keyval.load(tcg_mak)
4808    if 'CC' in config_cross_tcg
4809      summary_info += {config_cross_tcg['TARGET_NAME']: config_cross_tcg['CC']}
4810      have_cross = true
4811    endif
4812  endif
4813endforeach
4814if have_cross
4815  summary(summary_info, bool_yn: true, section: 'Cross compilers')
4816endif
4817
4818# Targets and accelerators
4819summary_info = {}
4820if have_system
4821  summary_info += {'KVM support':       config_all_accel.has_key('CONFIG_KVM')}
4822  summary_info += {'HVF support':       config_all_accel.has_key('CONFIG_HVF')}
4823  summary_info += {'WHPX support':      config_all_accel.has_key('CONFIG_WHPX')}
4824  summary_info += {'NVMM support':      config_all_accel.has_key('CONFIG_NVMM')}
4825  summary_info += {'Xen support':       xen.found()}
4826  if xen.found()
4827    summary_info += {'xen ctrl version':  xen.version()}
4828  endif
4829  summary_info += {'Xen emulation':     config_all_devices.has_key('CONFIG_XEN_EMU')}
4830endif
4831summary_info += {'TCG support':       config_all_accel.has_key('CONFIG_TCG')}
4832if config_all_accel.has_key('CONFIG_TCG')
4833  if get_option('tcg_interpreter')
4834    summary_info += {'TCG backend':   'TCI (TCG with bytecode interpreter, slow)'}
4835  else
4836    summary_info += {'TCG backend':   'native (@0@)'.format(cpu)}
4837  endif
4838  summary_info += {'TCG plugins':       get_option('plugins')}
4839  summary_info += {'TCG debug enabled': get_option('debug_tcg')}
4840  if have_linux_user or have_bsd_user
4841    summary_info += {'syscall buffer debugging support': get_option('debug_remap')}
4842  endif
4843endif
4844summary_info += {'target list':       ' '.join(target_dirs)}
4845if have_system
4846  summary_info += {'default devices':   get_option('default_devices')}
4847  summary_info += {'out of process emulation': multiprocess_allowed}
4848  summary_info += {'vfio-user server': vfio_user_server_allowed}
4849endif
4850summary(summary_info, bool_yn: true, section: 'Targets and accelerators')
4851
4852# Block layer
4853summary_info = {}
4854summary_info += {'coroutine backend': coroutine_backend}
4855summary_info += {'coroutine pool':    have_coroutine_pool}
4856if have_block
4857  summary_info += {'Block whitelist (rw)': get_option('block_drv_rw_whitelist')}
4858  summary_info += {'Block whitelist (ro)': get_option('block_drv_ro_whitelist')}
4859  summary_info += {'Use block whitelist in tools': get_option('block_drv_whitelist_in_tools')}
4860  summary_info += {'VirtFS (9P) support':    have_virtfs}
4861  summary_info += {'replication support': config_host_data.get('CONFIG_REPLICATION')}
4862  summary_info += {'bochs support':     get_option('bochs').allowed()}
4863  summary_info += {'cloop support':     get_option('cloop').allowed()}
4864  summary_info += {'dmg support':       get_option('dmg').allowed()}
4865  summary_info += {'qcow v1 support':   get_option('qcow1').allowed()}
4866  summary_info += {'vdi support':       get_option('vdi').allowed()}
4867  summary_info += {'vhdx support':      get_option('vhdx').allowed()}
4868  summary_info += {'vmdk support':      get_option('vmdk').allowed()}
4869  summary_info += {'vpc support':       get_option('vpc').allowed()}
4870  summary_info += {'vvfat support':     get_option('vvfat').allowed()}
4871  summary_info += {'qed support':       get_option('qed').allowed()}
4872  summary_info += {'parallels support': get_option('parallels').allowed()}
4873  summary_info += {'FUSE exports':      fuse}
4874  summary_info += {'VDUSE block exports': have_vduse_blk_export}
4875endif
4876summary(summary_info, bool_yn: true, section: 'Block layer support')
4877
4878# Crypto
4879summary_info = {}
4880summary_info += {'TLS priority':      get_option('tls_priority')}
4881summary_info += {'GNUTLS support':    gnutls}
4882if gnutls.found()
4883  summary_info += {'  GNUTLS crypto':   gnutls_crypto.found()}
4884  summary_info += {'  GNUTLS bug 1717 workaround': gnutls_bug1717_workaround }
4885endif
4886summary_info += {'libgcrypt':         gcrypt}
4887summary_info += {'nettle':            nettle}
4888if nettle.found()
4889   summary_info += {'  XTS':             xts != 'private'}
4890endif
4891summary_info += {'SM4 ALG support':   crypto_sm4}
4892summary_info += {'SM3 ALG support':   crypto_sm3}
4893summary_info += {'AF_ALG support':    have_afalg}
4894summary_info += {'rng-none':          get_option('rng_none')}
4895summary_info += {'Linux keyring':     have_keyring}
4896summary_info += {'Linux keyutils':    keyutils}
4897summary(summary_info, bool_yn: true, section: 'Crypto')
4898
4899# UI
4900summary_info = {}
4901if host_os == 'darwin'
4902  summary_info += {'Cocoa support':           cocoa}
4903endif
4904summary_info += {'D-Bus display':     dbus_display}
4905summary_info += {'SDL support':       sdl}
4906summary_info += {'SDL image support': sdl_image}
4907summary_info += {'GTK support':       gtk}
4908summary_info += {'pixman':            pixman}
4909summary_info += {'VTE support':       vte}
4910summary_info += {'PNG support':       png}
4911summary_info += {'VNC support':       vnc}
4912if vnc.found()
4913  summary_info += {'VNC SASL support':  sasl}
4914  summary_info += {'VNC JPEG support':  jpeg}
4915endif
4916summary_info += {'spice protocol support': spice_protocol}
4917if spice_protocol.found()
4918  summary_info += {'  spice server support': spice}
4919endif
4920summary_info += {'curses support':    curses}
4921summary_info += {'brlapi support':    brlapi}
4922summary(summary_info, bool_yn: true, section: 'User interface')
4923
4924# Graphics backends
4925summary_info = {}
4926summary_info += {'VirGL support':     virgl}
4927summary_info += {'Rutabaga support':  rutabaga}
4928summary(summary_info, bool_yn: true, section: 'Graphics backends')
4929
4930# Audio backends
4931summary_info = {}
4932if host_os not in ['darwin', 'haiku', 'windows']
4933  summary_info += {'OSS support':     oss}
4934  summary_info += {'sndio support':   sndio}
4935elif host_os == 'darwin'
4936  summary_info += {'CoreAudio support': coreaudio}
4937elif host_os == 'windows'
4938  summary_info += {'DirectSound support': dsound}
4939endif
4940if host_os == 'linux'
4941  summary_info += {'ALSA support':    alsa}
4942  summary_info += {'PulseAudio support': pulse}
4943endif
4944summary_info += {'PipeWire support':  pipewire}
4945summary_info += {'JACK support':      jack}
4946summary(summary_info, bool_yn: true, section: 'Audio backends')
4947
4948# Network backends
4949summary_info = {}
4950if host_os == 'darwin'
4951  summary_info += {'vmnet.framework support': vmnet}
4952endif
4953summary_info += {'AF_XDP support':    libxdp}
4954summary_info += {'passt support':     enable_passt}
4955summary_info += {'slirp support':     slirp}
4956summary_info += {'vde support':       vde}
4957summary_info += {'netmap support':    have_netmap}
4958summary_info += {'l2tpv3 support':    have_l2tpv3}
4959summary(summary_info, bool_yn: true, section: 'Network backends')
4960
4961# Libraries
4962summary_info = {}
4963summary_info += {'libtasn1':          tasn1}
4964summary_info += {'PAM':               pam}
4965summary_info += {'iconv support':     iconv}
4966summary_info += {'blkio support':     blkio}
4967summary_info += {'curl support':      curl}
4968summary_info += {'Multipath support': mpathpersist}
4969summary_info += {'Linux AIO support': libaio}
4970summary_info += {'Linux io_uring support': linux_io_uring}
4971summary_info += {'ATTR/XATTR support': libattr}
4972summary_info += {'RDMA support':      rdma}
4973summary_info += {'fdt support':       fdt_opt == 'internal' ? 'internal' : fdt}
4974summary_info += {'libcap-ng support': libcap_ng}
4975summary_info += {'bpf support':       libbpf}
4976summary_info += {'rbd support':       rbd}
4977summary_info += {'smartcard support': cacard}
4978summary_info += {'U2F support':       u2f}
4979summary_info += {'libusb':            libusb}
4980summary_info += {'usb net redir':     usbredir}
4981summary_info += {'OpenGL support (epoxy)': opengl}
4982summary_info += {'GBM':               gbm}
4983summary_info += {'libiscsi support':  libiscsi}
4984summary_info += {'libnfs support':    libnfs}
4985if host_os == 'windows'
4986  if have_ga
4987    summary_info += {'QGA VSS support':   have_qga_vss}
4988  endif
4989endif
4990summary_info += {'seccomp support':   seccomp}
4991summary_info += {'GlusterFS support': glusterfs}
4992summary_info += {'hv-balloon support': hv_balloon}
4993summary_info += {'TPM support':       have_tpm}
4994summary_info += {'IGVM support':      igvm}
4995summary_info += {'libssh support':    libssh}
4996summary_info += {'lzo support':       lzo}
4997summary_info += {'snappy support':    snappy}
4998summary_info += {'bzip2 support':     libbzip2}
4999summary_info += {'lzfse support':     liblzfse}
5000summary_info += {'zstd support':      zstd}
5001summary_info += {'Query Processing Library support': qpl}
5002summary_info += {'UADK Library support': uadk}
5003summary_info += {'qatzip support':    qatzip}
5004summary_info += {'NUMA host support': numa}
5005summary_info += {'capstone':          capstone}
5006summary_info += {'libpmem support':   libpmem}
5007summary_info += {'libdaxctl support': libdaxctl}
5008summary_info += {'libcbor support':   libcbor}
5009summary_info += {'libudev':           libudev}
5010# Dummy dependency, keep .found()
5011summary_info += {'FUSE lseek':        fuse_lseek.found()}
5012summary_info += {'selinux':           selinux}
5013summary_info += {'libdw':             libdw}
5014if host_os == 'freebsd'
5015  summary_info += {'libinotify-kqueue': inotify}
5016endif
5017if host_os == 'darwin'
5018  summary_info += {'ParavirtualizedGraphics support': pvg}
5019endif
5020summary_info += {'valgrind':          valgrind}
5021summary(summary_info, bool_yn: true, section: 'Dependencies')
5022
5023if host_arch == 'unknown'
5024  message()
5025  warning('UNSUPPORTED HOST CPU')
5026  message()
5027  message('Support for CPU host architecture ' + cpu + ' is not currently')
5028  message('maintained. The QEMU project does not guarantee that QEMU will')
5029  message('compile or work on this host CPU. You can help by volunteering')
5030  message('to maintain it and providing a build host for our continuous')
5031  message('integration setup.')
5032  if have_tcg
5033    message()
5034    message('configure has succeeded and you can continue to build, but')
5035    message('QEMU will use a slow interpreter to emulate the target CPU.')
5036  endif
5037elif host_long_bits < 64
5038  message()
5039  warning('DEPRECATED HOST CPU')
5040  message()
5041  message('Support for 32-bit CPU host architecture ' + cpu + ' is going')
5042  message('to be dropped in a future QEMU release.')
5043endif
5044
5045if not supported_oses.contains(host_os)
5046  message()
5047  warning('UNSUPPORTED HOST OS')
5048  message()
5049  message('Support for host OS ' + host_os + 'is not currently maintained.')
5050  message('configure has succeeded and you can continue to build, but')
5051  message('the QEMU project does not guarantee that QEMU will compile or')
5052  message('work on this operating system. You can help by volunteering')
5053  message('to maintain it and providing a build host for our continuous')
5054  message('integration setup. This will ensure that future versions of QEMU')
5055  message('will keep working on ' + host_os + '.')
5056endif
5057
5058if host_arch == 'unknown' or not supported_oses.contains(host_os)
5059  message()
5060  message('If you want to help supporting QEMU on this platform, please')
5061  message('contact the developers at qemu-devel@nongnu.org.')
5062endif
5063
5064actually_reloc = get_option('relocatable')
5065# check if get_relocated_path() is actually able to relocate paths
5066if get_option('relocatable') and \
5067  not (get_option('prefix') / get_option('bindir')).startswith(get_option('prefix') / '')
5068  message()
5069  warning('bindir not included within prefix, the installation will not be relocatable.')
5070  actually_reloc = false
5071endif
5072if not actually_reloc and (host_os == 'windows' or get_option('relocatable'))
5073  if host_os == 'windows'
5074    message()
5075    warning('Windows installs should usually be relocatable.')
5076  endif
5077  message()
5078  message('QEMU will have to be installed under ' + get_option('prefix') + '.')
5079  message('Use --disable-relocatable to remove this warning.')
5080endif
5081