diff options
Diffstat (limited to 'meson.build')
-rw-r--r-- | meson.build | 1009 |
1 files changed, 763 insertions, 246 deletions
diff --git a/meson.build b/meson.build index 97e00d6..b5f74aa 100644 --- a/meson.build +++ b/meson.build @@ -1,11 +1,16 @@ -project('qemu', ['c'], meson_version: '>=0.63.0', +project('qemu', ['c'], meson_version: '>=1.5.0', default_options: ['warning_level=1', 'c_std=gnu11', 'cpp_std=gnu++11', 'b_colorout=auto', 'b_staticpic=false', 'stdsplit=false', 'optimization=2', 'b_pie=true'], version: files('VERSION')) -add_test_setup('quick', exclude_suites: ['slow', 'thorough'], is_default: true) -add_test_setup('slow', exclude_suites: ['thorough'], env: ['G_TEST_SLOW=1', 'SPEED=slow']) -add_test_setup('thorough', env: ['G_TEST_SLOW=1', 'SPEED=thorough']) +meson.add_devenv({ 'MESON_BUILD_ROOT' : meson.project_build_root() }) + +add_test_setup('quick', exclude_suites: ['slow', 'thorough'], is_default: true, + env: ['RUST_BACKTRACE=1']) +add_test_setup('slow', exclude_suites: ['thorough'], + env: ['G_TEST_SLOW=1', 'SPEED=slow', 'RUST_BACKTRACE=1']) +add_test_setup('thorough', + env: ['G_TEST_SLOW=1', 'SPEED=thorough', 'RUST_BACKTRACE=1']) meson.add_postconf_script(find_program('scripts/symlink-install-tree.py')) @@ -15,6 +20,7 @@ meson.add_postconf_script(find_program('scripts/symlink-install-tree.py')) not_found = dependency('', required: false) keyval = import('keyval') +rust = import('rust') ss = import('sourceset') fs = import('fs') @@ -44,14 +50,25 @@ genh = [] qapi_trace_events = [] bsd_oses = ['gnu/kfreebsd', 'freebsd', 'netbsd', 'openbsd', 'dragonfly', 'darwin'] -supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux'] +supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux', 'emscripten'] supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv32', 'riscv64', 'x86', 'x86_64', - 'arm', 'aarch64', 'loongarch64', 'mips', 'mips64', 'sparc64'] + 'arm', 'aarch64', 'loongarch64', 'mips', 'mips64', 'sparc64', 'wasm32'] cpu = host_machine.cpu_family() target_dirs = config_host['TARGET_DIRS'].split() +# type of binaries to build +have_linux_user = false +have_bsd_user = false +have_system = false +foreach target : target_dirs + have_linux_user = have_linux_user or target.endswith('linux-user') + have_bsd_user = have_bsd_user or target.endswith('bsd-user') + have_system = have_system or target.endswith('-softmmu') +endforeach +have_user = have_linux_user or have_bsd_user + ############ # Programs # ############ @@ -71,6 +88,66 @@ if host_os == 'darwin' and \ objc = meson.get_compiler('objc') endif +have_rust = add_languages('rust', native: false, + required: get_option('rust').disable_auto_if(not have_system)) +have_rust = have_rust and add_languages('rust', native: true, + required: get_option('rust').disable_auto_if(not have_system)) +if have_rust + rustc = meson.get_compiler('rust') + if rustc.version().version_compare('<1.77.0') + if get_option('rust').enabled() + error('rustc version ' + rustc.version() + ' is unsupported. Please upgrade to at least 1.77.0') + else + warning('rustc version ' + rustc.version() + ' is unsupported, disabling Rust compilation.') + message('Please upgrade to at least 1.77.0 to use Rust.') + have_rust = false + endif + endif +endif + +if have_rust + rustdoc = find_program('rustdoc', required: get_option('rust')) + bindgen = find_program('bindgen', required: get_option('rust')) + if not bindgen.found() or bindgen.version().version_compare('<0.60.0') + if get_option('rust').enabled() + error('bindgen version ' + bindgen.version() + ' is unsupported. You can install a new version with "cargo install bindgen-cli"') + else + if bindgen.found() + warning('bindgen version ' + bindgen.version() + ' is unsupported, disabling Rust compilation.') + else + warning('bindgen not found, disabling Rust compilation.') + endif + message('To use Rust you can install a new version with "cargo install bindgen-cli"') + have_rust = false + endif + endif +endif + +if have_rust + rustc_args = [find_program('scripts/rust/rustc_args.py'), + '--rustc-version', rustc.version(), + '--workspace', meson.project_source_root() / 'rust'] + if get_option('strict_rust_lints') + rustc_args += ['--strict-lints'] + endif + + rustfmt = find_program('rustfmt', required: false) + + rustc_lint_args = run_command(rustc_args, '--lints', + capture: true, check: true).stdout().strip().splitlines() + + # Apart from procedural macros, our Rust executables will often link + # with C code, so include all the libraries that C code needs. This + # is safe; https://github.com/rust-lang/rust/pull/54675 says that + # passing -nodefaultlibs to the linker "was more ideological to + # start with than anything". + add_project_arguments(rustc_lint_args + + ['--cfg', 'MESON', '-C', 'default-linker-libraries'], + native: false, language: 'rust') + add_project_arguments(rustc_lint_args + ['--cfg', 'MESON'], + native: true, language: 'rust') +endif + dtrace = not_found stap = not_found if 'dtrace' in get_option('trace_backends') @@ -93,7 +170,7 @@ else iasl = find_program(get_option('iasl'), required: true) endif -edk2_targets = [ 'arm-softmmu', 'aarch64-softmmu', 'i386-softmmu', 'x86_64-softmmu' ] +edk2_targets = [ 'arm-softmmu', 'aarch64-softmmu', 'i386-softmmu', 'x86_64-softmmu', 'riscv64-softmmu', 'loongarch64-softmmu' ] unpack_edk2_blobs = false foreach target : edk2_targets if target in target_dirs @@ -171,16 +248,7 @@ have_vhost_net_vdpa = have_vhost_vdpa and get_option('vhost_net').allowed() have_vhost_net_kernel = have_vhost_kernel and get_option('vhost_net').allowed() have_vhost_net = have_vhost_net_kernel or have_vhost_net_user or have_vhost_net_vdpa -# type of binaries to build -have_linux_user = false -have_bsd_user = false -have_system = false -foreach target : target_dirs - have_linux_user = have_linux_user or target.endswith('linux-user') - have_bsd_user = have_bsd_user or target.endswith('bsd-user') - have_system = have_system or target.endswith('-softmmu') -endforeach -have_user = have_linux_user or have_bsd_user +have_tcg = get_option('tcg').allowed() and (have_system or have_user) have_tools = get_option('tools') \ .disable_auto_if(not have_system) \ @@ -215,30 +283,41 @@ else host_arch = cpu endif -if cpu in ['x86', 'x86_64'] +if cpu == 'x86' + kvm_targets = ['i386-softmmu'] +elif cpu == 'x86_64' kvm_targets = ['i386-softmmu', 'x86_64-softmmu'] elif cpu == 'aarch64' kvm_targets = ['aarch64-softmmu'] elif cpu == 's390x' kvm_targets = ['s390x-softmmu'] -elif cpu in ['ppc', 'ppc64'] +elif cpu == 'ppc' + kvm_targets = ['ppc-softmmu'] +elif cpu == 'ppc64' kvm_targets = ['ppc-softmmu', 'ppc64-softmmu'] -elif cpu in ['mips', 'mips64'] +elif cpu == 'mips' + kvm_targets = ['mips-softmmu', 'mipsel-softmmu'] +elif cpu == 'mips64' kvm_targets = ['mips-softmmu', 'mipsel-softmmu', 'mips64-softmmu', 'mips64el-softmmu'] -elif cpu in ['riscv32'] +elif cpu == 'riscv32' kvm_targets = ['riscv32-softmmu'] -elif cpu in ['riscv64'] +elif cpu == 'riscv64' kvm_targets = ['riscv64-softmmu'] -elif cpu in ['loongarch64'] +elif cpu == 'loongarch64' kvm_targets = ['loongarch64-softmmu'] else kvm_targets = [] endif accelerator_targets = { 'CONFIG_KVM': kvm_targets } -if cpu in ['x86', 'x86_64'] +if cpu == 'x86' + xen_targets = ['i386-softmmu'] +elif cpu == 'x86_64' xen_targets = ['i386-softmmu', 'x86_64-softmmu'] -elif cpu in ['arm', 'aarch64'] +elif cpu == 'arm' + # i386 emulator provides xenpv machine type for multiple architectures + xen_targets = ['i386-softmmu'] +elif cpu == 'aarch64' # i386 emulator provides xenpv machine type for multiple architectures xen_targets = ['i386-softmmu', 'x86_64-softmmu', 'aarch64-softmmu'] else @@ -246,13 +325,11 @@ else endif accelerator_targets += { 'CONFIG_XEN': xen_targets } -if cpu in ['aarch64'] +if cpu == 'aarch64' accelerator_targets += { 'CONFIG_HVF': ['aarch64-softmmu'] } -endif - -if cpu in ['x86', 'x86_64'] +elif cpu == 'x86_64' accelerator_targets += { 'CONFIG_HVF': ['x86_64-softmmu'], 'CONFIG_NVMM': ['i386-softmmu', 'x86_64-softmmu'], @@ -260,12 +337,6 @@ if cpu in ['x86', 'x86_64'] } endif -modular_tcg = [] -# Darwin does not support references to thread-local variables in modules -if host_os != 'darwin' - modular_tcg = ['i386-softmmu', 'x86_64-softmmu'] -endif - ################## # Compiler flags # ################## @@ -276,8 +347,8 @@ foreach lang : all_languages # ok elif compiler.get_id() == 'clang' and compiler.compiles(''' #ifdef __apple_build_version__ - # if __clang_major__ < 12 || (__clang_major__ == 12 && __clang_minor__ < 0) - # error You need at least XCode Clang v12.0 to compile QEMU + # if __clang_major__ < 15 || (__clang_major__ == 15 && __clang_minor__ < 0) + # error You need at least XCode Clang v15.0 to compile QEMU # endif #else # if __clang_major__ < 10 || (__clang_major__ == 10 && __clang_minor__ < 0) @@ -285,8 +356,10 @@ foreach lang : all_languages # endif #endif''') # ok + elif compiler.get_id() == 'emscripten' + # ok else - error('You either need GCC v7.4 or Clang v10.0 (or XCode Clang v12.0) to compile QEMU') + error('You either need GCC v7.4 or Clang v10.0 (or XCode Clang v15.0) to compile QEMU') endif endforeach @@ -315,8 +388,17 @@ elif host_os == 'sunos' qemu_common_flags += '-D__EXTENSIONS__' elif host_os == 'haiku' qemu_common_flags += ['-DB_USE_POSITIVE_POSIX_ERRORS', '-D_BSD_SOURCE', '-fPIC'] +elif host_os == 'windows' + # plugins use delaylib, and clang needs to be used with lld to make it work. + if compiler.get_id() == 'clang' and compiler.get_linker_id() != 'ld.lld' + error('On windows, you need to use lld with clang - use msys2 clang64/clangarm64 env') + endif endif +# Choose instruction set (currently x86-only) + +qemu_isa_flags = [] + # __sync_fetch_and_and requires at least -march=i486. Many toolchains # use i686 as default anyway, but for those that don't, an explicit # specification is necessary @@ -333,20 +415,47 @@ if host_arch == 'i386' and not cc.links(''' sfaa(&val); return val; }''') - qemu_common_flags = ['-march=i486'] + qemu_common_flags + qemu_isa_flags += ['-march=i486'] endif -# Assume x86-64-v2 (minus CMPXCHG16B for 32-bit code) -if host_arch == 'i386' - qemu_common_flags = ['-mfpmath=sse'] + qemu_common_flags -endif +# Pick x86-64 baseline version if host_arch in ['i386', 'x86_64'] - qemu_common_flags = ['-mpopcnt', '-msse4.2'] + qemu_common_flags -endif -if host_arch == 'x86_64' - qemu_common_flags = ['-mcx16'] + qemu_common_flags + if get_option('x86_version') == '0' and host_arch == 'x86_64' + error('x86_64-v1 required for x86-64 hosts') + endif + + # add flags for individual instruction set extensions + if get_option('x86_version') >= '1' + if host_arch == 'i386' + qemu_common_flags = ['-mfpmath=sse'] + qemu_common_flags + else + # present on basically all processors but technically not part of + # x86-64-v1, so only include -mneeded for x86-64 version 2 and above + qemu_isa_flags += ['-mcx16'] + endif + endif + if get_option('x86_version') >= '2' + qemu_isa_flags += ['-mpopcnt'] + qemu_isa_flags += cc.get_supported_arguments('-mneeded') + endif + if get_option('x86_version') >= '3' + qemu_isa_flags += ['-mmovbe', '-mabm', '-mbmi', '-mbmi2', '-mfma', '-mf16c'] + endif + + # add required vector instruction set (each level implies those below) + if get_option('x86_version') == '1' + qemu_isa_flags += ['-msse2'] + elif get_option('x86_version') == '2' + qemu_isa_flags += ['-msse4.2'] + elif get_option('x86_version') == '3' + qemu_isa_flags += ['-mavx2'] + elif get_option('x86_version') == '4' + qemu_isa_flags += ['-mavx512f', '-mavx512bw', '-mavx512cd', '-mavx512dq', '-mavx512vl'] + endif endif +qemu_common_flags = qemu_isa_flags + qemu_common_flags + if get_option('prefer_static') qemu_ldflags += get_option('b_pie') ? '-static-pie' : '-static' endif @@ -366,7 +475,10 @@ endif # instead, we can't add -no-pie because it overrides -shared: the linker then # tries to build an executable instead of a shared library and fails. So # don't add -no-pie anywhere and cross fingers. :( -if not get_option('b_pie') +# +# Emscripten doesn't support -no-pie but meson can't catch the compiler +# warning. So explicitly omit the flag for Emscripten. +if not get_option('b_pie') and host_os != 'emscripten' qemu_common_flags += cc.get_supported_arguments('-fno-pie', '-no-pie') endif @@ -410,6 +522,8 @@ ucontext_probe = ''' supported_backends = [] if host_os == 'windows' supported_backends += ['windows'] +elif host_os == 'emscripten' + supported_backends += ['wasm'] else if host_os != 'darwin' and cc.links(ucontext_probe) supported_backends += ['ucontext'] @@ -449,24 +563,38 @@ if get_option('safe_stack') and coroutine_backend != 'ucontext' error('SafeStack is only supported with the ucontext coroutine backend') endif -if get_option('sanitizers') +if get_option('asan') if cc.has_argument('-fsanitize=address') qemu_cflags = ['-fsanitize=address'] + qemu_cflags qemu_ldflags = ['-fsanitize=address'] + qemu_ldflags + else + error('Your compiler does not support -fsanitize=address') endif +endif - # Detect static linking issue with ubsan - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84285 +if get_option('ubsan') + # Detect static linking issue with ubsan: + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84285 if cc.links('int main(int argc, char **argv) { return argc + 1; }', args: [qemu_ldflags, '-fsanitize=undefined']) - qemu_cflags = ['-fsanitize=undefined'] + qemu_cflags - qemu_ldflags = ['-fsanitize=undefined'] + qemu_ldflags + qemu_cflags += ['-fsanitize=undefined'] + qemu_ldflags += ['-fsanitize=undefined'] + + # Suppress undefined behaviour from function call to mismatched type. + # In addition, tcg prologue does not emit function type prefix + # required by function call sanitizer. + if cc.has_argument('-fno-sanitize=function') + qemu_cflags += ['-fno-sanitize=function'] + endif + else + error('Your compiler does not support -fsanitize=undefined') endif endif # Thread sanitizer is, for now, much noisier than the other sanitizers; # keep it separate until that is not the case. if get_option('tsan') - if get_option('sanitizers') + if get_option('asan') or get_option('ubsan') error('TSAN is not supported with other sanitizers') endif if not cc.has_function('__tsan_create_fiber', @@ -474,7 +602,15 @@ if get_option('tsan') prefix: '#include <sanitizer/tsan_interface.h>') error('Cannot enable TSAN due to missing fiber annotation interface') endif - qemu_cflags = ['-fsanitize=thread'] + qemu_cflags + tsan_warn_suppress = [] + # gcc (>=11) will report constructions not supported by tsan: + # "error: ‘atomic_thread_fence’ is not supported with ‘-fsanitize=thread’" + # https://gcc.gnu.org/gcc-11/changes.html + # However, clang does not support this warning and this triggers an error. + if cc.has_argument('-Wno-tsan') + tsan_warn_suppress = ['-Wno-tsan'] + endif + qemu_cflags = ['-fsanitize=thread'] + tsan_warn_suppress + qemu_cflags qemu_ldflags = ['-fsanitize=thread'] + qemu_ldflags endif @@ -624,7 +760,19 @@ warn_flags = [ ] if host_os != 'darwin' - warn_flags += ['-Wthread-safety'] + tsa_has_cleanup = cc.compiles(''' + struct __attribute__((capability("mutex"))) mutex {}; + void lock(struct mutex *m) __attribute__((acquire_capability(m))); + void unlock(struct mutex *m) __attribute__((release_capability(m))); + + void test(void) { + struct mutex __attribute__((cleanup(unlock))) m; + lock(&m); + } + ''', args: ['-Wthread-safety', '-Werror']) + if tsa_has_cleanup + warn_flags += ['-Wthread-safety'] + endif endif # Set up C++ compiler flags @@ -685,17 +833,22 @@ socket = [] version_res = [] coref = [] iokit = [] +pvg = not_found emulator_link_args = [] midl = not_found widl = not_found pathcch = not_found +synchronization = not_found host_dsosuf = '.so' if host_os == 'windows' midl = find_program('midl', required: false) widl = find_program('widl', required: false) - pathcch = cc.find_library('pathcch') - socket = cc.find_library('ws2_32') - winmm = cc.find_library('winmm') + + # MinGW uses lowercase for library names + pathcch = cc.find_library('pathcch', required: true) + synchronization = cc.find_library('synchronization', required: true) + socket = cc.find_library('ws2_32', required: true) + winmm = cc.find_library('winmm', required: true) win = import('windows') version_res = win.compile_resources('version.rc', @@ -706,6 +859,8 @@ elif host_os == 'darwin' coref = dependency('appleframeworks', modules: 'CoreFoundation') iokit = dependency('appleframeworks', modules: 'IOKit', required: false) host_dsosuf = '.dylib' + pvg = dependency('appleframeworks', modules: ['ParavirtualizedGraphics', 'Metal'], + required: get_option('pvg')) elif host_os == 'sunos' socket = [cc.find_library('socket'), cc.find_library('nsl'), @@ -715,7 +870,7 @@ elif host_os == 'haiku' cc.find_library('network'), cc.find_library('bsd')] elif host_os == 'openbsd' - if get_option('tcg').allowed() and target_dirs.length() > 0 + if have_tcg # Disable OpenBSD W^X if available emulator_link_args = cc.get_supported_link_arguments('-Wl,-z,wxneeded') endif @@ -756,11 +911,15 @@ if host_os == 'netbsd' endif tcg_arch = host_arch -if get_option('tcg').allowed() +if have_tcg if host_arch == 'unknown' if not get_option('tcg_interpreter') error('Unsupported CPU @0@, try --enable-tcg-interpreter'.format(cpu)) endif + elif host_arch == 'wasm32' + if not get_option('tcg_interpreter') + error('WebAssembly host requires --enable-tcg-interpreter') + endif elif get_option('tcg_interpreter') warning('Use of the TCG interpreter is not recommended on this host') warning('architecture. There is a native TCG execution backend available') @@ -879,7 +1038,9 @@ have_xen_pci_passthrough = get_option('xen_pci_passthrough') \ ################ # When bumping glib minimum version, please check also whether to increase -# the _WIN32_WINNT setting in osdep.h according to the value from glib +# the _WIN32_WINNT setting in osdep.h according to the value from glib. +# You should also check if any of the glib.version() checks +# below can also be removed. glib_req_ver = '>=2.66.0' glib_pc = dependency('glib-2.0', version: glib_req_ver, required: true, method: 'pkg-config') @@ -929,6 +1090,9 @@ glib = declare_dependency(dependencies: [glib_pc, gmodule], # TODO: remove this check and the corresponding workaround (qtree) when # the minimum supported glib is >= 2.75.3 glib_has_gslice = glib.version().version_compare('<2.75.3') +# Check whether glib has the aligned_alloc family of functions. +# <https://docs.gtk.org/glib/func.aligned_alloc.html> +glib_has_aligned_alloc = glib.version().version_compare('>=2.72.0') # override glib dep to include the above refinements meson.override_dependency('glib-2.0', glib) @@ -956,7 +1120,7 @@ if not get_option('gio').auto() or have_system gio = not_found endif if gio.found() - gdbus_codegen = find_program(gio.get_variable('gdbus_codegen'), + gdbus_codegen = find_program('gdbus-codegen', required: get_option('gio')) gio_unix = dependency('gio-unix-2.0', required: get_option('gio'), method: 'pkg-config') @@ -1008,7 +1172,7 @@ endif libnfs = not_found if not get_option('libnfs').auto() or have_block - libnfs = dependency('libnfs', version: '>=1.9.3', + libnfs = dependency('libnfs', version: ['>=1.9.3', '<6.0.0'], required: get_option('libnfs'), method: 'pkg-config') endif @@ -1045,7 +1209,8 @@ if get_option('attr').allowed() endif endif -cocoa = dependency('appleframeworks', modules: ['Cocoa', 'CoreVideo'], +cocoa = dependency('appleframeworks', + modules: ['Cocoa', 'CoreVideo', 'QuartzCore'], required: get_option('cocoa')) vmnet = dependency('appleframeworks', modules: 'vmnet', required: get_option('vmnet')) @@ -1219,6 +1384,14 @@ if not get_option('uadk').auto() or have_system uadk = declare_dependency(dependencies: [libwd, libwd_comp]) endif endif + +qatzip = not_found +if not get_option('qatzip').auto() or have_system + qatzip = dependency('qatzip', version: '>=1.1.2', + required: get_option('qatzip'), + method: 'pkg-config') +endif + virgl = not_found have_vhost_user_gpu = have_tools and host_os == 'linux' and pixman.found() @@ -1309,7 +1482,7 @@ iconv = not_found curses = not_found if have_system and get_option('curses').allowed() curses_test = ''' - #if defined(__APPLE__) || defined(__OpenBSD__) + #ifdef __APPLE__ #define _XOPEN_SOURCE_EXTENDED 1 #endif #include <locale.h> @@ -1618,6 +1791,12 @@ if (have_system or have_tools) and (virgl.found() or opengl.found()) endif have_vhost_user_gpu = have_vhost_user_gpu and virgl.found() and opengl.found() and gbm.found() +libcbor = not_found +if not get_option('libcbor').auto() or have_system + libcbor = dependency('libcbor', version: '>=0.7.0', + required: get_option('libcbor')) +endif + gnutls = not_found gnutls_crypto = not_found if get_option('gnutls').enabled() or (get_option('gnutls').auto() and have_system) @@ -1656,6 +1835,7 @@ gcrypt = not_found nettle = not_found hogweed = not_found crypto_sm4 = not_found +crypto_sm3 = not_found xts = 'none' if get_option('nettle').enabled() and get_option('gcrypt').enabled() @@ -1670,7 +1850,6 @@ endif if not gnutls_crypto.found() if (not get_option('gcrypt').auto() or have_system) and not get_option('nettle').enabled() gcrypt = dependency('libgcrypt', version: '>=1.8', - method: 'config-tool', required: get_option('gcrypt')) # Debian has removed -lgpg-error from libgcrypt-config # as it "spreads unnecessary dependencies" which in @@ -1692,6 +1871,17 @@ if not gnutls_crypto.found() }''', dependencies: gcrypt) crypto_sm4 = not_found endif + crypto_sm3 = gcrypt + # SM3 ALG is available in libgcrypt >= 1.9 + if gcrypt.found() and not cc.links(''' + #include <gcrypt.h> + int main(void) { + gcry_md_hd_t handler; + gcry_md_open(&handler, GCRY_MD_SM3, 0); + return 0; + }''', dependencies: gcrypt) + crypto_sm3 = not_found + endif endif if (not get_option('nettle').auto() or have_system) and not gcrypt.found() nettle = dependency('nettle', version: '>=3.4', @@ -1712,6 +1902,31 @@ if not gnutls_crypto.found() }''', dependencies: nettle) crypto_sm4 = not_found endif + crypto_sm3 = nettle + # SM3 ALG is available in nettle >= 3.8 + if nettle.found() and not cc.links(''' + #include <nettle/sm3.h> + #include <nettle/hmac.h> + int main(void) { + struct sm3_ctx ctx; + struct hmac_sm3_ctx hmac_ctx; + unsigned char data[64] = {0}; + unsigned char output[32]; + + // SM3 hash function test + sm3_init(&ctx); + sm3_update(&ctx, 64, data); + sm3_digest(&ctx, 32, data); + + // HMAC-SM3 test + hmac_sm3_set_key(&hmac_ctx, 32, data); + hmac_sm3_update(&hmac_ctx, 64, data); + hmac_sm3_digest(&hmac_ctx, 32, output); + + return 0; + }''', dependencies: nettle) + crypto_sm3 = not_found + endif endif endif @@ -1953,6 +2168,7 @@ endif tasn1 = not_found if gnutls.found() tasn1 = dependency('libtasn1', + required: false, method: 'pkg-config') endif keyutils = not_found @@ -1987,19 +2203,23 @@ if not has_malloc_trim and get_option('malloc_trim').enabled() endif endif -gnu_source_prefix = ''' +osdep_prefix = ''' #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif -''' - -# Check whether the glibc provides STATX_BASIC_STATS - -has_statx = cc.has_header_symbol('sys/stat.h', 'STATX_BASIC_STATS', prefix: gnu_source_prefix) -# Check whether statx() provides mount ID information + #include <stddef.h> + #include <sys/types.h> -has_statx_mnt_id = cc.has_header_symbol('sys/stat.h', 'STATX_MNT_ID', prefix: gnu_source_prefix) + #include <string.h> + #include <limits.h> + /* Put unistd.h before time.h as that triggers localtime_r/gmtime_r + * function availability on recentish Mingw-w64 platforms. */ + #include <unistd.h> + #include <time.h> + #include <errno.h> + #include <fcntl.h> +''' have_vhost_user_blk_server = get_option('vhost_user_blk_server') \ .require(host_os == 'linux', @@ -2074,8 +2294,14 @@ endif # libxdp libxdp = not_found if not get_option('af_xdp').auto() or have_system - libxdp = dependency('libxdp', required: get_option('af_xdp'), - version: '>=1.4.0', method: 'pkg-config') + if libbpf.found() + libxdp = dependency('libxdp', required: get_option('af_xdp'), + version: '>=1.4.0', method: 'pkg-config') + else + if get_option('af_xdp').enabled() + error('libxdp requested, but libbpf is not available') + endif + endif endif # libdw @@ -2093,6 +2319,7 @@ endif config_host_data = configuration_data() +config_host_data.set('CONFIG_HAVE_RUST', have_rust) audio_drivers_selected = [] if have_system audio_drivers_available = { @@ -2154,12 +2381,18 @@ have_virtfs = get_option('virtfs') \ .disable_auto_if(not have_tools and not have_system) \ .allowed() -have_virtfs_proxy_helper = get_option('virtfs_proxy_helper') \ - .require(host_os != 'darwin', error_message: 'the virtfs proxy helper is incompatible with macOS') \ - .require(have_virtfs, error_message: 'the virtfs proxy helper requires that virtfs is enabled') \ - .disable_auto_if(not have_tools) \ - .require(libcap_ng.found(), error_message: 'the virtfs proxy helper requires libcap-ng') \ - .allowed() +qga_fsfreeze = false +qga_fstrim = false +if host_os == 'linux' + if cc.has_header_symbol('linux/fs.h', 'FIFREEZE') + qga_fsfreeze = true + endif + if cc.has_header_symbol('linux/fs.h', 'FITRIM') + qga_fstrim = true + endif +elif host_os == 'freebsd' and cc.has_header_symbol('ufs/ffs/fs.h', 'UFSSUSPEND') + qga_fsfreeze = true +endif if get_option('block_drv_ro_whitelist') == '' config_host_data.set('CONFIG_BDRV_RO_WHITELIST', '') @@ -2237,6 +2470,7 @@ config_host_data.set('CONFIG_ATTR', libattr.found()) config_host_data.set('CONFIG_BDRV_WHITELIST_TOOLS', get_option('block_drv_whitelist_in_tools')) config_host_data.set('CONFIG_BRLAPI', brlapi.found()) config_host_data.set('CONFIG_BSD', host_os in bsd_oses) +config_host_data.set('CONFIG_FREEBSD', host_os == 'freebsd') config_host_data.set('CONFIG_CAPSTONE', capstone.found()) config_host_data.set('CONFIG_COCOA', cocoa.found()) config_host_data.set('CONFIG_DARWIN', host_os == 'darwin') @@ -2253,6 +2487,8 @@ config_host_data.set('CONFIG_BLKIO', blkio.found()) if blkio.found() config_host_data.set('CONFIG_BLKIO_VHOST_VDPA_FD', blkio.version().version_compare('>=1.3.0')) + config_host_data.set('CONFIG_BLKIO_WRITE_ZEROS_FUA', + blkio.version().version_compare('>=1.4.0')) endif config_host_data.set('CONFIG_CURL', curl.found()) config_host_data.set('CONFIG_CURSES', curses.found()) @@ -2305,7 +2541,7 @@ config_host_data.set('CONFIG_PIXMAN', pixman.found()) config_host_data.set('CONFIG_SLIRP', slirp.found()) config_host_data.set('CONFIG_SNAPPY', snappy.found()) config_host_data.set('CONFIG_SOLARIS', host_os == 'sunos') -if get_option('tcg').allowed() +if have_tcg config_host_data.set('CONFIG_TCG', 1) config_host_data.set('CONFIG_TCG_INTERPRETER', tcg_arch == 'tci') endif @@ -2329,10 +2565,7 @@ config_host_data.set('CONFIG_VNC', vnc.found()) config_host_data.set('CONFIG_VNC_JPEG', jpeg.found()) config_host_data.set('CONFIG_VNC_SASL', sasl.found()) if virgl.found() - config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', - cc.has_member('struct virgl_renderer_resource_info_ext', 'd3d_tex2d', - prefix: '#include <virglrenderer.h>', - dependencies: virgl)) + config_host_data.set('VIRGL_VERSION_MAJOR', virgl.version().split('.')[0]) endif config_host_data.set('CONFIG_VIRTFS', have_virtfs) config_host_data.set('CONFIG_VTE', vte.found()) @@ -2345,14 +2578,14 @@ config_host_data.set('CONFIG_TASN1', tasn1.found()) config_host_data.set('CONFIG_GCRYPT', gcrypt.found()) config_host_data.set('CONFIG_NETTLE', nettle.found()) config_host_data.set('CONFIG_CRYPTO_SM4', crypto_sm4.found()) +config_host_data.set('CONFIG_CRYPTO_SM3', crypto_sm3.found()) config_host_data.set('CONFIG_HOGWEED', hogweed.found()) config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private') config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim) -config_host_data.set('CONFIG_STATX', has_statx) -config_host_data.set('CONFIG_STATX_MNT_ID', has_statx_mnt_id) config_host_data.set('CONFIG_ZSTD', zstd.found()) config_host_data.set('CONFIG_QPL', qpl.found()) config_host_data.set('CONFIG_UADK', uadk.found()) +config_host_data.set('CONFIG_QATZIP', qatzip.found()) config_host_data.set('CONFIG_FUSE', fuse.found()) config_host_data.set('CONFIG_FUSE_LSEEK', fuse_lseek.found()) config_host_data.set('CONFIG_SPICE_PROTOCOL', spice_protocol.found()) @@ -2397,13 +2630,26 @@ config_host_data.set('CONFIG_DEBUG_TCG', get_option('debug_tcg')) config_host_data.set('CONFIG_DEBUG_REMAP', get_option('debug_remap')) config_host_data.set('CONFIG_QOM_CAST_DEBUG', get_option('qom_cast_debug')) config_host_data.set('CONFIG_REPLICATION', get_option('replication').allowed()) +config_host_data.set('CONFIG_FSFREEZE', qga_fsfreeze) +config_host_data.set('CONFIG_FSTRIM', qga_fstrim) # has_header config_host_data.set('CONFIG_EPOLL', cc.has_header('sys/epoll.h')) config_host_data.set('CONFIG_LINUX_MAGIC_H', cc.has_header('linux/magic.h')) -config_host_data.set('CONFIG_VALGRIND_H', cc.has_header('valgrind/valgrind.h')) +valgrind = false +if get_option('valgrind').allowed() + if cc.has_header('valgrind/valgrind.h') + valgrind = true + else + if get_option('valgrind').enabled() + error('valgrind requested but valgrind.h not found') + endif + endif +endif +config_host_data.set('CONFIG_VALGRIND_H', valgrind) config_host_data.set('HAVE_BTRFS_H', cc.has_header('linux/btrfs.h')) config_host_data.set('HAVE_DRM_H', cc.has_header('libdrm/drm.h')) +config_host_data.set('HAVE_OPENAT2_H', cc.has_header('linux/openat2.h')) config_host_data.set('HAVE_PTY_H', cc.has_header('pty.h')) config_host_data.set('HAVE_SYS_DISK_H', cc.has_header('sys/disk.h')) config_host_data.set('HAVE_SYS_IOCCOM_H', cc.has_header('sys/ioccom.h')) @@ -2419,7 +2665,6 @@ config_host_data.set('CONFIG_CLOCK_ADJTIME', cc.has_function('clock_adjtime')) config_host_data.set('CONFIG_DUP3', cc.has_function('dup3')) config_host_data.set('CONFIG_FALLOCATE', cc.has_function('fallocate')) config_host_data.set('CONFIG_POSIX_FALLOCATE', cc.has_function('posix_fallocate')) -config_host_data.set('CONFIG_GETCPU', cc.has_function('getcpu', prefix: gnu_source_prefix)) config_host_data.set('CONFIG_SCHED_GETCPU', cc.has_function('sched_getcpu', prefix: '#include <sched.h>')) # Note that we need to specify prefix: here to avoid incorrectly # thinking that Windows has posix_memalign() @@ -2435,11 +2680,13 @@ config_host_data.set('CONFIG_SETNS', cc.has_function('setns') and cc.has_functio config_host_data.set('CONFIG_SYNCFS', cc.has_function('syncfs')) config_host_data.set('CONFIG_SYNC_FILE_RANGE', cc.has_function('sync_file_range')) config_host_data.set('CONFIG_TIMERFD', cc.has_function('timerfd_create')) +config_host_data.set('CONFIG_GETLOADAVG', cc.has_function('getloadavg')) config_host_data.set('HAVE_COPY_FILE_RANGE', cc.has_function('copy_file_range')) config_host_data.set('HAVE_GETIFADDRS', cc.has_function('getifaddrs')) config_host_data.set('HAVE_GLIB_WITH_SLICE_ALLOCATOR', glib_has_gslice) +config_host_data.set('HAVE_GLIB_WITH_ALIGNED_ALLOC', glib_has_aligned_alloc) config_host_data.set('HAVE_OPENPTY', cc.has_function('openpty', dependencies: util)) -config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul')) +config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul', prefix: osdep_prefix)) config_host_data.set('HAVE_SYSTEM_FUNCTION', cc.has_function('system', prefix: '#include <stdlib.h>')) if rbd.found() config_host_data.set('HAVE_RBD_NAMESPACE_EXISTS', @@ -2455,7 +2702,7 @@ if rdma.found() endif have_asan_fiber = false -if get_option('sanitizers') and \ +if get_option('asan') and \ not cc.has_function('__sanitizer_start_switch_fiber', args: '-fsanitize=address', prefix: '#include <sanitizer/asan_interface.h>') @@ -2495,6 +2742,8 @@ config_host_data.set('CONFIG_FALLOCATE_ZERO_RANGE', config_host_data.set('CONFIG_FIEMAP', cc.has_header('linux/fiemap.h') and cc.has_header_symbol('linux/fs.h', 'FS_IOC_FIEMAP')) +config_host_data.set('CONFIG_GETCPU', + cc.has_header_symbol('sched.h', 'getcpu', prefix: osdep_prefix)) config_host_data.set('CONFIG_GETRANDOM', cc.has_function('getrandom') and cc.has_header_symbol('sys/random.h', 'GRND_NONBLOCK')) @@ -2508,6 +2757,44 @@ config_host_data.set('HAVE_OPTRESET', cc.has_header_symbol('getopt.h', 'optreset')) config_host_data.set('HAVE_IPPROTO_MPTCP', cc.has_header_symbol('netinet/in.h', 'IPPROTO_MPTCP')) +if libaio.found() + config_host_data.set('HAVE_IO_PREP_PWRITEV2', + cc.has_header_symbol('libaio.h', 'io_prep_pwritev2')) +endif +if linux_io_uring.found() + config_host_data.set('HAVE_IO_URING_PREP_WRITEV2', + cc.has_header_symbol('liburing.h', 'io_uring_prep_writev2')) +endif +config_host_data.set('HAVE_TCP_KEEPCNT', + cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPCNT') or + cc.compiles(''' + #include <ws2tcpip.h> + #ifndef TCP_KEEPCNT + #error + #endif + int main(void) { return 0; }''', + name: 'Win32 TCP_KEEPCNT')) +# On Darwin TCP_KEEPIDLE is available under different name, TCP_KEEPALIVE. +# https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/bsd/man/man4/tcp.4#L172 +config_host_data.set('HAVE_TCP_KEEPIDLE', + cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPIDLE') or + cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPALIVE') or + cc.compiles(''' + #include <ws2tcpip.h> + #ifndef TCP_KEEPIDLE + #error + #endif + int main(void) { return 0; }''', + name: 'Win32 TCP_KEEPIDLE')) +config_host_data.set('HAVE_TCP_KEEPINTVL', + cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPINTVL') or + cc.compiles(''' + #include <ws2tcpip.h> + #ifndef TCP_KEEPINTVL + #error + #endif + int main(void) { return 0; }''', + name: 'Win32 TCP_KEEPINTVL')) # has_member config_host_data.set('HAVE_SIGEV_NOTIFY_THREAD_ID', @@ -2531,8 +2818,7 @@ config_host_data.set('HAVE_UTMPX', config_host_data.set('CONFIG_EVENTFD', cc.links(''' #include <sys/eventfd.h> int main(void) { return eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); }''')) -config_host_data.set('CONFIG_FDATASYNC', cc.links(gnu_source_prefix + ''' - #include <unistd.h> +config_host_data.set('CONFIG_FDATASYNC', cc.links(osdep_prefix + ''' int main(void) { #if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 return fdatasync(0); @@ -2541,10 +2827,8 @@ config_host_data.set('CONFIG_FDATASYNC', cc.links(gnu_source_prefix + ''' #endif }''')) -has_madvise = cc.links(gnu_source_prefix + ''' - #include <sys/types.h> +has_madvise = cc.links(osdep_prefix + ''' #include <sys/mman.h> - #include <stddef.h> int main(void) { return madvise(NULL, 0, MADV_DONTNEED); }''') missing_madvise_proto = false if has_madvise @@ -2554,21 +2838,18 @@ if has_madvise # missing-prototype case, we try again with a definitely-bogus prototype. # This will only compile if the system headers don't provide the prototype; # otherwise the conflicting prototypes will cause a compiler error. - missing_madvise_proto = cc.links(gnu_source_prefix + ''' - #include <sys/types.h> + missing_madvise_proto = cc.links(osdep_prefix + '''> #include <sys/mman.h> - #include <stddef.h> extern int madvise(int); int main(void) { return madvise(0); }''') endif config_host_data.set('CONFIG_MADVISE', has_madvise) config_host_data.set('HAVE_MADVISE_WITHOUT_PROTOTYPE', missing_madvise_proto) -config_host_data.set('CONFIG_MEMFD', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_MEMFD', cc.links(osdep_prefix + ''' #include <sys/mman.h> int main(void) { return memfd_create("foo", MFD_ALLOW_SEALING); }''')) -config_host_data.set('CONFIG_OPEN_BY_HANDLE', cc.links(gnu_source_prefix + ''' - #include <fcntl.h> +config_host_data.set('CONFIG_OPEN_BY_HANDLE', cc.links(osdep_prefix + ''' #if !defined(AT_EMPTY_PATH) # error missing definition #else @@ -2579,13 +2860,12 @@ config_host_data.set('CONFIG_OPEN_BY_HANDLE', cc.links(gnu_source_prefix + ''' # i.e. errno is set and -1 is returned. That's not really how POSIX defines the # function. On the flip side, it has madvise() which is preferred anyways. if host_os != 'darwin' - config_host_data.set('CONFIG_POSIX_MADVISE', cc.links(gnu_source_prefix + ''' + config_host_data.set('CONFIG_POSIX_MADVISE', cc.links(osdep_prefix + ''' #include <sys/mman.h> - #include <stddef.h> int main(void) { return posix_madvise(NULL, 0, POSIX_MADV_DONTNEED); }''')) endif -config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_W_TID', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_W_TID', cc.links(osdep_prefix + ''' #include <pthread.h> static void *f(void *p) { return NULL; } @@ -2596,7 +2876,7 @@ config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_W_TID', cc.links(gnu_source_pref pthread_setname_np(thread, "QEMU"); return 0; }''', dependencies: threads)) -config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_WO_TID', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_WO_TID', cc.links(osdep_prefix + ''' #include <pthread.h> static void *f(void *p) { pthread_setname_np("QEMU"); return NULL; } @@ -2606,7 +2886,7 @@ config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_WO_TID', cc.links(gnu_source_pre pthread_create(&thread, 0, f, 0); return 0; }''', dependencies: threads)) -config_host_data.set('CONFIG_PTHREAD_SET_NAME_NP', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_PTHREAD_SET_NAME_NP', cc.links(osdep_prefix + ''' #include <pthread.h> #include <pthread_np.h> @@ -2618,9 +2898,8 @@ config_host_data.set('CONFIG_PTHREAD_SET_NAME_NP', cc.links(gnu_source_prefix + pthread_set_name_np(thread, "QEMU"); return 0; }''', dependencies: threads)) -config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(osdep_prefix + ''' #include <pthread.h> - #include <time.h> int main(void) { @@ -2629,7 +2908,7 @@ config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(gnu_source_pre pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); return 0; }''', dependencies: threads)) -config_host_data.set('CONFIG_PTHREAD_AFFINITY_NP', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_PTHREAD_AFFINITY_NP', cc.links(osdep_prefix + ''' #include <pthread.h> static void *f(void *p) { return NULL; } @@ -2646,15 +2925,10 @@ config_host_data.set('CONFIG_PTHREAD_AFFINITY_NP', cc.links(gnu_source_prefix + CPU_FREE(cpuset); return 0; }''', dependencies: threads)) -config_host_data.set('CONFIG_SIGNALFD', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_SIGNALFD', cc.links(osdep_prefix + ''' #include <sys/signalfd.h> - #include <stddef.h> int main(void) { return signalfd(-1, NULL, SFD_CLOEXEC); }''')) -config_host_data.set('CONFIG_SPLICE', cc.links(gnu_source_prefix + ''' - #include <unistd.h> - #include <fcntl.h> - #include <limits.h> - +config_host_data.set('CONFIG_SPLICE', cc.links(osdep_prefix + ''' int main(void) { int len, fd = 0; @@ -2663,16 +2937,22 @@ config_host_data.set('CONFIG_SPLICE', cc.links(gnu_source_prefix + ''' return 0; }''')) -config_host_data.set('HAVE_MLOCKALL', cc.links(gnu_source_prefix + ''' +config_host_data.set('HAVE_MLOCKALL', cc.links(osdep_prefix + ''' #include <sys/mman.h> int main(void) { return mlockall(MCL_FUTURE); }''')) +config_host_data.set('HAVE_MLOCK_ONFAULT', cc.links(osdep_prefix + ''' + #include <sys/mman.h> + int main(void) { + return mlockall(MCL_FUTURE | MCL_ONFAULT); + }''')) + have_l2tpv3 = false if get_option('l2tpv3').allowed() and have_system have_l2tpv3 = cc.has_type('struct mmsghdr', - prefix: gnu_source_prefix + ''' + prefix: osdep_prefix + ''' #include <sys/socket.h> #include <linux/ip.h>''') endif @@ -2728,9 +3008,11 @@ config_host_data.set('CONFIG_ATOMIC64', cc.links(''' __atomic_exchange_n(&x, y, __ATOMIC_RELAXED); __atomic_fetch_add(&x, y, __ATOMIC_RELAXED); return 0; - }''')) + }''', args: qemu_isa_flags)) -has_int128_type = cc.compiles(''' +# has_int128_type is set to false on Emscripten to avoid errors by libffi +# during runtime. +has_int128_type = host_os != 'emscripten' and cc.compiles(''' __int128_t a; __uint128_t b; int main(void) { b = a; }''') @@ -2762,7 +3044,7 @@ if has_int128_type __atomic_compare_exchange_n(&p[4], &p[5], p[6], 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); return 0; }''' - has_atomic128 = cc.links(atomic_test_128) + has_atomic128 = cc.links(atomic_test_128, args: qemu_isa_flags) config_host_data.set('CONFIG_ATOMIC128', has_atomic128) @@ -2771,7 +3053,8 @@ if has_int128_type # without optimization enabled. Try again with optimizations locally # enabled for the function. See # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107389 - has_atomic128_opt = cc.links('__attribute__((optimize("O1")))' + atomic_test_128) + has_atomic128_opt = cc.links('__attribute__((optimize("O1")))' + atomic_test_128, + args: qemu_isa_flags) config_host_data.set('CONFIG_ATOMIC128_OPT', has_atomic128_opt) if not has_atomic128_opt @@ -2782,17 +3065,25 @@ if has_int128_type __sync_val_compare_and_swap_16(&x, y, x); return 0; } - ''')) + ''', args: qemu_isa_flags)) endif endif endif -config_host_data.set('CONFIG_GETAUXVAL', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_GETAUXVAL', cc.links(osdep_prefix + ''' #include <sys/auxv.h> int main(void) { return getauxval(AT_HWCAP) == 0; }''')) +config_host_data.set('CONFIG_ELF_AUX_INFO', cc.links(osdep_prefix + ''' + #include <sys/auxv.h> + int main(void) { + unsigned long hwcap = 0; + elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)); + return hwcap; + }''')) + config_host_data.set('CONFIG_USBFS', have_linux_user and cc.compiles(''' #include <linux/usbdevice_fs.h> @@ -2837,34 +3128,22 @@ have_cpuid_h = cc.links(''' }''') config_host_data.set('CONFIG_CPUID_H', have_cpuid_h) -config_host_data.set('CONFIG_AVX2_OPT', get_option('avx2') \ - .require(have_cpuid_h, error_message: 'cpuid.h not available, cannot enable AVX2') \ - .require(cc.links(''' - #include <cpuid.h> +# Don't bother to advertise asm/hwprobe.h for old versions that do +# not contain RISCV_HWPROBE_EXT_ZBA. +config_host_data.set('CONFIG_ASM_HWPROBE_H', + cc.has_header_symbol('asm/hwprobe.h', + 'RISCV_HWPROBE_EXT_ZBA')) + +if have_cpuid_h + have_avx2 = cc.links(''' #include <immintrin.h> static int __attribute__((target("avx2"))) bar(void *a) { __m256i x = *(__m256i *)a; return _mm256_testz_si256(x, x); } int main(int argc, char *argv[]) { return bar(argv[argc - 1]); } - '''), error_message: 'AVX2 not available').allowed()) - -config_host_data.set('CONFIG_AVX512F_OPT', get_option('avx512f') \ - .require(have_cpuid_h, error_message: 'cpuid.h not available, cannot enable AVX512F') \ - .require(cc.links(''' - #include <cpuid.h> - #include <immintrin.h> - static int __attribute__((target("avx512f"))) bar(void *a) { - __m512i x = *(__m512i *)a; - return _mm512_test_epi64_mask(x, x); - } - int main(int argc, char *argv[]) { return bar(argv[argc - 1]); } - '''), error_message: 'AVX512F not available').allowed()) - -config_host_data.set('CONFIG_AVX512BW_OPT', get_option('avx512bw') \ - .require(have_cpuid_h, error_message: 'cpuid.h not available, cannot enable AVX512BW') \ - .require(cc.links(''' - #include <cpuid.h> + ''') + have_avx512bw = cc.links(''' #include <immintrin.h> static int __attribute__((target("avx512bw"))) bar(void *a) { __m512i *x = a; @@ -2872,7 +3151,21 @@ config_host_data.set('CONFIG_AVX512BW_OPT', get_option('avx512bw') \ return res[1]; } int main(int argc, char *argv[]) { return bar(argv[0]); } - '''), error_message: 'AVX512BW not available').allowed()) + ''') + if get_option('x86_version') >= '3' and not have_avx2 + error('Cannot enable AVX optimizations due to missing intrinsics') + elif get_option('x86_version') >= '4' and not have_avx512bw + error('Cannot enable AVX512 optimizations due to missing intrinsics') + endif +else + have_avx2 = false + have_avx512bw = false + if get_option('x86_version') >= '3' + error('Cannot enable AVX optimizations due to missing cpuid.h') + endif +endif +config_host_data.set('CONFIG_AVX2_OPT', have_avx2) +config_host_data.set('CONFIG_AVX512BW_OPT', have_avx512bw) # For both AArch64 and AArch32, detect if builtins are available. config_host_data.set('CONFIG_ARM_AES_BUILTIN', cc.compiles(''' @@ -2904,9 +3197,7 @@ config_host_data.set('CONFIG_MEMBARRIER', get_option('membarrier') \ .allowed()) have_afalg = get_option('crypto_afalg') \ - .require(cc.compiles(gnu_source_prefix + ''' - #include <errno.h> - #include <sys/types.h> + .require(cc.compiles(osdep_prefix + ''' #include <sys/socket.h> #include <linux/if_alg.h> int main(void) { @@ -2945,6 +3236,11 @@ if host_os == 'windows' }''', name: '_lock_file and _unlock_file')) endif +if spice.found() + config_host_data.set('HAVE_SPICE_QXL_GL_SCANOUT2', + cc.has_function('spice_qxl_gl_scanout2', dependencies: spice)) +endif + if host_os == 'windows' mingw_has_setjmp_longjmp = cc.links(''' #include <setjmp.h> @@ -2966,6 +3262,9 @@ if host_os == 'windows' endif endif +# Detect host pointer size for the target configuration loop. +host_long_bits = cc.sizeof('void *') * 8 + ######################## # Target configuration # ######################## @@ -2978,11 +3277,11 @@ config_devices_mak_list = [] config_devices_h = {} config_target_h = {} config_target_mak = {} +config_base_arch_mak = {} disassemblers = { 'alpha' : ['CONFIG_ALPHA_DIS'], 'avr' : ['CONFIG_AVR_DIS'], - 'cris' : ['CONFIG_CRIS_DIS'], 'hexagon' : ['CONFIG_HEXAGON_DIS'], 'hppa' : ['CONFIG_HPPA_DIS'], 'i386' : ['CONFIG_I386_DIS'], @@ -3009,6 +3308,8 @@ host_kconfig = \ (spice.found() ? ['CONFIG_SPICE=y'] : []) + \ (have_ivshmem ? ['CONFIG_IVSHMEM=y'] : []) + \ (opengl.found() ? ['CONFIG_OPENGL=y'] : []) + \ + (libcbor.found() ? ['CONFIG_LIBCBOR=y'] : []) + \ + (gnutls.found() ? ['CONFIG_GNUTLS=y'] : []) + \ (x11.found() ? ['CONFIG_X11=y'] : []) + \ (fdt.found() ? ['CONFIG_FDT=y'] : []) + \ (have_vhost_user ? ['CONFIG_VHOST_USER=y'] : []) + \ @@ -3018,7 +3319,8 @@ host_kconfig = \ (host_os == 'linux' ? ['CONFIG_LINUX=y'] : []) + \ (multiprocess_allowed ? ['CONFIG_MULTIPROCESS_ALLOWED=y'] : []) + \ (vfio_user_server_allowed ? ['CONFIG_VFIO_USER_SERVER_ALLOWED=y'] : []) + \ - (hv_balloon ? ['CONFIG_HV_BALLOON_POSSIBLE=y'] : []) + (hv_balloon ? ['CONFIG_HV_BALLOON_POSSIBLE=y'] : []) + \ + (have_rust ? ['CONFIG_HAVE_RUST=y'] : []) ignored = [ 'TARGET_XML_FILES', 'TARGET_ABI_DIR', 'TARGET_ARCH' ] @@ -3051,20 +3353,22 @@ foreach target : target_dirs config_target += { 'CONFIG_USER_ONLY': 'y', 'CONFIG_QEMU_INTERP_PREFIX': - get_option('interp_prefix').replace('%M', config_target['TARGET_NAME']) + get_option('interp_prefix').replace('%M', config_target['TARGET_NAME']), + 'CONFIG_QEMU_RTSIG_MAP': get_option('rtsig_map'), } endif + config_target += keyval.load('configs/targets' / target + '.mak') + target_kconfig = [] foreach sym: accelerators + # Disallow 64-bit on 32-bit emulation and virtualization + if host_long_bits < config_target['TARGET_LONG_BITS'].to_int() + continue + endif if sym == 'CONFIG_TCG' or target in accelerator_targets.get(sym, []) config_target += { sym: 'y' } config_all_accel += { sym: 'y' } - if target in modular_tcg - config_target += { 'CONFIG_TCG_MODULAR': 'y' } - else - config_target += { 'CONFIG_TCG_BUILTIN': 'y' } - endif target_kconfig += [ sym + '=y' ] endif endforeach @@ -3075,9 +3379,6 @@ foreach target : target_dirs error('No accelerator available for target @0@'.format(target)) endif - config_target += keyval.load('configs/targets' / target + '.mak') - config_target += { 'TARGET_' + config_target['TARGET_ARCH'].to_upper(): 'y' } - if 'TARGET_NEED_FDT' in config_target and not fdt.found() if default_targets warning('Disabling ' + target + ' due to missing libfdt') @@ -3090,6 +3391,7 @@ foreach target : target_dirs actual_target_dirs += target # Add default keys + config_target += { 'TARGET_' + config_target['TARGET_ARCH'].to_upper(): 'y' } if 'TARGET_BASE_ARCH' not in config_target config_target += {'TARGET_BASE_ARCH': config_target['TARGET_ARCH']} endif @@ -3137,6 +3439,12 @@ foreach target : target_dirs target_kconfig += 'CONFIG_' + config_target['TARGET_ARCH'].to_upper() + '=y' target_kconfig += 'CONFIG_TARGET_BIG_ENDIAN=' + config_target['TARGET_BIG_ENDIAN'] + # PVG is not cross-architecture. Use accelerator_targets as a proxy to + # figure out which target can support PVG on this host + if pvg.found() and target in accelerator_targets.get('CONFIG_HVF', []) + target_kconfig += 'CONFIG_MAC_PVG=y' + endif + config_input = meson.get_external_property(target, 'default') config_devices_mak = target + '-config-devices.mak' config_devices_mak = configure_file( @@ -3161,6 +3469,11 @@ foreach target : target_dirs config_all_devices += config_devices endif config_target_mak += {target: config_target} + + # build a merged config for all targets with the same TARGET_BASE_ARCH + target_base_arch = config_target['TARGET_BASE_ARCH'] + config_base_arch = config_base_arch_mak.get(target_base_arch, {}) + config_target + config_base_arch_mak += {target_base_arch: config_base_arch} endforeach target_dirs = actual_target_dirs @@ -3206,7 +3519,8 @@ endif # Generated sources # ##################### -genh += configure_file(output: 'config-host.h', configuration: config_host_data) +config_host_h = configure_file(output: 'config-host.h', configuration: config_host_data) +genh += config_host_h hxtool = find_program('scripts/hxtool') shaderinclude = find_program('scripts/shaderinclude.py') @@ -3224,6 +3538,7 @@ qapi_gen_depends = [ meson.current_source_dir() / 'scripts/qapi/__init__.py', meson.current_source_dir() / 'scripts/qapi/schema.py', meson.current_source_dir() / 'scripts/qapi/source.py', meson.current_source_dir() / 'scripts/qapi/types.py', + meson.current_source_dir() / 'scripts/qapi/features.py', meson.current_source_dir() / 'scripts/qapi/visit.py', meson.current_source_dir() / 'scripts/qapi-gen.py' ] @@ -3307,6 +3622,7 @@ if have_block trace_events_subdirs += [ 'authz', 'block', + 'chardev', 'io', 'nbd', 'scsi', @@ -3314,11 +3630,11 @@ if have_block endif if have_system trace_events_subdirs += [ + 'accel/hvf', 'accel/kvm', 'audio', 'backends', 'backends/tpm', - 'chardev', 'ebpf', 'hw/9pfs', 'hw/acpi', @@ -3353,19 +3669,24 @@ if have_system 'hw/pci-host', 'hw/ppc', 'hw/rtc', + 'hw/riscv', 'hw/s390x', 'hw/scsi', 'hw/sd', + 'hw/sensor', 'hw/sh4', 'hw/sparc', 'hw/sparc64', 'hw/ssi', 'hw/timer', 'hw/tpm', + 'hw/uefi', 'hw/ufs', 'hw/usb', 'hw/vfio', + 'hw/vfio-user', 'hw/virtio', + 'hw/vmapple', 'hw/watchdog', 'hw/xen', 'hw/gpio', @@ -3412,6 +3733,7 @@ qom_ss = ss.source_set() system_ss = ss.source_set() specific_fuzz_ss = ss.source_set() specific_ss = ss.source_set() +rust_devices_ss = ss.source_set() stub_ss = ss.source_set() trace_ss = ss.source_set() user_ss = ss.source_set() @@ -3419,14 +3741,17 @@ util_ss = ss.source_set() # accel modules qtest_module_ss = ss.source_set() -tcg_module_ss = ss.source_set() modules = {} target_modules = {} +plugin_modules = [] hw_arch = {} target_arch = {} target_system_arch = {} target_user_arch = {} +hw_common_arch = {} +target_common_arch = {} +target_common_system_arch = {} # NOTE: the trace/ subdirectory needs the qapi_trace_events variable # that is filled in by qapi/. @@ -3448,22 +3773,21 @@ endif if enable_modules libmodulecommon = static_library('module-common', files('module-common.c') + genh, pic: true, c_args: '-DBUILD_DSO') - modulecommon = declare_dependency(link_whole: libmodulecommon, compile_args: '-DBUILD_DSO') + modulecommon = declare_dependency(objects: libmodulecommon.extract_all_objects(recursive: false), compile_args: '-DBUILD_DSO') endif qom_ss = qom_ss.apply({}) libqom = static_library('qom', qom_ss.sources() + genh, dependencies: [qom_ss.dependencies()], - name_suffix: 'fa', build_by_default: false) -qom = declare_dependency(link_whole: libqom) +qom = declare_dependency(objects: libqom.extract_all_objects(recursive: false), + dependencies: qom_ss.dependencies()) event_loop_base = files('event-loop-base.c') event_loop_base = static_library('event-loop-base', sources: event_loop_base + genh, - name_suffix: 'fa', build_by_default: false) -event_loop_base = declare_dependency(link_whole: event_loop_base, +event_loop_base = declare_dependency(objects: event_loop_base.extract_all_objects(recursive: false), dependencies: [qom]) stub_ss = stub_ss.apply({}) @@ -3474,9 +3798,13 @@ libqemuutil = static_library('qemuutil', build_by_default: false, sources: util_ss.sources() + stub_ss.sources() + genh, dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc]) +qemuutil_deps = [event_loop_base] +if host_os != 'windows' + qemuutil_deps += [rt] +endif qemuutil = declare_dependency(link_with: libqemuutil, sources: genh + version_res, - dependencies: [event_loop_base]) + dependencies: qemuutil_deps) if have_system or have_user decodetree = generator(find_program('scripts/decodetree.py'), @@ -3512,12 +3840,14 @@ if have_block 'blockdev-nbd.c', 'iothread.c', 'job-qmp.c', - ), gnutls) + )) # os-posix.c contains POSIX-specific functions used by qemu-storage-daemon, # os-win32.c does not if host_os == 'windows' system_ss.add(files('os-win32.c')) + elif host_os == 'emscripten' + blockdev_ss.add(files('os-wasm.c')) else blockdev_ss.add(files('os-posix.c')) endif @@ -3548,6 +3878,9 @@ endif common_ss.add(pagevary) specific_ss.add(files('page-target.c', 'page-vary-target.c')) +common_ss.add(files('target-info.c')) +specific_ss.add(files('target-info-stub.c')) + subdir('backends') subdir('disas') subdir('migration') @@ -3562,6 +3895,10 @@ subdir('accel') subdir('plugins') subdir('ebpf') +if 'CONFIG_TCG' in config_all_accel + subdir('contrib/plugins') +endif + common_user_inc = [] subdir('common-user') @@ -3573,11 +3910,7 @@ subdir('tests/qtest/libqos') subdir('tests/qtest/fuzz') # accel modules -tcg_real_module_ss = ss.source_set() -tcg_real_module_ss.add_all(when: 'CONFIG_TCG_MODULAR', if_true: tcg_module_ss) -specific_ss.add_all(when: 'CONFIG_TCG_BUILTIN', if_true: tcg_module_ss) -target_modules += { 'accel' : { 'qtest': qtest_module_ss, - 'tcg': tcg_real_module_ss }} +target_modules += { 'accel' : { 'qtest': qtest_module_ss }} ############################################## # Internal static_libraries and dependencies # @@ -3589,6 +3922,7 @@ modinfo_files = [] block_mods = [] system_mods = [] +emulator_modules = [] foreach d, list : modules if not (d == 'block' ? have_block : have_system) continue @@ -3596,25 +3930,27 @@ foreach d, list : modules foreach m, module_ss : list if enable_modules + module_ss.add(modulecommon) module_ss = module_ss.apply(config_all_devices, strict: false) sl = static_library(d + '-' + m, [genh, module_ss.sources()], - dependencies: [modulecommon, module_ss.dependencies()], pic: true) + dependencies: module_ss.dependencies(), pic: true) if d == 'block' block_mods += sl else system_mods += sl endif + emulator_modules += shared_module(sl.name(), + name_prefix: '', + objects: sl.extract_all_objects(recursive: false), + dependencies: module_ss.dependencies(), + install: true, + install_dir: qemu_moddir) if module_ss.sources() != [] - # FIXME: Should use sl.extract_all_objects(recursive: true) as - # input. Sources can be used multiple times but objects are - # unique when it comes to lookup in compile_commands.json. - # Depnds on a mesion version with - # https://github.com/mesonbuild/meson/pull/8900 modinfo_files += custom_target(d + '-' + m + '.modinfo', output: d + '-' + m + '.modinfo', - input: module_ss.sources() + genh, + input: sl.extract_all_objects(recursive: true), capture: true, - command: [modinfo_collect, module_ss.sources()]) + command: [modinfo_collect, '@INPUT@']) endif else if d == 'block' @@ -3629,6 +3965,7 @@ endforeach foreach d, list : target_modules foreach m, module_ss : list if enable_modules + module_ss.add(modulecommon) foreach target : target_dirs if target.endswith('-softmmu') config_target = config_target_mak[target] @@ -3641,17 +3978,22 @@ foreach d, list : target_modules module_name = d + '-' + m + '-' + config_target['TARGET_NAME'] sl = static_library(module_name, [genh, target_module_ss.sources()], - dependencies: [modulecommon, target_module_ss.dependencies()], + dependencies: target_module_ss.dependencies(), include_directories: target_inc, c_args: c_args, pic: true) system_mods += sl - # FIXME: Should use sl.extract_all_objects(recursive: true) too. + emulator_modules += shared_module(sl.name(), + name_prefix: '', + objects: sl.extract_all_objects(recursive: false), + dependencies: target_module_ss.dependencies(), + install: true, + install_dir: qemu_moddir) modinfo_files += custom_target(module_name + '.modinfo', output: module_name + '.modinfo', - input: target_module_ss.sources() + genh, + input: sl.extract_all_objects(recursive: true), capture: true, - command: [modinfo_collect, '--target', target, target_module_ss.sources()]) + command: [modinfo_collect, '--target', target, '@INPUT@']) endif endif endforeach @@ -3679,6 +4021,10 @@ if enable_modules hw_arch[arch].add(modinfo_dep) endif endforeach + + if emulator_modules.length() > 0 + alias_target('modules', emulator_modules) + endif endif nm = find_program('nm') @@ -3695,101 +4041,92 @@ qemu_syms = custom_target('qemu.syms', output: 'qemu.syms', authz_ss = authz_ss.apply({}) libauthz = static_library('authz', authz_ss.sources() + genh, dependencies: [authz_ss.dependencies()], - name_suffix: 'fa', build_by_default: false) -authz = declare_dependency(link_whole: libauthz, - dependencies: qom) +authz = declare_dependency(objects: libauthz.extract_all_objects(recursive: false), + dependencies: [authz_ss.dependencies(), qom]) crypto_ss = crypto_ss.apply({}) libcrypto = static_library('crypto', crypto_ss.sources() + genh, dependencies: [crypto_ss.dependencies()], - name_suffix: 'fa', build_by_default: false) -crypto = declare_dependency(link_whole: libcrypto, - dependencies: [authz, qom]) +crypto = declare_dependency(objects: libcrypto.extract_all_objects(recursive: false), + dependencies: [crypto_ss.dependencies(), authz, qom]) io_ss = io_ss.apply({}) libio = static_library('io', io_ss.sources() + genh, dependencies: [io_ss.dependencies()], link_with: libqemuutil, - name_suffix: 'fa', build_by_default: false) -io = declare_dependency(link_whole: libio, dependencies: [crypto, qom]) +io = declare_dependency(objects: libio.extract_all_objects(recursive: false), + dependencies: [io_ss.dependencies(), crypto, qom]) libmigration = static_library('migration', sources: migration_files + genh, - name_suffix: 'fa', build_by_default: false) -migration = declare_dependency(link_with: libmigration, +migration = declare_dependency(objects: libmigration.extract_all_objects(recursive: false), dependencies: [qom, io]) system_ss.add(migration) block_ss = block_ss.apply({}) libblock = static_library('block', block_ss.sources() + genh, dependencies: block_ss.dependencies(), - link_depends: block_syms, - name_suffix: 'fa', build_by_default: false) -block = declare_dependency(link_whole: [libblock], - link_args: '@block.syms', - dependencies: [crypto, io]) +block = declare_dependency(objects: libblock.extract_all_objects(recursive: false), + dependencies: [block_ss.dependencies(), crypto, io]) blockdev_ss = blockdev_ss.apply({}) libblockdev = static_library('blockdev', blockdev_ss.sources() + genh, dependencies: blockdev_ss.dependencies(), - name_suffix: 'fa', build_by_default: false) -blockdev = declare_dependency(link_whole: [libblockdev], - dependencies: [block, event_loop_base]) +blockdev = declare_dependency(objects: libblockdev.extract_all_objects(recursive: false), + dependencies: [blockdev_ss.dependencies(), block, event_loop_base]) qmp_ss = qmp_ss.apply({}) libqmp = static_library('qmp', qmp_ss.sources() + genh, dependencies: qmp_ss.dependencies(), - name_suffix: 'fa', build_by_default: false) -qmp = declare_dependency(link_whole: [libqmp]) +qmp = declare_dependency(objects: libqmp.extract_all_objects(recursive: false), + dependencies: qmp_ss.dependencies()) libchardev = static_library('chardev', chardev_ss.sources() + genh, - name_suffix: 'fa', dependencies: chardev_ss.dependencies(), build_by_default: false) -chardev = declare_dependency(link_whole: libchardev) +chardev = declare_dependency(objects: libchardev.extract_all_objects(recursive: false), + dependencies: [chardev_ss.dependencies(), io]) hwcore_ss = hwcore_ss.apply({}) libhwcore = static_library('hwcore', sources: hwcore_ss.sources() + genh, - name_suffix: 'fa', build_by_default: false) -hwcore = declare_dependency(link_whole: libhwcore) +hwcore = declare_dependency(objects: libhwcore.extract_all_objects(recursive: false)) common_ss.add(hwcore) ########### # Targets # ########### -emulator_modules = [] -foreach m : block_mods + system_mods - emulator_modules += shared_module(m.name(), - build_by_default: true, - name_prefix: '', - link_whole: m, - install: true, - install_dir: qemu_moddir) -endforeach -if emulator_modules.length() > 0 - alias_target('modules', emulator_modules) -endif - system_ss.add(authz, blockdev, chardev, crypto, io, qmp) common_ss.add(qom, qemuutil) -common_ss.add_all(when: 'CONFIG_SYSTEM_ONLY', if_true: [system_ss]) -common_ss.add_all(when: 'CONFIG_USER_ONLY', if_true: user_ss) +libuser = static_library('user', + user_ss.all_sources() + genh, + c_args: ['-DCONFIG_USER_ONLY', + '-DCOMPILING_SYSTEM_VS_USER'], + include_directories: common_user_inc, + dependencies: user_ss.all_dependencies(), + build_by_default: false) + +libsystem = static_library('system', + system_ss.all_sources() + genh, + c_args: ['-DCONFIG_SOFTMMU', + '-DCOMPILING_SYSTEM_VS_USER'], + dependencies: system_ss.all_dependencies(), + build_by_default: false) # Note that this library is never used directly (only through extract_objects) # and is not built by default; therefore, source files not used by the build @@ -3797,12 +4134,114 @@ common_ss.add_all(when: 'CONFIG_USER_ONLY', if_true: user_ss) common_all = static_library('common', build_by_default: false, sources: common_ss.all_sources() + genh, - include_directories: common_user_inc, implicit_include_directories: false, - dependencies: common_ss.all_dependencies(), - name_suffix: 'fa') + dependencies: common_ss.all_dependencies()) + +# construct common libraries per base architecture +target_common_arch_libs = {} +target_common_system_arch_libs = {} +foreach target_base_arch, config_base_arch : config_base_arch_mak + target_inc = [include_directories('target' / target_base_arch)] + inc = [common_user_inc + target_inc] + + target_common = common_ss.apply(config_base_arch, strict: false) + target_system = system_ss.apply(config_base_arch, strict: false) + target_user = user_ss.apply(config_base_arch, strict: false) + common_deps = [] + system_deps = [] + user_deps = [] + foreach dep: target_common.dependencies() + common_deps += dep.partial_dependency(compile_args: true, includes: true) + endforeach + foreach dep: target_system.dependencies() + system_deps += dep.partial_dependency(compile_args: true, includes: true) + endforeach + foreach dep: target_user.dependencies() + user_deps += dep.partial_dependency(compile_args: true, includes: true) + endforeach + + # prevent common code to access cpu compile time definition, + # but still allow access to cpu.h + target_c_args = ['-DCPU_DEFS_H'] + target_system_c_args = target_c_args + ['-DCOMPILING_SYSTEM_VS_USER', '-DCONFIG_SOFTMMU'] + + if target_base_arch in target_common_arch + src = target_common_arch[target_base_arch] + lib = static_library( + 'common_' + target_base_arch, + build_by_default: false, + sources: src.all_sources() + genh, + include_directories: inc, + c_args: target_c_args, + dependencies: src.all_dependencies() + common_deps + + system_deps + user_deps) + target_common_arch_libs += {target_base_arch: lib} + endif + + # merge hw_common_arch in target_common_system_arch + if target_base_arch in hw_common_arch + hw_src = hw_common_arch[target_base_arch] + if target_base_arch in target_common_system_arch + target_common_system_arch[target_base_arch].add_all(hw_src) + else + target_common_system_arch += {target_base_arch: hw_src} + endif + endif + + if target_base_arch in target_common_system_arch + src = target_common_system_arch[target_base_arch] + lib = static_library( + 'system_' + target_base_arch, + build_by_default: false, + sources: src.all_sources() + genh, + include_directories: inc, + c_args: target_system_c_args, + dependencies: src.all_dependencies() + common_deps + system_deps) + target_common_system_arch_libs += {target_base_arch: lib} + endif +endforeach + +if have_rust + bindings_incdir = include_directories('.', 'include') + # We would like to use --generate-cstr, but it is only available + # starting with bindgen 0.66.0. The oldest supported versions + # is 0.60.x (Debian 12 has 0.60.1) which introduces --allowlist-file. + bindgen_args_common = [ + '--disable-header-comment', + '--raw-line', '// @generated', + '--ctypes-prefix', 'std::os::raw', + '--generate-block', + '--impl-debug', + '--no-doc-comments', + '--with-derive-default', + '--no-layout-tests', + '--no-prepend-enum-name', + '--allowlist-file', meson.project_source_root() + '/include/.*', + '--allowlist-file', meson.project_source_root() + '/.*', + '--allowlist-file', meson.project_build_root() + '/.*' + ] + if not rustfmt.found() + if bindgen.version().version_compare('<0.65.0') + bindgen_args_common += ['--no-rustfmt-bindings'] + else + bindgen_args_common += ['--formatter', 'none'] + endif + endif + if bindgen.version().version_compare('>=0.66.0') + bindgen_args_common += ['--rust-target', '1.59'] + endif + if bindgen.version().version_compare('<0.61.0') + # default in 0.61+ + bindgen_args_common += ['--size_t-is-usize'] + else + bindgen_args_common += ['--merge-extern-blocks'] + endif + subdir('rust') +endif + feature_to_c = find_program('scripts/feature_to_c.py') +rust_root_crate = find_program('scripts/rust/rust_root_crate.sh') if host_os == 'darwin' entitlement = find_program('scripts/entitlement.sh') @@ -3818,7 +4257,7 @@ foreach target : target_dirs arch_deps = [] c_args = ['-DCOMPILING_PER_TARGET', '-DCONFIG_TARGET="@0@-config-target.h"'.format(target), - '-DCONFIG_DEVICES="@0@-config-devices.h"'.format(target)] + ] link_args = emulator_link_args target_inc = [include_directories('target' / config_target['TARGET_BASE_ARCH'])] @@ -3838,6 +4277,7 @@ foreach target : target_dirs arch_deps += hw.dependencies() endif + c_args += ['-DCONFIG_DEVICES="@0@-config-devices.h"'.format(target)] arch_srcs += config_devices_h[target] link_args += ['@block.syms', '@qemu.syms'] else @@ -3888,13 +4328,57 @@ foreach target : target_dirs arch_deps += t.dependencies() target_common = common_ss.apply(config_target, strict: false) - objects = common_all.extract_objects(target_common.sources()) + objects = [common_all.extract_objects(target_common.sources())] arch_deps += target_common.dependencies() + if target_base_arch in target_common_arch_libs + src = target_common_arch[target_base_arch].apply(config_target, strict: false) + lib = target_common_arch_libs[target_base_arch] + objects += lib.extract_objects(src.sources()) + arch_deps += src.dependencies() + endif + if target_type == 'system' + src = system_ss.apply(config_target, strict: false) + objects += libsystem.extract_objects(src.sources()) + arch_deps += src.dependencies() + endif + if target_type == 'user' + src = user_ss.apply(config_target, strict: false) + objects += libuser.extract_objects(src.sources()) + arch_deps += src.dependencies() + endif + if target_type == 'system' and target_base_arch in target_common_system_arch_libs + src = target_common_system_arch[target_base_arch].apply(config_target, strict: false) + lib = target_common_system_arch_libs[target_base_arch] + objects += lib.extract_objects(src.sources()) + arch_deps += src.dependencies() + endif target_specific = specific_ss.apply(config_target, strict: false) arch_srcs += target_specific.sources() arch_deps += target_specific.dependencies() + if have_rust and target_type == 'system' + target_rust = rust_devices_ss.apply(config_target, strict: false) + crates = [] + foreach dep : target_rust.dependencies() + crates += dep.get_variable('crate') + endforeach + if crates.length() > 0 + rlib_rs = custom_target('rust_' + target.underscorify() + '.rs', + output: 'rust_' + target.underscorify() + '.rs', + command: [rust_root_crate, crates], + capture: true, + build_by_default: true, + build_always_stale: true) + rlib = static_library('rust_' + target.underscorify(), + structured_sources([], {'.': rlib_rs}), + dependencies: target_rust.dependencies(), + override_options: ['rust_std=2021', 'build.rust_std=2021'], + rust_abi: 'c') + arch_deps += declare_dependency(link_whole: [rlib]) + endif + endif + # allow using headers from the dependencies but do not include the sources, # because this emulator only needs those in "objects". For external # dependencies, the full dependency is included below in the executable. @@ -3909,22 +4393,21 @@ foreach target : target_dirs objects: objects, include_directories: target_inc, c_args: c_args, - build_by_default: false, - name_suffix: 'fa') + build_by_default: false) if target.endswith('-softmmu') execs = [{ 'name': 'qemu-system-' + target_name, 'win_subsystem': 'console', 'sources': files('system/main.c'), - 'dependencies': [] + 'dependencies': [sdl] }] if host_os == 'windows' and (sdl.found() or gtk.found()) execs += [{ 'name': 'qemu-system-' + target_name + 'w', 'win_subsystem': 'windows', 'sources': files('system/main.c'), - 'dependencies': [] + 'dependencies': [sdl] }] endif if get_option('fuzzing') @@ -4016,11 +4499,14 @@ endif if have_tools qemu_img = executable('qemu-img', [files('qemu-img.c'), hxdep], + link_args: '@block.syms', link_depends: block_syms, dependencies: [authz, block, crypto, io, qom, qemuutil], install: true) qemu_io = executable('qemu-io', files('qemu-io.c'), + link_args: '@block.syms', link_depends: block_syms, dependencies: [block, qemuutil], install: true) qemu_nbd = executable('qemu-nbd', files('qemu-nbd.c'), - dependencies: [blockdev, qemuutil, gnutls, selinux], + link_args: '@block.syms', link_depends: block_syms, + dependencies: [blockdev, qemuutil, selinux], install: true) subdir('storage-daemon') @@ -4035,7 +4521,7 @@ if have_tools subdir('contrib/elf2dmp') executable('qemu-edid', files('qemu-edid.c', 'hw/display/edid-generate.c'), - dependencies: qemuutil, + dependencies: [qemuutil, rt], install: true) if have_vhost_user @@ -4055,6 +4541,13 @@ if have_tools dependencies: [authz, crypto, io, qom, qemuutil, libcap_ng, mpathpersist], install: true) + + if cpu in ['x86', 'x86_64'] + executable('qemu-vmsr-helper', files('tools/i386/qemu-vmsr-helper.c'), + dependencies: [authz, crypto, io, qom, qemuutil, + libcap_ng, mpathpersist], + install: true) + endif endif if have_ivshmem @@ -4093,7 +4586,11 @@ subdir('scripts') subdir('tools') subdir('pc-bios') subdir('docs') -subdir('tests') +# Tests are disabled on emscripten because they rely on host features that aren't +# supported by emscripten (e.g. fork and unix socket). +if host_os != 'emscripten' + subdir('tests') +endif if gtk.found() subdir('po') endif @@ -4196,7 +4693,6 @@ summary_info += {'Trace backends': ','.join(get_option('trace_backends'))} if 'simple' in get_option('trace_backends') summary_info += {'Trace output file': get_option('trace_file') + '-<pid>'} endif -summary_info += {'D-Bus display': dbus_display} summary_info += {'QOM debugging': get_option('qom_cast_debug')} summary_info += {'Relocatable install': get_option('relocatable')} summary_info += {'vhost-kernel support': have_vhost_kernel} @@ -4224,6 +4720,15 @@ if 'objc' in all_languages else summary_info += {'Objective-C compiler': false} endif +summary_info += {'Rust support': have_rust} +if have_rust + summary_info += {'Rust target': config_host['RUST_TARGET_TRIPLE']} + summary_info += {'rustc': ' '.join(rustc.cmd_array())} + summary_info += {'rustc version': rustc.version()} + summary_info += {'rustdoc': rustdoc} + summary_info += {'bindgen': bindgen.full_path()} + summary_info += {'bindgen version': bindgen.version()} +endif option_cflags = (get_option('debug') ? ['-g'] : []) if get_option('optimization') != 'plain' option_cflags += ['-O' + get_option('optimization')] @@ -4258,7 +4763,6 @@ summary_info += {'mutex debugging': get_option('debug_mutex')} summary_info += {'memory allocator': get_option('malloc')} summary_info += {'avx2 optimization': config_host_data.get('CONFIG_AVX2_OPT')} summary_info += {'avx512bw optimization': config_host_data.get('CONFIG_AVX512BW_OPT')} -summary_info += {'avx512f optimization': config_host_data.get('CONFIG_AVX512F_OPT')} summary_info += {'gcov': get_option('b_coverage')} summary_info += {'thread sanitizer': get_option('tsan')} summary_info += {'CFI support': get_option('cfi')} @@ -4330,7 +4834,6 @@ if have_block summary_info += {'Block whitelist (ro)': get_option('block_drv_ro_whitelist')} summary_info += {'Use block whitelist in tools': get_option('block_drv_whitelist_in_tools')} summary_info += {'VirtFS (9P) support': have_virtfs} - summary_info += {'VirtFS (9P) Proxy Helper support (deprecated)': have_virtfs_proxy_helper} summary_info += {'replication support': config_host_data.get('CONFIG_REPLICATION')} summary_info += {'bochs support': get_option('bochs').allowed()} summary_info += {'cloop support': get_option('cloop').allowed()} @@ -4361,6 +4864,7 @@ if nettle.found() summary_info += {' XTS': xts != 'private'} endif summary_info += {'SM4 ALG support': crypto_sm4} +summary_info += {'SM3 ALG support': crypto_sm3} summary_info += {'AF_ALG support': have_afalg} summary_info += {'rng-none': get_option('rng_none')} summary_info += {'Linux keyring': have_keyring} @@ -4372,6 +4876,7 @@ summary_info = {} if host_os == 'darwin' summary_info += {'Cocoa support': cocoa} endif +summary_info += {'D-Bus display': dbus_display} summary_info += {'SDL support': sdl} summary_info += {'SDL image support': sdl_image} summary_info += {'GTK support': gtk} @@ -4468,10 +4973,12 @@ summary_info += {'lzfse support': liblzfse} summary_info += {'zstd support': zstd} summary_info += {'Query Processing Library support': qpl} summary_info += {'UADK Library support': uadk} +summary_info += {'qatzip support': qatzip} summary_info += {'NUMA host support': numa} summary_info += {'capstone': capstone} summary_info += {'libpmem support': libpmem} summary_info += {'libdaxctl support': libdaxctl} +summary_info += {'libcbor support': libcbor} summary_info += {'libudev': libudev} # Dummy dependency, keep .found() summary_info += {'FUSE lseek': fuse_lseek.found()} @@ -4480,6 +4987,10 @@ summary_info += {'libdw': libdw} if host_os == 'freebsd' summary_info += {'libinotify-kqueue': inotify} endif +if host_os == 'darwin' + summary_info += {'ParavirtualizedGraphics support': pvg} +endif +summary_info += {'valgrind': valgrind} summary(summary_info, bool_yn: true, section: 'Dependencies') if host_arch == 'unknown' @@ -4491,11 +5002,17 @@ if host_arch == 'unknown' message('compile or work on this host CPU. You can help by volunteering') message('to maintain it and providing a build host for our continuous') message('integration setup.') - if get_option('tcg').allowed() and target_dirs.length() > 0 + if have_tcg message() message('configure has succeeded and you can continue to build, but') message('QEMU will use a slow interpreter to emulate the target CPU.') endif +elif host_long_bits < 64 + message() + warning('DEPRECATED HOST CPU') + message() + message('Support for 32-bit CPU host architecture ' + cpu + ' is going') + message('to be dropped in a future QEMU release.') endif if not supported_oses.contains(host_os) |