From b1b4aec6adc3c9f919b21dbb8b8c65544985c187 Mon Sep 17 00:00:00 2001 From: Alexey Shabalin Date: Fri, 27 Feb 2026 19:10:45 +0300 Subject: [PATCH] Introduce meson build files Co-authored-by: OpenAI Codex --- meson.build | 683 ++++++++++++++++++++++++++++++++++++++++++++++ meson_options.txt | 10 + 2 files changed, 693 insertions(+) create mode 100644 meson.build create mode 100644 meson_options.txt diff --git a/meson.build b/meson.build new file mode 100644 index 00000000..de90fa37 --- /dev/null +++ b/meson.build @@ -0,0 +1,683 @@ +project( + 'vitastor', + ['cpp', 'c'], + version: '3.0.8', + default_options: [ + 'cpp_std=gnu++17', + 'buildtype=debugoptimized', + ], +) + +cc = meson.get_compiler('c') +cpp = meson.get_compiler('cpp') +pkgconfig = import('pkgconfig') +fs = import('fs') + +with_qemu = get_option('with_qemu') +with_fio = get_option('with_fio') +fio_srcdir = get_option('fio_srcdir') +qemu_srcdir = get_option('qemu_srcdir') +qemu_builddir = get_option('qemu_builddir') +with_asan = get_option('with_asan') +with_system_liburing = get_option('with_system_liburing') +enable_coverage = get_option('enable_coverage') +build_tests_opt = get_option('build_tests') +qemu_plugindir = get_option('qemu_plugindir') + +common_args = [ + '-DVITASTOR_VERSION="' + meson.project_version() + '"', + '-D_GNU_SOURCE', + '-D_LARGEFILE64_SOURCE', + '-D_FILE_OFFSET_BITS=64', + '-Wall', + '-Wno-sign-compare', + '-Wno-comment', + '-Wno-parentheses', + '-Wno-pointer-arith', + '-fdiagnostics-color=always', + '-fvisibility=hidden', + '-fno-omit-frame-pointer', +] +add_project_arguments(common_args, language: ['c', 'cpp']) + +if with_asan + add_project_arguments(['-fsanitize=address'], language: ['c', 'cpp']) + add_project_link_arguments(['-fsanitize=address'], language: ['c', 'cpp']) +endif + +# enable_coverage is a compatibility alias for Meson's b_coverage option +if enable_coverage + set_option('b_coverage', true) +endif + +have_nbd_netlink = cc.has_header('linux/nbd-netlink.h') + +threads_dep = dependency('threads') +ibverbs_dep = dependency('libibverbs', required: false) +if ibverbs_dep.found() + add_project_arguments(['-DWITH_RDMA'], language: ['c', 'cpp']) +endif + +isal_dep = dependency('libisal', required: false) +if isal_dep.found() + add_project_arguments(['-DWITH_ISAL'], language: ['c', 'cpp']) +endif + +rdmacm_dep = dependency('librdmacm', required: false) +if rdmacm_dep.found() + add_project_arguments(['-DWITH_RDMACM'], language: ['c', 'cpp']) +endif + +glib_dep = dependency('glib-2.0', required: with_qemu) +jerasure_dep = dependency('Jerasure', required: false) +if not jerasure_dep.found() + jerasure_dep = cpp.find_library('Jerasure', required: true) +endif +gf_complete_dep = dependency('gf_complete', required: false) +if not gf_complete_dep.found() + gf_complete_dep = cpp.find_library('gf_complete', required: true) +endif +have_jerasure_ec = cc.has_function( + 'ec_encode_data', + dependencies: [jerasure_dep, gf_complete_dep], +) + +tcmalloc_dep = dependency('tcmalloc_minimal', required: false) +if not tcmalloc_dep.found() + tcmalloc_dep = cpp.find_library('tcmalloc_minimal', required: true) +endif + +nl3_genl_dep = dependency('libnl-genl-3.0', required: true) +nl3_dep = dependency('libnl-3.0', required: true) + +liburing_inc = [] +if with_system_liburing + liburing_dep = dependency('liburing', required: true, version: '>=2.10') +else + liburing_inc = include_directories('src/liburing/include') + liburing_lib = library( + 'uring', + [ + 'src/liburing/queue.c', + 'src/liburing/register.c', + 'src/liburing/setup.c', + 'src/liburing/syscall.c', + 'src/liburing/version.c', + ], + include_directories: liburing_inc, + c_args: ['-D_GNU_SOURCE', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64'], + pic: true, + install: false, + ) + liburing_dep = declare_dependency( + link_with: liburing_lib, + include_directories: liburing_inc, + ) +endif + +fio_inc = [] +if with_fio + fio_srcdir_abs = fio_srcdir + if fio_srcdir != '' and not fs.is_absolute(fio_srcdir) + fio_srcdir_abs = join_paths(meson.current_source_dir(), fio_srcdir) + endif + if fio_srcdir != '' and fs.exists(fio_srcdir_abs) + fio_link = join_paths(meson.current_build_dir(), 'fio') + run_command('ln', '-sfn', fio_srcdir_abs, fio_link, check: true) + fio_inc = [include_directories('.')] + elif not cc.has_header('fio/arch/arch.h') + error('with_fio=true requires fio headers; set -Dfio_srcdir=PATH or install fio-devel') + endif +endif + +inc = include_directories( + 'src', + 'src/blockstore', + 'src/cmd', + 'src/client', + 'src/disk_tool', + 'src/kv', + 'src/nfs', + 'src/osd', + 'src/test', + 'src/util', + '/usr/include/jerasure', +) + +json11_inc = include_directories('json11') +json11_lib = static_library( + 'json11', + ['json11/json11.cpp'], + include_directories: json11_inc, + pic: true, + install: false, +) +json11_dep = declare_dependency( + link_with: json11_lib, + include_directories: json11_inc, +) + +common_json_deps = [json11_dep] + +vitastor_common_sources = [ + 'src/util/epoll_manager.cpp', + 'src/client/etcd_state_client.cpp', + 'src/client/messenger.cpp', + 'src/util/addr_util.cpp', + 'src/client/msgr_stop.cpp', + 'src/client/msgr_op.cpp', + 'src/client/msgr_send.cpp', + 'src/client/msgr_receive.cpp', + 'src/util/ringloop.cpp', + 'src/client/http_client.cpp', + 'src/client/osd_ops.cpp', + 'src/client/pg_states.cpp', + 'src/util/timerfd_manager.cpp', + 'src/util/str_util.cpp', + 'src/util/json_util.cpp', +] +if ibverbs_dep.found() + vitastor_common_sources += 'src/client/msgr_rdma.cpp' +endif +if rdmacm_dep.found() + vitastor_common_sources += 'src/client/msgr_rdmacm.cpp' +endif + +vitastor_common = static_library( + 'vitastor_common', + vitastor_common_sources, + include_directories: inc, + dependencies: [threads_dep, ibverbs_dep, rdmacm_dep] + common_json_deps, + pic: true, + install: false, +) +vitastor_common_dep = declare_dependency( + link_with: vitastor_common, + include_directories: inc, + dependencies: [threads_dep, ibverbs_dep, rdmacm_dep] + common_json_deps, +) + +vitastor_blk = static_library( + 'vitastor_blk', + [ + 'src/util/allocator.cpp', + 'src/util/crc32c.c', + 'src/util/ringloop.cpp', + 'src/blockstore/multilist.cpp', + 'src/blockstore/blockstore_heap.cpp', + 'src/blockstore/blockstore_disk.cpp', + 'src/blockstore/blockstore.cpp', + 'src/blockstore/blockstore_impl.cpp', + 'src/blockstore/blockstore_init.cpp', + 'src/blockstore/blockstore_open.cpp', + 'src/blockstore/blockstore_flush.cpp', + 'src/blockstore/blockstore_read.cpp', + 'src/blockstore/blockstore_stable.cpp', + 'src/blockstore/blockstore_sync.cpp', + 'src/blockstore/blockstore_write.cpp', + 'src/blockstore/v1/flush.cpp', + 'src/blockstore/v1/impl.cpp', + 'src/blockstore/v1/init.cpp', + 'src/blockstore/v1/journal.cpp', + 'src/blockstore/v1/open.cpp', + 'src/blockstore/v1/read.cpp', + 'src/blockstore/v1/rollback.cpp', + 'src/blockstore/v1/stable.cpp', + 'src/blockstore/v1/sync.cpp', + 'src/blockstore/v1/write.cpp', + ], + include_directories: inc, + dependencies: [liburing_dep, isal_dep], + link_with: vitastor_common, + pic: true, + install: false, +) + +fio_vitastor_blk = [] +if with_fio + fio_vitastor_blk = shared_library( + 'fio_vitastor_blk', + [ + 'src/blockstore/fio_engine.cpp', + ], + include_directories: [inc] + fio_inc, + link_with: vitastor_blk, + dependencies: common_json_deps, + override_options: ['b_lundef=false'], + install: true, + ) +endif + +vitastor_cli = static_library( + 'vitastor_cli', + [ + 'src/cmd/cli_common.cpp', + 'src/cmd/cli_alloc_osd.cpp', + 'src/cmd/cli_status.cpp', + 'src/cmd/cli_describe.cpp', + 'src/cmd/cli_fix.cpp', + 'src/cmd/cli_ls.cpp', + 'src/cmd/cli_create.cpp', + 'src/cmd/cli_dd.cpp', + 'src/cmd/cli_modify.cpp', + 'src/cmd/cli_modify_osd.cpp', + 'src/cmd/cli_osd_tree.cpp', + 'src/cmd/cli_pg_ls.cpp', + 'src/cmd/cli_flatten.cpp', + 'src/cmd/cli_merge.cpp', + 'src/cmd/cli_rm_data.cpp', + 'src/cmd/cli_rm_wildcard.cpp', + 'src/cmd/cli_rm.cpp', + 'src/cmd/cli_rm_osd.cpp', + 'src/cmd/cli_pool_cfg.cpp', + 'src/cmd/cli_pool_create.cpp', + 'src/cmd/cli_pool_ls.cpp', + 'src/cmd/cli_pool_modify.cpp', + 'src/cmd/cli_pool_rm.cpp', + ], + include_directories: inc, + pic: true, + install: false, +) + +vitastor_client = shared_library( + 'vitastor_client', + [ + 'src/client/cluster_client.cpp', + 'src/client/cluster_client_list.cpp', + 'src/client/cluster_client_wb.cpp', + 'src/client/vitastor_c.cpp', + ], + include_directories: inc, + link_with: [vitastor_common, vitastor_cli], + dependencies: [liburing_dep, ibverbs_dep, rdmacm_dep] + common_json_deps, + version: meson.project_version(), + soversion: '0', + install: true, +) + +pkgconfig.generate( + name: 'Vitastor', + description: 'Vitastor client library', + version: meson.project_version(), + libraries: vitastor_client, + subdirs: ['client'], + filebase: 'vitastor', +) + +if with_fio + fio_vitastor = shared_library( + 'fio_vitastor', + ['src/client/fio_cluster.cpp'], + include_directories: [inc] + fio_inc, + link_with: vitastor_client, + override_options: ['b_lundef=false'], + install: true, + ) + + fio_vitastor_sec = shared_library( + 'fio_vitastor_sec', + [ + 'src/client/fio_sec_osd.cpp', + 'src/util/rw_blocking.cpp', + 'src/util/addr_util.cpp', + ], + include_directories: inc, + dependencies: [tcmalloc_dep], + override_options: ['b_lundef=false'], + install: true, + ) +endif + +vitastor_nbd_deps = [nl3_dep, nl3_genl_dep] +vitastor_nbd_args = [] +if have_nbd_netlink and nl3_dep.found() + vitastor_nbd_args += '-DHAVE_NBD_NETLINK_H' +endif +vitastor_nbd = executable( + 'vitastor-nbd', + ['src/client/nbd_proxy.cpp'], + include_directories: inc, + link_with: vitastor_client, + dependencies: vitastor_nbd_deps + [liburing_dep] + common_json_deps, + c_args: vitastor_nbd_args, + cpp_args: vitastor_nbd_args, + install: true, +) + +vitastor_ublk = executable( + 'vitastor-ublk', + ['src/client/ublk_server.cpp'], + include_directories: inc, + link_with: vitastor_client, + dependencies: [liburing_dep] + common_json_deps, + install: true, +) + +if with_qemu + if qemu_srcdir == '' or qemu_builddir == '' or not fs.exists(qemu_srcdir) or not fs.exists(qemu_builddir) + error('with_qemu=true requires QEMU source and build dirs. Set -Dqemu_srcdir=PATH and -Dqemu_builddir=PATH') + endif + qemu_inc = [include_directories(join_paths(qemu_srcdir, 'include'))] + if fs.exists(qemu_builddir) + qemu_inc += include_directories(qemu_builddir) + endif + if fs.exists(join_paths(qemu_builddir, 'include')) + qemu_inc += include_directories(join_paths(qemu_builddir, 'include')) + endif + if fs.exists(join_paths(qemu_builddir, 'qemu')) + qemu_inc += include_directories(join_paths(qemu_builddir, 'qemu')) + endif + qemu_vitastor = shared_library( + 'block-vitastor', + ['src/client/qemu_driver.c'], + include_directories: [inc] + qemu_inc, + link_with: vitastor_client, + dependencies: [glib_dep], + c_args: ['-DVITASTOR_SOURCE_TREE'], + override_options: ['b_lundef=false'], + name_prefix: '', + install: true, + install_dir: join_paths(get_option('libdir'), qemu_plugindir), + ) +endif + +test_cluster_client = executable( + 'test_cluster_client', + [ + 'src/test/test_cluster_client.cpp', + 'src/client/pg_states.cpp', + 'src/client/osd_ops.cpp', + 'src/client/cluster_client.cpp', + 'src/client/cluster_client_list.cpp', + 'src/client/cluster_client_wb.cpp', + 'src/client/msgr_op.cpp', + 'src/client/msgr_stop.cpp', + 'src/test/mock/messenger.cpp', + 'src/client/etcd_state_client.cpp', + 'src/util/timerfd_manager.cpp', + 'src/util/addr_util.cpp', + 'src/util/str_util.cpp', + 'src/util/json_util.cpp', + ], + include_directories: [inc, include_directories('src/test/mock')], + dependencies: [threads_dep, liburing_dep] + common_json_deps, + build_by_default: false, + cpp_args: ['-D__MOCK__'], +) + +vitastor_disk = executable( + 'vitastor-disk', + [ + 'src/disk_tool/disk_tool.cpp', + 'src/disk_tool/disk_simple_offsets.cpp', + 'src/disk_tool/disk_tool_discard.cpp', + 'src/disk_tool/disk_tool_journal.cpp', + 'src/disk_tool/disk_tool_meta.cpp', + 'src/disk_tool/disk_tool_prepare.cpp', + 'src/disk_tool/disk_tool_resize.cpp', + 'src/disk_tool/disk_tool_resize_auto.cpp', + 'src/disk_tool/disk_tool_udev.cpp', + 'src/disk_tool/disk_tool_utils.cpp', + 'src/disk_tool/disk_tool_upgrade.cpp', + 'src/util/crc32c.c', + 'src/util/str_util.cpp', + 'src/util/json_util.cpp', + 'src/util/rw_blocking.cpp', + 'src/util/allocator.cpp', + 'src/util/ringloop.cpp', + 'src/blockstore/blockstore_disk.cpp', + 'src/blockstore/blockstore_heap.cpp', + 'src/blockstore/multilist.cpp', + ], + include_directories: inc, + dependencies: [tcmalloc_dep, liburing_dep, isal_dep] + common_json_deps, + install: true, +) + +vitastor_cli_exe = executable( + 'vitastor-cli', + ['src/cmd/cli.cpp'], + include_directories: inc, + link_with: [vitastor_client, vitastor_cli], + dependencies: [liburing_dep] + common_json_deps, + install: true, +) + +vitastor_kv = shared_library( + 'vitastor_kv', + ['src/kv/kv_db.cpp'], + include_directories: inc, + link_with: vitastor_client, + dependencies: common_json_deps, + version: meson.project_version(), + soversion: '0', + install: true, +) + +vitastor_kv_cli = executable( + 'vitastor-kv', + ['src/kv/kv_cli.cpp'], + include_directories: inc, + link_with: [vitastor_kv, vitastor_common, vitastor_client], + dependencies: [liburing_dep] + common_json_deps, + install: true, +) + +vitastor_kv_stress = executable( + 'vitastor-kv-stress', + ['src/kv/kv_stress.cpp'], + include_directories: inc, + link_with: [vitastor_kv, vitastor_common, vitastor_client], + dependencies: [liburing_dep] + common_json_deps, + install: true, +) + +vitastor_osd = executable( + 'vitastor-osd', + [ + 'src/osd/osd_main.cpp', + 'src/osd/osd.cpp', + 'src/osd/osd_secondary.cpp', + 'src/osd/osd_peering.cpp', + 'src/osd/osd_flush.cpp', + 'src/osd/osd_peering_pg.cpp', + 'src/osd/osd_primary.cpp', + 'src/osd/osd_primary_chain.cpp', + 'src/osd/osd_primary_sync.cpp', + 'src/osd/osd_primary_write.cpp', + 'src/osd/osd_primary_subops.cpp', + 'src/osd/osd_cluster.cpp', + 'src/osd/osd_rmw.cpp', + 'src/osd/osd_scrub.cpp', + 'src/osd/osd_primary_describe.cpp', + ], + include_directories: inc, + link_with: [vitastor_common, vitastor_blk], + dependencies: [jerasure_dep, gf_complete_dep, isal_dep, ibverbs_dep, rdmacm_dep] + common_json_deps, + install: true, +) + +osd_rmw_test = executable( + 'osd_rmw_test', + ['src/osd/osd_rmw_test.cpp', 'src/util/allocator.cpp'], + include_directories: inc, + dependencies: [jerasure_dep, gf_complete_dep, isal_dep, tcmalloc_dep], + build_by_default: false, +) +osd_rmw_test_je = [] +if isal_dep.found() and have_jerasure_ec + osd_rmw_test_je = executable( + 'osd_rmw_test_je', + ['src/osd/osd_rmw_test.cpp', 'src/util/allocator.cpp'], + include_directories: inc, + dependencies: [jerasure_dep, gf_complete_dep, tcmalloc_dep], + build_by_default: false, + override_options: ['cpp_args=-DNO_ISAL'], + ) +endif + +osd_peering_pg_test = executable( + 'osd_peering_pg_test', + ['src/osd/osd_peering_pg_test.cpp', 'src/osd/osd_peering_pg.cpp'], + include_directories: inc, + dependencies: tcmalloc_dep, + build_by_default: false, +) + +vitastor_nfs = executable( + 'vitastor-nfs', + [ + 'src/nfs/nfs_proxy.cpp', + 'src/nfs/nfs_proxy_rdma.cpp', + 'src/nfs/nfs_block.cpp', + 'src/nfs/nfs_kv.cpp', + 'src/nfs/nfs_kv_create.cpp', + 'src/nfs/nfs_kv_defrag.cpp', + 'src/nfs/nfs_kv_getattr.cpp', + 'src/nfs/nfs_kv_link.cpp', + 'src/nfs/nfs_kv_lookup.cpp', + 'src/nfs/nfs_kv_read.cpp', + 'src/nfs/nfs_kv_readdir.cpp', + 'src/nfs/nfs_kv_remove.cpp', + 'src/nfs/nfs_kv_rename.cpp', + 'src/nfs/nfs_kv_setattr.cpp', + 'src/nfs/nfs_kv_write.cpp', + 'src/nfs/nfs_fsstat.cpp', + 'src/nfs/nfs_mount.cpp', + 'src/nfs/nfs_portmap.cpp', + 'src/nfs/rdma_alloc.cpp', + 'src/util/sha256.c', + 'src/nfs/proto/xdr_impl.cpp', + 'src/nfs/proto/rpc_rdma_xdr.cpp', + 'src/nfs/proto/rpc_xdr.cpp', + 'src/nfs/proto/portmap_xdr.cpp', + 'src/nfs/proto/nfs_xdr.cpp', + ], + include_directories: inc, + link_with: [vitastor_client, vitastor_kv, vitastor_cli, vitastor_common], + dependencies: [rdmacm_dep, ibverbs_dep, liburing_dep] + common_json_deps, + install: true, +) + +stub_osd = executable( + 'stub_osd', + ['src/test/stub_osd.cpp', 'src/util/rw_blocking.cpp', 'src/util/addr_util.cpp'], + dependencies: tcmalloc_dep, + build_by_default: false, +) +stub_bench = executable( + 'stub_bench', + ['src/test/stub_bench.cpp', 'src/util/rw_blocking.cpp', 'src/util/addr_util.cpp'], + dependencies: tcmalloc_dep, + build_by_default: false, +) +osd_test = executable( + 'osd_test', + ['src/test/osd_test.cpp', 'src/util/rw_blocking.cpp', 'src/util/addr_util.cpp'], + dependencies: tcmalloc_dep, + build_by_default: false, +) + +bindiff = executable( + 'bindiff', + ['src/test/bindiff.c'], + build_by_default: false, +) + +stub_uring_osd = executable( + 'stub_uring_osd', + ['src/test/stub_uring_osd.cpp'], + link_with: vitastor_common, + dependencies: [liburing_dep, ibverbs_dep, rdmacm_dep, tcmalloc_dep], + build_by_default: false, +) + +test_allocator = executable( + 'test_allocator', + ['src/test/test_allocator.cpp', 'src/util/allocator.cpp'], + include_directories: inc, + dependencies: [tcmalloc_dep], + build_by_default: false, +) + +test_heap = executable( + 'test_heap', + [ + 'src/test/test_heap.cpp', + 'src/blockstore/multilist.cpp', + 'src/blockstore/blockstore_heap.cpp', + 'src/util/crc32c.c', + 'src/util/allocator.cpp', + 'src/blockstore/blockstore_disk.cpp', + 'src/util/str_util.cpp', + ], + include_directories: inc, + dependencies: isal_dep, + build_by_default: false, +) + +test_cas = executable( + 'test_cas', + ['src/test/test_cas.cpp'], + include_directories: inc, + link_with: vitastor_client, + build_by_default: false, +) + +test_crc32 = executable( + 'test_crc32', + ['src/test/test_crc32.cpp'], + include_directories: inc, + link_with: vitastor_blk, + dependencies: isal_dep, + build_by_default: false, +) + +test_blockstore = executable( + 'test_blockstore', + ['src/test/test_blockstore.cpp', 'src/test/ringloop_mock.cpp'], + include_directories: inc, + link_with: [vitastor_blk, vitastor_common], + dependencies: isal_dep, + build_by_default: false, +) + +test_atomic = executable( + 'test_atomic', + ['src/test/test_atomic.cpp', 'src/util/ringloop.cpp'], + include_directories: inc, + dependencies: liburing_dep, + build_by_default: false, +) + +if build_tests_opt + test('test_cluster_client', test_cluster_client) + test('osd_rmw_test', osd_rmw_test) + if isal_dep.found() and have_jerasure_ec + test('osd_rmw_test_jerasure', osd_rmw_test_je) + endif + test('osd_peering_pg_test', osd_peering_pg_test, timeout: 120) + test('test_allocator', test_allocator) + test('test_heap', test_heap) + test('test_blockstore', test_blockstore) +endif + +install_symlink( + 'vitastor-dump-journal', + pointing_to: 'vitastor-disk', + install_dir: get_option('bindir'), +) +install_symlink( + 'vitastor-rm', + pointing_to: 'vitastor-cli', + install_dir: get_option('bindir'), +) +install_symlink( + 'vita', + pointing_to: 'vitastor-cli', + install_dir: get_option('bindir'), +) + +install_headers('src/client/vitastor_c.h') +install_headers('src/kv/vitastor_kv.h') diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 00000000..8540f0e6 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,10 @@ +option('with_qemu', type: 'boolean', value: false, description: 'Build QEMU driver inside source tree') +option('with_fio', type: 'boolean', value: true, description: 'Build FIO driver') +option('fio_srcdir', type: 'string', value: 'fio', description: 'Path to fio source tree (to provide fio headers)') +option('qemu_srcdir', type: 'string', value: 'qemu', description: 'Path to QEMU source tree') +option('qemu_builddir', type: 'string', value: 'qemu/b/qemu', description: 'Path to QEMU build directory (generated headers)') +option('qemu_plugindir', type: 'string', value: 'qemu', description: 'QEMU plugin directory suffix') +option('with_asan', type: 'boolean', value: false, description: 'Enable AddressSanitizer flags') +option('with_system_liburing', type: 'boolean', value: false, description: 'Use system-provided liburing instead of bundled sources') +option('enable_coverage', type: 'boolean', value: false, description: 'Compatibility alias for Meson b_coverage') +option('build_tests', type: 'boolean', value: true, description: 'Register unit/integration tests') -- 2.47.3