yams/CMakeLists.txt
2025-08-11 20:35:51 -04:00

1115 lines
40 KiB
CMake

cmake_minimum_required(VERSION 3.20)
# Option to use Conan for dependency management
# Check if we're running with a Conan preset (the toolchain file will be in generators/)
if(CMAKE_TOOLCHAIN_FILE MATCHES "conan_toolchain\\.cmake$")
set(YAMS_USE_CONAN ON CACHE BOOL "Using Conan package manager" FORCE)
else()
option(YAMS_USE_CONAN "Use Conan package manager for dependencies" OFF)
endif()
# Derive version from git tags or allow override via -DYAMS_VERSION=MAJOR.MINOR.PATCH
set(YAMS_VERSION "" CACHE STRING "Override Yams version (semver: MAJOR.MINOR.PATCH)")
if(NOT YAMS_VERSION)
find_package(Git QUIET)
if(Git_FOUND)
execute_process(
COMMAND "${GIT_EXECUTABLE}" describe --tags --match "v[0-9]*" --dirty --always
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
OUTPUT_VARIABLE GIT_DESCRIBE
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Strip leading 'v' and any suffix like -123-gabcdef
string(REGEX REPLACE "^v" "" YAMS_VERSION_CANDIDATE "${GIT_DESCRIBE}")
string(REGEX MATCH "^[0-9]+\\.[0-9]+\\.[0-9]+" YAMS_SEMVER "${YAMS_VERSION_CANDIDATE}")
if(NOT YAMS_SEMVER)
set(YAMS_SEMVER "0.0.0")
endif()
else()
set(YAMS_SEMVER "0.0.0")
endif()
else()
set(YAMS_SEMVER "${YAMS_VERSION}")
endif()
project(YAMS
VERSION ${YAMS_SEMVER}
DESCRIPTION "Yet Another Memory System - High-performance content-addressed storage"
LANGUAGES C CXX
)
# Generate version header from project version
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/generated/yams")
# Write template for version header and configure it
set(_YAMS_VERSION_TEMPLATE "${CMAKE_CURRENT_BINARY_DIR}/yams_version.hpp.in")
file(WRITE "${_YAMS_VERSION_TEMPLATE}" "/* Auto-generated by CMake - Do not edit */
#pragma once
#define YAMS_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define YAMS_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define YAMS_VERSION_PATCH @PROJECT_VERSION_PATCH@
#define YAMS_VERSION_STRING \"@PROJECT_VERSION@\"
")
configure_file(
"${_YAMS_VERSION_TEMPLATE}"
"${CMAKE_CURRENT_BINARY_DIR}/generated/yams/version.hpp"
@ONLY
)
# Ensure default CMake package dir uses 'Yams' casing for consumers
include(GNUInstallDirs)
# Install generated version header
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/generated/yams/version.hpp"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/yams"
COMPONENT development)
set(YAMS_CMAKE_PACKAGE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/Yams"
CACHE PATH "Install dir for YAMS CMake package files")
# Modern CMake policies (set only if available)
if(POLICY CMP0077) # option() honors normal variables
cmake_policy(SET CMP0077 NEW)
endif()
if(POLICY CMP0126) # file(GENERATE) supports generator expressions in OUTPUT
cmake_policy(SET CMP0126 NEW)
endif()
if(POLICY CMP0135) # IN_LIST behavior and other modern improvements
cmake_policy(SET CMP0135 NEW)
endif()
# C++20 is required
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Compiler version checks for GCC
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11)
message(FATAL_ERROR "GCC ${CMAKE_CXX_COMPILER_VERSION} detected. GCC 11+ is required for C++20 support.")
endif()
message(STATUS "Using GCC ${CMAKE_CXX_COMPILER_VERSION}")
endif()
# Check for std::format availability
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("
#include <version>
#ifdef __cpp_lib_format
#include <format>
int main() {
auto s = std::format(\"{}\", 42);
return 0;
}
#else
#error No format support
#endif
" YAMS_HAS_STD_FORMAT)
if(YAMS_HAS_STD_FORMAT)
add_compile_definitions(YAMS_HAS_STD_FORMAT=1)
message(STATUS "std::format is available")
else()
add_compile_definitions(YAMS_HAS_STD_FORMAT=0)
message(STATUS "std::format is NOT available - using fallbacks")
endif()
# Export compile commands for tooling
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Build profile options
set(YAMS_BUILD_PROFILE "custom" CACHE STRING "Build profile: release, dev, or custom")
set_property(CACHE YAMS_BUILD_PROFILE PROPERTY STRINGS release dev custom)
# Individual component options
option(YAMS_BUILD_CLI "Build CLI tool" ON)
option(YAMS_BUILD_MCP_SERVER "Build MCP server" ON)
option(YAMS_BUILD_MAINTENANCE_TOOLS "Build maintenance tools (gc, stats)" OFF)
option(YAMS_BUILD_TESTS "Build unit tests" OFF)
option(YAMS_BUILD_STRESS_TESTS "Build stress tests" OFF)
option(YAMS_BUILD_BENCHMARKS "Build benchmarks" OFF)
option(YAMS_ENABLE_SANITIZERS "Enable sanitizers in Debug" ON)
option(YAMS_ENABLE_COVERAGE "Enable code coverage" OFF)
option(YAMS_USE_VCPKG "Use vcpkg for dependencies" OFF)
# ------------------------------------------------------------------------------
# Docs build (Pandoc) and embedded CLI help assets
# ------------------------------------------------------------------------------
option(YAMS_BUILD_DOCS "Build CLI docs, generate manpages, and embed verbose help" ON)
find_program(PANDOC_EXECUTABLE pandoc)
set(CLI_MD "${CMAKE_SOURCE_DIR}/docs/user_guide/cli.md")
set(GEN_DIR "${CMAKE_BINARY_DIR}/generated/cli")
set(MAN_DIR "${CMAKE_BINARY_DIR}/man")
if(YAMS_BUILD_DOCS AND PANDOC_EXECUTABLE AND EXISTS "${CLI_MD}")
# Ensure output directories
file(MAKE_DIRECTORY "${GEN_DIR}")
file(MAKE_DIRECTORY "${MAN_DIR}")
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/generated")
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/cmake")
# 1) Generate full plain-text help from Markdown
add_custom_command(
OUTPUT "${GEN_DIR}/cli_help.txt"
COMMAND "${PANDOC_EXECUTABLE}" -f markdown -t plain "${CLI_MD}" -o "${GEN_DIR}/cli_help.txt"
DEPENDS "${CLI_MD}"
COMMENT "Generating plain-text CLI help from Markdown"
VERBATIM
)
# 2) Generate yams(1) manpage from Markdown
add_custom_command(
OUTPUT "${MAN_DIR}/yams.1"
COMMAND "${PANDOC_EXECUTABLE}" -s -f markdown -t man "${CLI_MD}" -o "${MAN_DIR}/yams.1"
DEPENDS "${CLI_MD}"
COMMENT "Generating yams(1) manpage from Markdown"
VERBATIM
)
# 3) Embed script (converts a text file to a C++ header with a constexpr string)
set(EMBED_SCRIPT "${CMAKE_BINARY_DIR}/cmake/embed_text.cmake")
file(WRITE "${EMBED_SCRIPT}"
"if(NOT DEFINED INPUT)
message(FATAL_ERROR \"INPUT not set\")
endif()
if(NOT DEFINED OUTPUT)
message(FATAL_ERROR \"OUTPUT not set\")
endif()
# Optional: caller can pass -DSYMBOL=<name>. Defaults to VERBOSE.
if(NOT DEFINED SYMBOL)
set(SYMBOL \"VERBOSE\")
endif()
set(_SYM \"\${SYMBOL}\")
string(TOUPPER \"\${_SYM}\" _SYM)
string(REGEX REPLACE \"[^A-Za-z0-9_]\" \"_\" _SYM \"\${_SYM}\")
# Prefix command-specific symbols for clarity (keep full doc as VERBOSE)
if(NOT _SYM STREQUAL \"VERBOSE\")
set(_SYM \"CMD_\${_SYM}\")
endif()
# Strip quotes from INPUT and OUTPUT if present
string(REGEX REPLACE \"^\\\"(.*)\\\"$\" \"\\\\1\" INPUT_CLEAN \"\${INPUT}\")
string(REGEX REPLACE \"^\\\"(.*)\\\"$\" \"\\\\1\" OUTPUT_CLEAN \"\${OUTPUT}\")
# Check if input file exists
if(NOT EXISTS \"\${INPUT_CLEAN}\")
message(FATAL_ERROR \"Input file does not exist: '\${INPUT_CLEAN}'\")
endif()
# Check if output directory exists
get_filename_component(OUTPUT_DIR \"\${OUTPUT_CLEAN}\" DIRECTORY)
if(NOT EXISTS \"\${OUTPUT_DIR}\")
file(MAKE_DIRECTORY \"\${OUTPUT_DIR}\")
endif()
file(READ \"\${INPUT_CLEAN}\" _c)
string(REPLACE \"\\\\\" \"\\\\\\\\\" _c \"\${_c}\")
string(REPLACE \"\\\"\" \"\\\\\\\"\" _c \"\${_c}\")
string(REPLACE \"\\n\" \"\\\\n\\\"\\n\\\"\" _c \"\${_c}\")
file(WRITE \"\${OUTPUT_CLEAN}\" \"// Generated by embed_text.cmake - do not edit\\n#pragma once\\nnamespace yams { namespace cli_help {\\nconstexpr const char \${_SYM}[] = \\\"\${_c}\\\";\\n} } // namespace yams::cli_help\\n\")
")
# 4) Embed full verbose help into a header
add_custom_command(
OUTPUT "${CMAKE_BINARY_DIR}/generated/cli_help.hpp"
COMMAND "${CMAKE_COMMAND}" -DINPUT="${GEN_DIR}/cli_help.txt" -DOUTPUT="${CMAKE_BINARY_DIR}/generated/cli_help.hpp" -DSYMBOL=VERBOSE -P "${EMBED_SCRIPT}"
DEPENDS "${GEN_DIR}/cli_help.txt" "${EMBED_SCRIPT}"
COMMENT "Embedding full CLI help into header"
VERBATIM
)
# 5) Split per-command sections from the Markdown for detailed command help
# The splitter scans lines and collects sections for known commands.
set(SPLIT_SCRIPT "${CMAKE_BINARY_DIR}/cmake/split_cli_sections.cmake")
file(WRITE "${SPLIT_SCRIPT}"
"set(CLI_MD \"${CLI_MD}\")
set(OUT_DIR \"${GEN_DIR}\")
# Commands to extract (must match headings like '## <name>' or '## <name> {#cmd-name}')
set(COMMANDS init add get delete list search config auth stats uninstall migrate browse serve)
file(STRINGS \"${CLI_MD}\" LINES)
set(current \"\")
set(in_section FALSE)
set(content \"\")
function(_flush_section name)
if(NOT \"\${name}\" STREQUAL \"\")
set(path \"\${OUT_DIR}/cli_help_\${name}.txt\")
file(WRITE \"\${OUT_DIR}/tmp_\${name}.txt\" \"\${content}\")
file(RENAME \"\${OUT_DIR}/tmp_\${name}.txt\" \"\${path}\")
endif()
endfunction()
foreach(line IN LISTS LINES)
if(line MATCHES \"^##[ ]+([A-Za-z0-9_-]+)[ ]*(\\{#cmd-.*\\})?\")
string(REGEX REPLACE \"^##[ ]+([A-Za-z0-9_-]+).*$\" \"\\\\1\" heading \"\${line}\")
# Close previous section if any
if(in_section)
_flush_section(\"\${current}\")
set(content \"\")
endif()
# Start a new section only if the heading is one of our commands
list(FIND COMMANDS \"\${heading}\" idx)
if(NOT idx EQUAL -1)
set(current \"\${heading}\")
set(in_section TRUE)
set(content \"\${line}\\n\")
else()
set(current \"\")
set(in_section FALSE)
set(content \"\")
endif()
else()
if(in_section)
set(content \"\${content}\${line}\\n\")
endif()
endif()
endforeach()
# Flush the last open section
if(in_section)
_flush_section(\"\${current}\")
endif()
")
add_custom_command(
OUTPUT
"${GEN_DIR}/cli_help_init.txt"
"${GEN_DIR}/cli_help_add.txt"
"${GEN_DIR}/cli_help_get.txt"
"${GEN_DIR}/cli_help_delete.txt"
"${GEN_DIR}/cli_help_list.txt"
"${GEN_DIR}/cli_help_search.txt"
"${GEN_DIR}/cli_help_config.txt"
"${GEN_DIR}/cli_help_auth.txt"
"${GEN_DIR}/cli_help_stats.txt"
"${GEN_DIR}/cli_help_uninstall.txt"
"${GEN_DIR}/cli_help_migrate.txt"
"${GEN_DIR}/cli_help_browse.txt"
"${GEN_DIR}/cli_help_serve.txt"
COMMAND "${CMAKE_COMMAND}" -P "${SPLIT_SCRIPT}"
DEPENDS "${CLI_MD}" "${SPLIT_SCRIPT}"
COMMENT "Splitting per-command CLI sections from Markdown"
VERBATIM
)
# 6) Embed per-command verbose help headers
set(EMBED_HEADERS)
foreach(cmd init add get delete list search config auth stats uninstall migrate browse serve)
set(infile "${GEN_DIR}/cli_help_${cmd}.txt")
set(outfile "${CMAKE_BINARY_DIR}/generated/cli_help_${cmd}.hpp")
add_custom_command(
OUTPUT "${outfile}"
COMMAND "${CMAKE_COMMAND}" -DINPUT="${infile}" -DOUTPUT="${outfile}" -DSYMBOL=${cmd} -P "${EMBED_SCRIPT}"
DEPENDS "${infile}" "${EMBED_SCRIPT}"
COMMENT "Embedding ${cmd} CLI help into header"
VERBATIM
)
list(APPEND EMBED_HEADERS "${outfile}")
endforeach()
# 7) Aggregate docs target
add_custom_target(docs
DEPENDS
"${CMAKE_BINARY_DIR}/generated/cli_help.hpp"
${EMBED_HEADERS}
"${MAN_DIR}/yams.1"
)
# 8) Install generated manpage
include(GNUInstallDirs)
install(FILES "${MAN_DIR}/yams.1" DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" COMPONENT runtime)
# 9) Global compile definition to indicate embedded help is available
add_compile_definitions(YAMS_EMBEDDED_VERBOSE_HELP=1)
else()
if(YAMS_BUILD_DOCS AND NOT PANDOC_EXECUTABLE)
message(WARNING "YAMS_BUILD_DOCS=ON but Pandoc was not found. Install Pandoc and re-configure CMake.
- macOS: brew install pandoc
- Ubuntu/Debian: sudo apt-get update && sudo apt-get install -y pandoc
- Fedora: sudo dnf install -y pandoc
- Arch: sudo pacman -S pandoc
- Windows (PowerShell): choco install pandoc or scoop install pandoc")
elseif(YAMS_BUILD_DOCS AND NOT EXISTS "${CLI_MD}")
message(WARNING "YAMS_BUILD_DOCS=ON but CLI markdown not found at ${CLI_MD}; skipping docs build.")
else()
message(STATUS "Docs build disabled; verbose help embedding and manpage generation are skipped.")
endif()
endif()
# Configure based on build profile
if(YAMS_BUILD_PROFILE STREQUAL "release")
message(STATUS "Using RELEASE build profile - CLI and MCP server only")
set(YAMS_BUILD_CLI ON CACHE BOOL "" FORCE)
set(YAMS_BUILD_MCP_SERVER ON CACHE BOOL "" FORCE)
set(YAMS_BUILD_MAINTENANCE_TOOLS OFF CACHE BOOL "" FORCE)
set(YAMS_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(YAMS_BUILD_BENCHMARKS OFF CACHE BOOL "" FORCE)
set(YAMS_BUILD_STRESS_TESTS OFF CACHE BOOL "" FORCE)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE)
endif()
elseif(YAMS_BUILD_PROFILE STREQUAL "dev")
message(STATUS "Using DEVELOPMENT build profile - all components")
set(YAMS_BUILD_CLI ON CACHE BOOL "" FORCE)
set(YAMS_BUILD_MCP_SERVER ON CACHE BOOL "" FORCE)
set(YAMS_BUILD_MAINTENANCE_TOOLS ON CACHE BOOL "" FORCE)
set(YAMS_BUILD_TESTS ON CACHE BOOL "" FORCE)
set(YAMS_BUILD_BENCHMARKS ON CACHE BOOL "" FORCE)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE)
endif()
else()
message(STATUS "Using CUSTOM build profile - individual options apply")
# Set a sensible default build type for single-config generators when unset
if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel)
endif()
endif()
# Legacy compatibility
set(YAMS_BUILD_TOOLS ${YAMS_BUILD_CLI})
# C++20 feature checks
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("
#include <concepts>
#include <coroutine>
#include <ranges>
#include <format>
#include <span>
template<typename T>
concept Integral = std::integral<T>;
int main() {
std::span<int> s;
return 0;
}
" HAVE_CXX20_FEATURES)
if(NOT HAVE_CXX20_FEATURES)
message(FATAL_ERROR "C++20 features not fully supported by compiler")
endif()
# Compiler warnings
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
add_compile_options(
-Wall -Wextra -Wpedantic
-Wcast-align -Wcast-qual
-Wconversion -Wsign-conversion
-Wdouble-promotion -Wformat=2
-Wnon-virtual-dtor -Wold-style-cast
-Woverloaded-virtual -Wshadow
$<$<CONFIG:Debug>:-Og>
$<$<CONFIG:Debug>:-g3>
$<$<CONFIG:Release>:-O3>
)
# Architecture-specific optimizations (not on Apple Silicon)
if(NOT APPLE OR NOT CMAKE_SYSTEM_PROCESSOR MATCHES "arm64")
add_compile_options($<$<CONFIG:Release>:-march=native>)
endif()
# Coroutine support
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
add_compile_options(-fcoroutines)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-stdlib=libc++)
add_link_options(-stdlib=libc++)
# Apple Clang has coroutines enabled by default in C++20
if(NOT APPLE)
add_compile_options(-fcoroutines-ts)
endif()
endif()
elseif(MSVC)
add_compile_options(
/W4 /permissive- /Zc:__cplusplus
/Zc:preprocessor # For proper __VA_OPT__ support
$<$<CONFIG:Debug>:/Od /RTC1>
$<$<CONFIG:Release>:/O2 /GL>
)
add_link_options($<$<CONFIG:Release>:/LTCG>)
endif()
# Sanitizers
if(YAMS_ENABLE_SANITIZERS AND CMAKE_BUILD_TYPE STREQUAL "Debug")
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
add_compile_options(-fsanitize=address,undefined -fno-omit-frame-pointer)
add_link_options(-fsanitize=address,undefined)
endif()
endif()
# Code Coverage
if(YAMS_ENABLE_COVERAGE)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
add_compile_options(-fprofile-arcs -ftest-coverage)
add_link_options(-fprofile-arcs -ftest-coverage)
set(COVERAGE_LIBRARIES gcov)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-fprofile-instr-generate -fcoverage-mapping)
add_link_options(-fprofile-instr-generate -fcoverage-mapping)
endif()
# Find coverage tools
find_program(GCOVR_PATH gcovr)
find_program(LCOV_PATH lcov)
find_program(GENHTML_PATH genhtml)
if(GCOVR_PATH)
message(STATUS "Found gcovr: ${GCOVR_PATH}")
elseif(LCOV_PATH AND GENHTML_PATH)
message(STATUS "Found lcov: ${LCOV_PATH}")
message(STATUS "Found genhtml: ${GENHTML_PATH}")
else()
message(WARNING "No coverage report generator found. Install gcovr or lcov for coverage reports.")
endif()
message(STATUS "Code coverage enabled")
endif()
# Dependencies
include(FetchContent)
set(FETCHCONTENT_QUIET FALSE)
# OpenSSL
if(APPLE)
# Help CMake find Homebrew's OpenSSL
set(OPENSSL_ROOT_DIR ${OPENSSL_ROOT_DIR} /opt/homebrew/opt/openssl@3 /usr/local/opt/openssl@3)
endif()
find_package(OpenSSL REQUIRED)
message(STATUS "Found OpenSSL: ${OPENSSL_VERSION}")
message(STATUS "OpenSSL include dir: ${OPENSSL_INCLUDE_DIR}")
message(STATUS "OpenSSL crypto library: ${OPENSSL_CRYPTO_LIBRARY}")
# Threads (required for websocketpp)
find_package(Threads REQUIRED)
# Ncurses detection for Linux builds
if(YAMS_BUILD_CLI AND NOT YAMS_USE_CONAN)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
# Look for ncurses with wide character support first
find_package(Curses)
if(NOT CURSES_FOUND)
# Try pkg-config as fallback
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
pkg_check_modules(NCURSES ncursesw)
if(NOT NCURSES_FOUND)
pkg_check_modules(NCURSES ncurses)
endif()
endif()
if(NOT NCURSES_FOUND)
message(FATAL_ERROR
"ncurses library not found. Please install it:\n"
" Ubuntu/Debian: sudo apt-get install libncurses-dev\n"
" RHEL/CentOS: sudo yum install ncurses-devel\n"
" Fedora: sudo dnf install ncurses-devel\n"
" Arch: sudo pacman -S ncurses")
endif()
else()
message(STATUS "Found Curses: ${CURSES_LIBRARIES}")
endif()
endif()
endif()
# Google Test
if(YAMS_BUILD_TESTS)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.14.0
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
endif()
# Google Benchmark
if(YAMS_BUILD_BENCHMARKS)
FetchContent_Declare(
benchmark
GIT_REPOSITORY https://github.com/google/benchmark.git
GIT_TAG v1.8.3
)
set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE)
# Disable werror for benchmark library to avoid strict warning issues
set(BENCHMARK_ENABLE_WERROR OFF CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(benchmark)
# Apply warning suppressions to benchmark target after it's created
if(TARGET benchmark)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(benchmark PRIVATE
-Wno-sign-conversion
-Wno-format-nonliteral
-Wno-double-promotion
-Wno-conversion
-Wno-old-style-cast)
endif()
endif()
if(TARGET benchmark_main)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(benchmark_main PRIVATE
-Wno-sign-conversion
-Wno-format-nonliteral
-Wno-double-promotion
-Wno-conversion
-Wno-old-style-cast)
endif()
endif()
endif()
# Dependency management
if(YAMS_USE_CONAN)
# When using Conan, dependencies are provided via find_package
find_package(spdlog REQUIRED)
find_package(nlohmann_json REQUIRED)
find_package(CLI11 REQUIRED)
find_package(ZLIB REQUIRED)
find_package(zstd REQUIRED)
find_package(lz4 REQUIRED)
find_package(SQLite3 REQUIRED)
find_package(Protobuf REQUIRED)
find_package(OpenSSL REQUIRED)
if(YAMS_BUILD_CLI)
find_package(Curses REQUIRED)
endif()
if(YAMS_BUILD_MCP_SERVER)
find_package(Drogon REQUIRED)
find_package(Boost REQUIRED)
endif()
if(YAMS_BUILD_TESTS)
# Note: Conan's GTest config has issues with alias targets
# We'll use FetchContent for tests even with Conan
set(YAMS_USE_FETCHCONTENT_FOR_TESTS ON)
endif()
if(YAMS_BUILD_BENCHMARKS)
find_package(benchmark REQUIRED)
endif()
endif()
# When not using Conan, use FetchContent for dependencies
message(STATUS "YAMS_USE_CONAN is: ${YAMS_USE_CONAN}")
if(NOT YAMS_USE_CONAN)
message(STATUS "Using FetchContent for dependencies (non-Conan mode)")
# spdlog for logging
FetchContent_Declare(
spdlog
GIT_REPOSITORY https://github.com/gabime/spdlog.git
GIT_TAG v1.12.0
)
set(SPDLOG_INSTALL ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(spdlog)
# nlohmann_json for JSON parsing
find_package(nlohmann_json 3.11 QUIET)
if(NOT nlohmann_json_FOUND)
FetchContent_Declare(
nlohmann_json
GIT_REPOSITORY https://github.com/nlohmann/json.git
GIT_TAG v3.11.3
)
FetchContent_MakeAvailable(nlohmann_json)
# Export nlohmann_json with YamsTargets for downstream consumers
install(TARGETS nlohmann_json
EXPORT YamsTargets
)
endif()
# Install nlohmann_json headers (it's header-only)
install(DIRECTORY ${nlohmann_json_SOURCE_DIR}/include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
endif()
# CLI11 for command line parsing
if(YAMS_BUILD_TOOLS)
if(NOT YAMS_USE_CONAN)
FetchContent_Declare(
CLI11
GIT_REPOSITORY https://github.com/CLIUtils/CLI11.git
GIT_TAG v2.4.1
)
FetchContent_MakeAvailable(CLI11)
endif()
# ImTUI for Terminal User Interface (Immediate Mode TUI)
if(YAMS_BUILD_CLI)
if(YAMS_USE_CONAN)
# When using Conan, we need to use ExternalProject_Add to pass ncurses paths
include(ExternalProject)
# Find Curses package to get Conan-provided paths
find_package(Curses REQUIRED)
# Build the full library paths from Conan variables
set(NCURSES_LIB_PATH "${ncurses_LIB_DIRS_RELEASE}/libncursesw.a")
set(TINFO_LIB_PATH "${ncurses_LIB_DIRS_RELEASE}/libtinfow.a")
# Use ExternalProject_Add to build ImTUI with system ncurses
# Use system ncurses for ImTUI to get compatible versioned symbols
# while keeping Conan for all other dependencies
ExternalProject_Add(
imtui_external
GIT_REPOSITORY https://github.com/ggerganov/imtui.git
GIT_TAG master
CMAKE_ARGS
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/imtui_install
-DIMTUI_BUILD_EXAMPLES=OFF
# Let ImTUI find system ncurses naturally for compatibility
BUILD_ALWAYS OFF
INSTALL_COMMAND ""
)
# Create interface library for ImTUI that our code can link to
add_library(imtui-ncurses INTERFACE)
add_dependencies(imtui-ncurses imtui_external)
# Add include directories - ImTUI needs to find imgui/imgui.h
# The ImTUI header does #include "imgui/imgui.h" so we need to add the dir that contains imgui/
# Our code does #include <imgui.h> so we need to add the imgui dir itself too
target_include_directories(imtui-ncurses INTERFACE
${CMAKE_BINARY_DIR}/imtui_external-prefix/src/imtui_external/include
${CMAKE_BINARY_DIR}/imtui_external-prefix/src/imtui_external/third-party/imgui
${CMAKE_BINARY_DIR}/imtui_external-prefix/src/imtui_external/third-party/imgui/imgui
)
# Link to the built ImTUI library and system ncurses for compatibility
target_link_libraries(imtui-ncurses INTERFACE
${CMAKE_BINARY_DIR}/imtui_external-prefix/src/imtui_external-build/src/libimtui-ncurses.a
${CMAKE_BINARY_DIR}/imtui_external-prefix/src/imtui_external-build/src/libimtui.a
${CMAKE_BINARY_DIR}/imtui_external-prefix/src/imtui_external-build/third-party/libimgui-for-imtui.a
# Use system ncurses for ImTUI to match versioned symbols
curses
)
if(APPLE)
target_link_libraries(imtui-ncurses INTERFACE "-framework System")
endif()
else()
# Use FetchContent for non-Conan builds
FetchContent_Declare(
imtui
GIT_REPOSITORY https://github.com/ggerganov/imtui.git
GIT_TAG master
GIT_SHALLOW TRUE
GIT_SUBMODULES_RECURSE TRUE
)
set(IMTUI_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(imtui)
endif()
endif()
endif()
# Boost.Beast is part of Boost and will be available automatically
# No separate dependency needed for WebSocket transport
# Zstandard for compression - only if not using Conan
if(NOT YAMS_USE_CONAN)
FetchContent_Declare(
zstd
URL https://github.com/facebook/zstd/releases/download/v1.5.6/zstd-1.5.6.tar.gz
URL_HASH SHA256=8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1
SOURCE_SUBDIR build/cmake
)
set(ZSTD_BUILD_PROGRAMS OFF CACHE BOOL "" FORCE)
set(ZSTD_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(ZSTD_BUILD_SHARED OFF CACHE BOOL "" FORCE)
set(ZSTD_BUILD_STATIC ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(zstd)
endif()
# LZMA SDK for compression - always needed since no good Conan package exists
# if(NOT YAMS_USE_CONAN)
FetchContent_Declare(
lzma
URL https://github.com/ip7z/7zip/releases/download/24.08/7z2408-src.tar.xz
URL_HASH SHA256=aa04aac906a04df59e7301f4c69e9f48808e6c8ecae4eb697703a47bfb0ac042
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
)
FetchContent_GetProperties(lzma)
if(NOT lzma_POPULATED)
FetchContent_Populate(lzma)
# Create LZMA library from SDK sources
add_library(lzma_sdk STATIC
${lzma_SOURCE_DIR}/C/LzmaEnc.c
${lzma_SOURCE_DIR}/C/LzmaDec.c
${lzma_SOURCE_DIR}/C/LzFind.c
${lzma_SOURCE_DIR}/C/Lzma2Enc.c
${lzma_SOURCE_DIR}/C/Lzma2Dec.c
${lzma_SOURCE_DIR}/C/Lzma86Enc.c
${lzma_SOURCE_DIR}/C/Lzma86Dec.c
${lzma_SOURCE_DIR}/C/CpuArch.c
${lzma_SOURCE_DIR}/C/Alloc.c
${lzma_SOURCE_DIR}/C/LzFindMt.c
${lzma_SOURCE_DIR}/C/Threads.c
${lzma_SOURCE_DIR}/C/MtCoder.c
${lzma_SOURCE_DIR}/C/MtDec.c
${lzma_SOURCE_DIR}/C/Lzma2DecMt.c
${lzma_SOURCE_DIR}/C/LzFindOpt.c
${lzma_SOURCE_DIR}/C/7zStream.c
)
target_include_directories(lzma_sdk PUBLIC
$<BUILD_INTERFACE:${lzma_SOURCE_DIR}/C>
$<INSTALL_INTERFACE:include/lzma>
)
# Enable multi-threaded support for LZMA SDK
# Disable warnings for third-party code
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(lzma_sdk PRIVATE -w)
elseif(MSVC)
target_compile_options(lzma_sdk PRIVATE /w)
endif()
endif()
# endif()
# SQLite3 with FTS5 - only if not using Conan
if(NOT YAMS_USE_CONAN)
FetchContent_Declare(
sqlite3
URL https://www.sqlite.org/2024/sqlite-amalgamation-3460100.zip
URL_HASH SHA256=77823cb110929c2bcb0f5d48e4833b5c59a8a6e40cdea3936b99e199dbbe5784
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
)
FetchContent_GetProperties(sqlite3)
if(NOT sqlite3_POPULATED)
FetchContent_Populate(sqlite3)
# Create SQLite library with FTS5 enabled
add_library(sqlite3 STATIC
${sqlite3_SOURCE_DIR}/sqlite3.c
)
target_include_directories(sqlite3 PUBLIC
$<BUILD_INTERFACE:${sqlite3_SOURCE_DIR}>
$<INSTALL_INTERFACE:include/sqlite3>
)
# Enable FTS5 and other useful extensions
target_compile_definitions(sqlite3 PRIVATE
SQLITE_ENABLE_FTS5=1
SQLITE_ENABLE_RTREE=1
SQLITE_ENABLE_JSON1=1
SQLITE_ENABLE_STAT4=1
SQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
SQLITE_ENABLE_COLUMN_METADATA=1
SQLITE_DEFAULT_MEMSTATUS=0
SQLITE_DEFAULT_WAL_SYNCHRONOUS=1
SQLITE_LIKE_DOESNT_MATCH_BLOBS=1
SQLITE_MAX_EXPR_DEPTH=0
SQLITE_OMIT_DEPRECATED=1
SQLITE_OMIT_SHARED_CACHE=1
SQLITE_USE_ALLOCA=1
SQLITE_THREADSAFE=2
)
# Disable warnings for third-party code
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(sqlite3 PRIVATE -w)
elseif(MSVC)
target_compile_options(sqlite3 PRIVATE /w)
endif()
endif()
endif()
# Protocol Buffers (optional, for manifest serialization)
find_package(Protobuf QUIET)
if(Protobuf_FOUND)
message(STATUS "Found Protobuf: ${Protobuf_VERSION}")
# Find Abseil (required by modern Protocol Buffers)
find_package(absl QUIET)
if(absl_FOUND)
message(STATUS "Found Abseil for Protocol Buffers")
else()
# Try to find Abseil through pkg-config
find_package(PkgConfig QUIET)
if(PkgConfig_FOUND)
pkg_check_modules(ABSL absl_base absl_strings absl_log absl_log_internal)
if(ABSL_FOUND)
message(STATUS "Found Abseil via pkg-config")
endif()
endif()
endif()
else()
message(STATUS "Protobuf not found, using custom serialization")
endif()
# Create core library
add_library(yams_core INTERFACE)
target_include_directories(yams_core INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
target_compile_features(yams_core INTERFACE cxx_std_20)
add_library(yams::core ALIAS yams_core)
# Add subdirectories
add_subdirectory(src)
if(YAMS_BUILD_TESTS)
enable_testing()
# Use FetchContent for GTest due to Conan config issues
if(YAMS_USE_FETCHCONTENT_FOR_TESTS OR NOT YAMS_USE_CONAN)
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.14.0
GIT_SHALLOW TRUE
)
# Prevent overriding the parent project's compiler/linker settings on Windows
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
endif()
add_subdirectory(tests)
endif()
# CTest is included for test discovery
include(CTest)
# Build tools based on options
if(YAMS_BUILD_CLI OR YAMS_BUILD_MCP_SERVER OR YAMS_BUILD_MAINTENANCE_TOOLS)
add_subdirectory(tools)
endif()
# Installation
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
# ---------------------------------------------------------------------------
# RPATH best practices (for installed targets on macOS/Linux)
# ---------------------------------------------------------------------------
# Use build RPATH so binaries run from the build tree
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
# Add install directories to the install RPATH
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
# macOS specific
if(APPLE)
set(CMAKE_MACOSX_RPATH ON)
endif()
# If the install libdir isn't a system dir, add it to the install RPATH
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_LIBDIR}" _isSys)
if(_isSys EQUAL -1)
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
endif()
# ---------------------------------------------------------------------------
# Uninstall target (uses install_manifest.txt generated by "make install")
# ---------------------------------------------------------------------------
set(UNINSTALL_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
file(WRITE "${UNINSTALL_SCRIPT}" "if(NOT EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\")\n message(FATAL_ERROR \"Cannot find install manifest: ${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\")\nendif()\nfile(READ \"${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\" _files)\nstring(REPLACE \"\\n\" \";\" _files \"${_files}\")\nforeach(_file IN LISTS _files)\n if(_file STREQUAL \"\")\n continue()\n endif()\n if(EXISTS \"${_file}\" OR IS_SYMLINK \"${_file}\")\n file(REMOVE \"${_file}\")\n endif()\nendforeach()\n")
if(NOT TARGET uninstall)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P "${UNINSTALL_SCRIPT}"
COMMENT "Removing installed files listed in install_manifest.txt"
)
endif()
# Package config (install location configurable)
# Export targets
set(YAMS_EXPORT_TARGETS yams_core yams_indexing)
# Always export lzma_sdk since we always build it
if(TARGET lzma_sdk)
list(APPEND YAMS_EXPORT_TARGETS lzma_sdk)
endif()
# Only export sqlite3 if we built it (non-Conan)
if(NOT YAMS_USE_CONAN)
if(TARGET sqlite3)
list(APPEND YAMS_EXPORT_TARGETS sqlite3)
endif()
endif()
install(TARGETS ${YAMS_EXPORT_TARGETS}
EXPORT YamsTargets
)
install(EXPORT YamsTargets
FILE YamsTargets.cmake
NAMESPACE yams::
DESTINATION ${YAMS_CMAKE_PACKAGE_DIR}
)
# Install headers
install(DIRECTORY include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
COMPONENT development
)
# CPack configuration for creating packages
set(CPACK_PACKAGE_NAME "YAMS")
set(CPACK_PACKAGE_VENDOR "YAMS Project")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Yet Another Memory System - High-performance content-addressed storage")
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
# Components
set(CPACK_COMPONENTS_ALL runtime maintenance development)
set(CPACK_COMPONENT_RUNTIME_DISPLAY_NAME "Runtime")
set(CPACK_COMPONENT_RUNTIME_DESCRIPTION "YAMS CLI and MCP server")
set(CPACK_COMPONENT_MAINTENANCE_DISPLAY_NAME "Maintenance Tools")
set(CPACK_COMPONENT_MAINTENANCE_DESCRIPTION "Garbage collection and statistics tools")
set(CPACK_COMPONENT_DEVELOPMENT_DISPLAY_NAME "Development")
set(CPACK_COMPONENT_DEVELOPMENT_DESCRIPTION "Headers and libraries for development")
# Package generation
if(YAMS_BUILD_PROFILE STREQUAL "release")
set(CPACK_COMPONENTS_ALL runtime)
endif()
include(CPack)
# Create package config
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/YamsConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/YamsConfig.cmake"
INSTALL_DESTINATION ${YAMS_CMAKE_PACKAGE_DIR}
)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/YamsConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/YamsConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/YamsConfigVersion.cmake"
DESTINATION ${YAMS_CMAKE_PACKAGE_DIR}
)
# Coverage targets
if(YAMS_ENABLE_COVERAGE)
# Create coverage directory
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/coverage)
# Coverage target using gcovr (preferred)
if(GCOVR_PATH)
add_custom_target(coverage-html
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/coverage/html
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/coverage/html
COMMAND ${GCOVR_PATH} --root ${CMAKE_SOURCE_DIR}
--exclude ${CMAKE_SOURCE_DIR}/tests/
--exclude ${CMAKE_SOURCE_DIR}/_deps/
--exclude ${CMAKE_SOURCE_DIR}/build/
--html --html-details
--output ${CMAKE_BINARY_DIR}/coverage/html/index.html
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Generating coverage HTML report with gcovr"
)
add_custom_target(coverage-xml
COMMAND ${GCOVR_PATH} --root ${CMAKE_SOURCE_DIR}
--exclude ${CMAKE_SOURCE_DIR}/tests/
--exclude ${CMAKE_SOURCE_DIR}/_deps/
--exclude ${CMAKE_SOURCE_DIR}/build/
--xml --output ${CMAKE_BINARY_DIR}/coverage/coverage.xml
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Generating coverage XML report with gcovr"
)
add_custom_target(coverage-summary
COMMAND ${GCOVR_PATH} --root ${CMAKE_SOURCE_DIR}
--exclude ${CMAKE_SOURCE_DIR}/tests/
--exclude ${CMAKE_SOURCE_DIR}/_deps/
--exclude ${CMAKE_SOURCE_DIR}/build/
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Displaying coverage summary"
)
# Coverage target using lcov (alternative)
elseif(LCOV_PATH AND GENHTML_PATH)
add_custom_target(coverage-html
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/coverage/html
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/coverage/html
COMMAND ${LCOV_PATH} --capture --directory ${CMAKE_BINARY_DIR}
--output-file ${CMAKE_BINARY_DIR}/coverage/coverage.info
COMMAND ${LCOV_PATH} --remove ${CMAKE_BINARY_DIR}/coverage/coverage.info
'${CMAKE_SOURCE_DIR}/tests/*'
'${CMAKE_SOURCE_DIR}/_deps/*'
'${CMAKE_SOURCE_DIR}/build/*'
'/usr/*' '/opt/*'
--output-file ${CMAKE_BINARY_DIR}/coverage/coverage.info
COMMAND ${GENHTML_PATH} ${CMAKE_BINARY_DIR}/coverage/coverage.info
--output-directory ${CMAKE_BINARY_DIR}/coverage/html
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Generating coverage HTML report with lcov"
)
add_custom_target(coverage-summary
COMMAND ${LCOV_PATH} --summary ${CMAKE_BINARY_DIR}/coverage/coverage.info
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Displaying coverage summary"
)
endif()
# Combined coverage target that runs tests first
if(TARGET coverage-html)
add_custom_target(coverage
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target all
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target coverage-html
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Running tests and generating coverage report"
)
endif()
endif()
# CPack configuration
set(CPACK_PACKAGE_VENDOR "YAMS Project")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${PROJECT_DESCRIPTION})
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
include(CPack)
# Generate and install CMake package config for find_package(Yams)
include(CMakePackageConfigHelpers)
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/YamsConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/YamsConfig.cmake"
INSTALL_DESTINATION ${YAMS_CMAKE_PACKAGE_DIR}
)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/YamsConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/YamsConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/YamsConfigVersion.cmake"
DESTINATION ${YAMS_CMAKE_PACKAGE_DIR}
)