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