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