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