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