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