256 lines
8.6 KiB
Meson
256 lines
8.6 KiB
Meson
project('yams', ['cpp', 'c'],
|
|
version: '0.0.0',
|
|
default_options: [
|
|
'buildtype=release',
|
|
'warning_level=2',
|
|
'cpp_std=c++20',
|
|
'c_std=c11',
|
|
],
|
|
)
|
|
|
|
fs = import('fs')
|
|
pkg = import('pkgconfig')
|
|
|
|
if host_machine.system() == 'darwin'
|
|
add_global_link_arguments('-Wl,-no_warn_duplicate_libraries', language: 'cpp')
|
|
endif
|
|
|
|
# --- libc++ hardening mode ---
|
|
# Apply hardening defines when using libc++ (Darwin always uses libc++, Linux when explicitly set)
|
|
cpp = meson.get_compiler('cpp')
|
|
libcxx_hardening = get_option('libcxx-hardening')
|
|
|
|
if libcxx_hardening != 'none'
|
|
# Check if we're actually using libc++
|
|
using_libcxx = false
|
|
if host_machine.system() == 'darwin'
|
|
# macOS always uses libc++
|
|
using_libcxx = true
|
|
elif cpp.get_id() == 'clang' or cpp.get_id() == 'clang-cl'
|
|
# On non-Darwin, check if -stdlib=libc++ is in use
|
|
# This is a heuristic; proper detection would check link flags
|
|
has_libcxx = cpp.has_header('__config', prefix: '#include <ciso646>')
|
|
if has_libcxx
|
|
using_libcxx = true
|
|
endif
|
|
endif
|
|
|
|
if using_libcxx
|
|
hardening_mode_map = {
|
|
'fast': '_LIBCPP_HARDENING_MODE_FAST',
|
|
'extensive': '_LIBCPP_HARDENING_MODE_EXTENSIVE',
|
|
'debug': '_LIBCPP_HARDENING_MODE_DEBUG',
|
|
}
|
|
hardening_define = hardening_mode_map.get(libcxx_hardening)
|
|
if hardening_define != ''
|
|
add_project_arguments('-D' + hardening_define, language: 'cpp')
|
|
message('Enabling libc++ hardening mode: ' + libcxx_hardening + ' (' + hardening_define + ')')
|
|
endif
|
|
else
|
|
warning('libc++ hardening requested but not using libc++ (detected: ' + cpp.get_id() + '). Hardening mode ignored.')
|
|
endif
|
|
endif
|
|
|
|
# --- ThreadSanitizer for race detection ---
|
|
enable_tsan = get_option('enable-tsan')
|
|
if enable_tsan
|
|
buildtype = get_option('buildtype')
|
|
# TSan is most useful in debug builds; warn if enabled in release
|
|
if buildtype == 'release' or buildtype == 'plain'
|
|
warning('ThreadSanitizer enabled in non-debug build. This will significantly impact performance.')
|
|
endif
|
|
|
|
tsan_flags = [
|
|
'-fsanitize=thread',
|
|
'-g', # Debug symbols for better stack traces
|
|
'-fno-omit-frame-pointer', # Better stack traces
|
|
]
|
|
|
|
# Check if compiler supports TSan
|
|
if cpp.has_argument('-fsanitize=thread')
|
|
add_project_arguments(tsan_flags, language: 'cpp')
|
|
add_project_arguments(tsan_flags, language: 'c')
|
|
add_project_link_arguments(['-fsanitize=thread'], language: 'cpp')
|
|
add_project_link_arguments(['-fsanitize=thread'], language: 'c')
|
|
message('ThreadSanitizer enabled - expect significant performance impact')
|
|
message('Note: TSan requires all code (including dependencies) to be compiled with -fsanitize=thread')
|
|
else
|
|
error('ThreadSanitizer requested but compiler does not support -fsanitize=thread')
|
|
endif
|
|
endif
|
|
|
|
# --- Install prefix for plugin auto-trust ---
|
|
# Pass the install prefix to C++ code so the daemon knows where system plugins are installed
|
|
install_prefix = get_option('prefix')
|
|
add_project_arguments('-DYAMS_INSTALL_PREFIX="' + install_prefix + '"', language: 'cpp')
|
|
message('YAMS install prefix: ' + install_prefix)
|
|
|
|
onnx_opt = get_option('enable-onnx')
|
|
|
|
# Enforce sqlite3 FTS5 presence at configure time (configurable)
|
|
require_fts5 = get_option('require-fts5')
|
|
sqlite_dep = dependency('sqlite3', required: true)
|
|
# Skip runtime test when cross-compiling
|
|
if meson.is_cross_build()
|
|
warning('Cross-compiling: skipping SQLite FTS5 runtime check. Ensure FTS5 is enabled in your target SQLite build.')
|
|
else
|
|
fts5_prog = cpp.run(files('meson/fts5_check.cpp'), dependencies: sqlite_dep, name: 'sqlite3 FTS5 check')
|
|
if fts5_prog.returncode() != 0
|
|
msg = 'SQLite3 built without FTS5 support. Enable FTS5 in your package manager or Conan (e.g., -o "sqlite3/*:fts5=True").'
|
|
if require_fts5
|
|
error(msg)
|
|
else
|
|
warning(msg)
|
|
endif
|
|
endif
|
|
endif
|
|
|
|
# Boost is a core requirement (e.g., Boost.Asio for daemon communication).
|
|
# Conan's PkgConfigDeps often doesn't emit boost.pc, so prefer CMake config.
|
|
boost_dep = dependency('boost', modules: ['system', 'thread'], method: 'cmake', required: true)
|
|
meson.override_dependency('boost', boost_dep)
|
|
|
|
# --- Version header generation ---
|
|
_override_version = get_option('yams-version')
|
|
_effective_version = _override_version != '' ? _override_version : meson.project_version()
|
|
_build_timestamp = run_command('date', '-u', '+%Y-%m-%dT%H:%M:%SZ', check: true).stdout().strip()
|
|
_git_desc = ''
|
|
_git_cmd = find_program('git', required: false)
|
|
if _git_cmd.found()
|
|
# Capture short git describe (best-effort; ignore errors quietly)
|
|
_r = run_command(_git_cmd, ['describe', '--tags', '--always', '--dirty'], check: false)
|
|
if _r.returncode() == 0
|
|
_git_desc = _r.stdout().strip()
|
|
endif
|
|
endif
|
|
|
|
version_config = configuration_data()
|
|
version_config.set('YAMS_EFFECTIVE_VERSION', _effective_version)
|
|
version_config.set('YAMS_PROJECT_VERSION', meson.project_version())
|
|
version_config.set('YAMS_OVERRIDE_VERSION', _override_version)
|
|
version_config.set('YAMS_BUILD_TIMESTAMP', _build_timestamp)
|
|
version_config.set('YAMS_GIT_DESCRIBE', _git_desc)
|
|
|
|
configure_file(
|
|
output: 'version_generated.h',
|
|
install: true,
|
|
install_dir: get_option('includedir') / 'yams',
|
|
configuration: version_config,
|
|
format: 'cmake', # Simple @VAR@ substitution; header template below.
|
|
input: files('include/yams/version_generated.h.in')
|
|
)
|
|
|
|
yams_build_cli = get_option('build-cli')
|
|
yams_build_mcp = get_option('build-mcp-server')
|
|
yams_enable_tui = get_option('enable-tui')
|
|
|
|
# Install public headers under the compiler's include prefix without duplicating
|
|
# the top-level 'include' directory (was producing prefix/include/include/...).
|
|
install_subdir('include', install_dir: get_option('includedir'), strip_directory: true)
|
|
|
|
# Core libraries (ordered by dependency)
|
|
subdir('src/core')
|
|
subdir('src/crypto')
|
|
subdir('src/chunking')
|
|
subdir('src/compression')
|
|
subdir('src/storage')
|
|
subdir('src/wal')
|
|
subdir('src/manifest')
|
|
subdir('src/integrity')
|
|
subdir('src/config')
|
|
subdir('src/metadata')
|
|
subdir('src/extraction')
|
|
subdir('src/detection')
|
|
subdir('src/content')
|
|
subdir('src/downloader')
|
|
subdir('src/indexing')
|
|
subdir('src/genai')
|
|
subdir('src/vector')
|
|
subdir('src/search')
|
|
subdir('src/api')
|
|
subdir('src/ingest')
|
|
subdir('src/repair')
|
|
subdir('src/daemon/client')
|
|
subdir('src/app/services')
|
|
subdir('src/daemon')
|
|
subdir('src/mobile')
|
|
subdir('src/benchmarks')
|
|
|
|
if get_option('build-mcp-server')
|
|
subdir('src/mcp')
|
|
endif
|
|
|
|
if get_option('build-plugins')
|
|
subdir('plugins')
|
|
endif
|
|
|
|
if get_option('build-cli')
|
|
subdir('src/cli')
|
|
subdir('tools/yams-cli')
|
|
if get_option('build-mcp-server')
|
|
subdir('tools/yams-mcp')
|
|
endif
|
|
endif
|
|
|
|
# Tests (enabled by default in Debug builds)
|
|
_tests_opt = get_option('build-tests')
|
|
_buildtype = get_option('buildtype')
|
|
_tests_enabled = _tests_opt or (_buildtype == 'debug')
|
|
if _tests_enabled
|
|
subdir('tests')
|
|
endif
|
|
|
|
# Fuzzing harnesses (AFL++/libFuzzer)
|
|
if get_option('build-fuzzers')
|
|
subdir('tools/fuzzing')
|
|
endif
|
|
|
|
summary({
|
|
'project': meson.project_name(),
|
|
'version': meson.project_version(),
|
|
'cpp_std': get_option('cpp_std'),
|
|
'build_cli': yams_build_cli,
|
|
'build_mcp_server': yams_build_mcp,
|
|
'enable_tui': yams_enable_tui,
|
|
}, section: 'YAMS Meson configuration', bool_yn: true)
|
|
|
|
if get_option('b_coverage')
|
|
gcovr = find_program('gcovr', required: false)
|
|
if gcovr.found()
|
|
coverage_report_target = custom_target('coverage-report',
|
|
output: 'coverage-report.stamp',
|
|
command: [
|
|
gcovr,
|
|
'--root', meson.project_source_root(),
|
|
'--filter', join_paths(meson.project_source_root(), 'src'),
|
|
'--filter', join_paths(meson.project_source_root(), 'include'),
|
|
'--exclude', join_paths(meson.project_source_root(), 'src', 'benchmarks'),
|
|
'--html', '--html-details',
|
|
'--output', join_paths(meson.project_build_root(), 'coverage', 'index.html'),
|
|
meson.project_build_root(),
|
|
],
|
|
build_by_default: false,
|
|
build_always_stale: true,
|
|
)
|
|
|
|
coverage_txt_target = custom_target('coverage-summary',
|
|
output: 'coverage.txt',
|
|
command: [
|
|
gcovr,
|
|
'--root', meson.project_source_root(),
|
|
'--filter', join_paths(meson.project_source_root(), 'src'),
|
|
'--filter', join_paths(meson.project_source_root(), 'include'),
|
|
'--exclude', join_paths(meson.project_source_root(), 'src', 'benchmarks'),
|
|
'--print-summary',
|
|
'--output', '@OUTPUT@',
|
|
meson.project_build_root(),
|
|
],
|
|
build_by_default: false,
|
|
build_always_stale: true,
|
|
)
|
|
|
|
message('Coverage reporting configured. Run tests then: ninja -C builddir coverage-report')
|
|
else
|
|
warning('gcovr not found. Install gcovr to generate coverage reports.')
|
|
endif
|
|
endif
|