# SPDX-License-Identifier: BSD-3-Clause # Copyright 2017-2021, Intel Corporation cmake_minimum_required(VERSION 3.3) project(pmemkv) set(PMEMKV_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) include(${PMEMKV_ROOT_DIR}/cmake/helpers.cmake) set_version(VERSION) # ----------------------------------------------------------------- # ## CMake build options # ----------------------------------------------------------------- # option(BUILD_DOC "build documentation" ON) option(BUILD_EXAMPLES "build examples" ON) option(BUILD_TESTS "build tests" ON) option(BUILD_JSON_CONFIG "build the 'libpmemkv_json_config' library" ON) option(TESTS_LONG "enable long running tests" OFF) option(TESTS_USE_FORCED_PMEM "run tests with PMEM_IS_PMEM_FORCE=1 - it speeds up tests execution on emulated pmem" OFF) option(TESTS_USE_VALGRIND "enable tests with valgrind (fail build if Valgrind not found)" ON) option(TESTS_PMEMOBJ_DRD_HELGRIND "enable test of pmemobj engines under drd and helgrind (they should only be run on PMEM)" OFF) option(TESTS_JSON "enable tests which require libpmemkv_json_config library (BUILD_JSON_CONFIG has to be ON)" ON) option(COVERAGE "enable collecting of coverage data" OFF) option(DEVELOPER_MODE "enable developer's checks" OFF) option(CHECK_CPP_STYLE "check code style of C++ sources" OFF) option(USE_ASAN "enable AddressSanitizer (debugging)" OFF) option(USE_UBSAN "enable UndefinedBehaviorSanitizer (debugging)" OFF) option(USE_CCACHE "use ccache if it is available in the system" ON) # Each engine can be enabled separately. option(ENGINE_CMAP "enable cmap engine" ON) option(ENGINE_VCMAP "enable vcmap engine" ON) option(ENGINE_VSMAP "enable vsmap engine" ON) option(ENGINE_CSMAP "enable experimental csmap engine (requires CXX_STANDARD to be set to value >= 14)" OFF) option(ENGINE_STREE "enable experimental stree engine" ON) option(ENGINE_TREE3 "enable experimental tree3 engine" OFF) option(ENGINE_RADIX "enable experimental radix engine" OFF) option(ENGINE_ROBINHOOD "enable experimental robinhood engine (requires CXX_STANDARD to be set to value >= 14)" OFF) option(ENGINE_DRAM_VCMAP "enable testing dram_vcmap engine" OFF) # ----------------------------------------------------------------- # ## Set required and useful variables # ----------------------------------------------------------------- # set(CXX_STANDARD 11 CACHE STRING "C++ language standard") set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD ${CXX_STANDARD}) # Specify and print the build type set(DEFAULT_BUILD_TYPE "RelWithDebInfo") set(predefined_build_types Debug Release RelWithDebInfo MinSizeRel) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE ${DEFAULT_BUILD_TYPE} CACHE STRING "choose the type of build (${predefined_build_types})" FORCE) message(STATUS "CMAKE_BUILD_TYPE not set, setting the default one: ${CMAKE_BUILD_TYPE}") else() message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") if(NOT CMAKE_BUILD_TYPE IN_LIST predefined_build_types) message(WARNING "Unusual build type was set, please make sure it's proper one. " "By default supported are only following: ${predefined_build_types}.") endif() endif() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PMEMKV_ROOT_DIR}/cmake) set(LIBPMEMOBJ_CPP_REQUIRED_VERSION 1.13.0) set(LIBPMEMOBJ_REQUIRED_VERSION 1.9.1) set(LIBPMEM_REQUIRED_VERSION 1.7) set(MEMKIND_REQUIRED_VERSION 1.8.0) set(RAPIDJSON_REQUIRED_VERSION 1.0.0) set(PKG_CONFIG_REQUIRES) set(DEB_DEPENDS) set(RPM_DEPENDS) set(TEST_DIR ${CMAKE_CURRENT_BINARY_DIR}/test CACHE STRING "working directory for tests") message(STATUS "TEST_DIR set to: \"${TEST_DIR}\"") # Do not treat include directories from the interfaces # of consumed Imported Targets as SYSTEM by default. set(CMAKE_NO_SYSTEM_FROM_IMPORTED 1) set(SOURCE_FILES src/libpmemkv.cc src/libpmemkv.h src/engine.cc src/engines/blackhole.cc src/engines/blackhole.h src/out.cc src/out.h src/iterator.h src/iterator.cc ) # Add each engine source separately if(ENGINE_CMAP) list(APPEND SOURCE_FILES src/engines/cmap.h src/engines/cmap.cc ) endif() if(ENGINE_CSMAP) list(APPEND SOURCE_FILES src/engines-experimental/csmap.h src/engines-experimental/csmap.cc ) endif() if(ENGINE_VCMAP) list(APPEND SOURCE_FILES src/engines/basic_vcmap.h src/engines/vcmap.h src/engines/vcmap.cc ) endif() if(ENGINE_VSMAP) list(APPEND SOURCE_FILES src/engines/vsmap.h src/engines/vsmap.cc ) endif() if(ENGINE_STREE) list(APPEND SOURCE_FILES src/engines-experimental/stree.h src/engines-experimental/stree.cc src/engines-experimental/stree/persistent_b_tree.h ) endif() if(ENGINE_TREE3) list(APPEND SOURCE_FILES src/engines-experimental/tree3.h src/engines-experimental/tree3.cc ) endif() if(ENGINE_RADIX) list(APPEND SOURCE_FILES src/engines-experimental/radix.h src/engines-experimental/radix.cc ) endif() if(ENGINE_ROBINHOOD) list(APPEND SOURCE_FILES src/engines-experimental/robinhood.h src/engines-experimental/robinhood.cc src/fast_hash.h src/fast_hash.cc ) endif() if(ENGINE_DRAM_VCMAP) list(APPEND SOURCE_FILES src/engines/basic_vcmap.h src/engines-testing/dram_vcmap.h src/engines-testing/dram_vcmap.cc ) endif() # ----------------------------------------------------------------- # ## Setup defines and check status of each engine # ----------------------------------------------------------------- # if(ENGINE_CMAP) add_definitions(-DENGINE_CMAP) message(STATUS "CMAP engine is ON") else() message(STATUS "CMAP engine is OFF") endif() if(ENGINE_CSMAP) add_definitions(-DENGINE_CSMAP) message(STATUS "CSMAP engine is ON") if(CXX_STANDARD LESS 14) message(FATAL_ERROR "CXX_STANDARD must be >= 14 if ENGINE_CSMAP is ON") endif() else() message(STATUS "CSMAP engine is OFF") endif() if(ENGINE_VCMAP) add_definitions(-DENGINE_VCMAP) message(STATUS "VCMAP engine is ON") else() message(STATUS "VCMAP engine is OFF") endif() if(ENGINE_VSMAP) add_definitions(-DENGINE_VSMAP) message(STATUS "VSMAP engine is ON") else() message(STATUS "VSMAP engine is OFF") endif() if(ENGINE_STREE) add_definitions(-DENGINE_STREE) message(STATUS "STREE engine is ON") else() message(STATUS "STREE engine is OFF") endif() if(ENGINE_TREE3) add_definitions(-DENGINE_TREE3) message(STATUS "TREE3 engine is ON") else() message(STATUS "TREE3 engine is OFF") endif() if(ENGINE_RADIX) add_definitions(-DENGINE_RADIX) message(STATUS "RADIX engine is ON") else() message(STATUS "RADIX engine is OFF") endif() if(ENGINE_ROBINHOOD) add_definitions(-DENGINE_ROBINHOOD) message(STATUS "ROBINHOOD engine is ON") if(CXX_STANDARD LESS 14) message(FATAL_ERROR "CXX_STANDARD must be >= 14 if ENGINE_ROBINHOOD is ON") endif() else() message(STATUS "ROBINHOOD engine is OFF") endif() if(ENGINE_DRAM_VCMAP) add_definitions(-DENGINE_DRAM_VCMAP) message(STATUS "DRAM_VCMAP engine is ON") else() message(STATUS "DRAM_VCMAP engine is OFF") endif() # ----------------------------------------------------------------- # ## Set compiler's flags # ----------------------------------------------------------------- # if(DEVELOPER_MODE) add_common_flag(-Werror) endif() if(USE_ASAN) add_sanitizer_flag(address) endif() if(USE_UBSAN) add_sanitizer_flag(undefined) endif() if(COVERAGE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -coverage") endif() add_common_flag(-Wall) add_common_flag(-Wpointer-arith) add_common_flag(-Wsign-compare) add_common_flag(-Wunreachable-code-return) add_common_flag(-Wmissing-variable-declarations) add_common_flag(-fno-common) add_common_flag(-Wunused-macros) add_common_flag(-Wsign-conversion) add_common_flag(-Wno-maybe-uninitialized) add_common_flag(-ggdb DEBUG) add_common_flag(-DDEBUG DEBUG) add_common_flag("-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2" RELEASE) # ----------------------------------------------------------------- # ## Setup environment, find packages, ## configure list of package dependencies # ----------------------------------------------------------------- # find_package(PkgConfig QUIET) include(FindPerl) include(ExternalProject) include(FindThreads) include(CheckCXXSourceCompiles) include(GNUInstallDirs) include(libpmemobj++) list(APPEND PKG_CONFIG_REQUIRES "libpmemobj++ >= ${LIBPMEMOBJ_CPP_REQUIRED_VERSION}") list(APPEND RPM_DEPENDS "libpmemobj >= ${LIBPMEMOBJ_REQUIRED_VERSION}") list(APPEND DEB_DEPENDS "libpmemobj1 (>= ${LIBPMEMOBJ_REQUIRED_VERSION}) | libpmemobj (>= ${LIBPMEMOBJ_REQUIRED_VERSION})") # Configure the ccache as compiler launcher find_program(CCACHE_FOUND ccache) if(USE_CCACHE AND CCACHE_FOUND) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) endif() if(ENGINE_VSMAP OR ENGINE_VCMAP) include(memkind) list(APPEND PKG_CONFIG_REQUIRES "memkind >= ${MEMKIND_REQUIRED_VERSION}") list(APPEND RPM_DEPENDS "memkind >= ${MEMKIND_REQUIRED_VERSION}") list(APPEND DEB_DEPENDS "libmemkind0 (>= ${MEMKIND_REQUIRED_VERSION})") endif() if(ENGINE_VCMAP OR ENGINE_DRAM_VCMAP) include(tbb) add_definitions(-DTBB_DEFINE_STD_HASH_SPECIALIZATIONS) list(APPEND PKG_CONFIG_REQUIRES tbb) list(APPEND RPM_DEPENDS tbb) list(APPEND DEB_DEPENDS libtbb2) endif() # ----------------------------------------------------------------- # ## Link libraries, setup targets # ----------------------------------------------------------------- # add_library(pmemkv SHARED ${SOURCE_FILES}) set_target_properties(pmemkv PROPERTIES SOVERSION 1) target_link_libraries(pmemkv PRIVATE -Wl,--version-script=${PMEMKV_ROOT_DIR}/src/libpmemkv.map) target_include_directories(pmemkv PRIVATE src/valgrind) # Enable libpmemobj-cpp valgrind annotations target_compile_options(pmemkv PRIVATE -DLIBPMEMOBJ_CPP_VG_ENABLED=1) target_link_libraries(pmemkv PRIVATE ${LIBPMEMOBJ++_LIBRARIES}) if(ENGINE_VSMAP OR ENGINE_VCMAP) target_link_libraries(pmemkv PRIVATE ${MEMKIND_LIBRARIES}) endif() if(ENGINE_VCMAP OR ENGINE_DRAM_VCMAP) target_link_libraries(pmemkv PRIVATE ${TBB_LIBRARIES}) endif() # ----------------------------------------------------------------- # ## Setup additional targets # ----------------------------------------------------------------- # add_custom_target(checkers ALL) add_custom_target(cppstyle) add_custom_target(cppformat) add_custom_target(check-whitespace) add_custom_target(check-license COMMAND ${PMEMKV_ROOT_DIR}/utils/check_license/check-headers.sh ${PMEMKV_ROOT_DIR} BSD-3-Clause) add_custom_target(copyright-format COMMAND ${PMEMKV_ROOT_DIR}/utils/check_license/check-headers.sh ${PMEMKV_ROOT_DIR} BSD-3-Clause -d) find_program(CLANG_FORMAT NAMES clang-format-9 clang-format-9.0 clang-format) set(CLANG_FORMAT_REQUIRED "9.0") if(CLANG_FORMAT) get_program_version_major_minor(${CLANG_FORMAT} CLANG_FORMAT_VERSION) message(STATUS "Found clang-format: ${CLANG_FORMAT} (version: ${CLANG_FORMAT_VERSION})") endif() if(CHECK_CPP_STYLE) if(CLANG_FORMAT) if(NOT (CLANG_FORMAT_VERSION VERSION_EQUAL CLANG_FORMAT_REQUIRED)) message(FATAL_ERROR "required clang-format version is ${CLANG_FORMAT_REQUIRED}") endif() else() message(FATAL_ERROR "CHECK_CPP_STYLE=ON, but clang-format not found (required version: ${CLANG_FORMAT_REQUIRED})") endif() add_dependencies(checkers cppstyle) endif() if(DEVELOPER_MODE) # check for required programs for whitespace and license checks and add dependencies to ALL if(NOT PERL_FOUND) message(FATAL_ERROR "Perl not found") endif() if(PERL_VERSION_STRING VERSION_LESS 5.16) message(FATAL_ERROR "Minimum required version of Perl is 5.16)") endif() execute_process(COMMAND ${PERL_EXECUTABLE} -MText::Diff -e "" ERROR_QUIET RESULT_VARIABLE PERL_TEXT_DIFF_STATUS) if(PERL_TEXT_DIFF_STATUS) message(FATAL_ERROR "Text::Diff Perl module not found (install libtext-diff-perl or perl-Text-Diff)") endif() add_dependencies(checkers check-whitespace) add_dependencies(checkers check-license) endif() add_cppstyle(src ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c* ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h* ${CMAKE_CURRENT_SOURCE_DIR}/src/comparator/*.h* ${CMAKE_CURRENT_SOURCE_DIR}/src/engines/*.c* ${CMAKE_CURRENT_SOURCE_DIR}/src/engines/*.h* ${CMAKE_CURRENT_SOURCE_DIR}/src/engines-experimental/*.c* ${CMAKE_CURRENT_SOURCE_DIR}/src/engines-experimental/*.h* ${CMAKE_CURRENT_SOURCE_DIR}/src/engines-experimental/stree/*.h*) add_check_whitespace(main ${PMEMKV_ROOT_DIR}/utils/check_whitespace ${CMAKE_CURRENT_SOURCE_DIR}/utils/check_license/*.sh ${CMAKE_CURRENT_SOURCE_DIR}/*.md) add_check_whitespace(src ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c* ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h* ${CMAKE_CURRENT_SOURCE_DIR}/src/comparator/*.h* ${CMAKE_CURRENT_SOURCE_DIR}/src/engines/*.c* ${CMAKE_CURRENT_SOURCE_DIR}/src/engines/*.h* ${CMAKE_CURRENT_SOURCE_DIR}/src/engines-experimental/*.c* ${CMAKE_CURRENT_SOURCE_DIR}/src/engines-experimental/*.h* ${CMAKE_CURRENT_SOURCE_DIR}/src/engines-experimental/stree/*.h*) # ----------------------------------------------------------------- # ## Add sub-directories if builds enabled # ----------------------------------------------------------------- # if(BUILD_JSON_CONFIG) include(rapidjson) list(APPEND PKG_CONFIG_REQUIRES "RapidJSON >= ${RAPIDJSON_REQUIRED_VERSION}") list(APPEND RPM_DEPENDS "rapidjson-devel >= ${RAPIDJSON_REQUIRED_VERSION}") list(APPEND DEB_DEPENDS "rapidjson-dev (>= ${RAPIDJSON_REQUIRED_VERSION})") add_definitions(-DBUILD_JSON_CONFIG) set(SOURCE_FILES_JSON_CONFIG src/libpmemkv_json_config.cc src/libpmemkv_json_config.h src/out.cc src/out.h ) add_library(pmemkv_json_config SHARED ${SOURCE_FILES_JSON_CONFIG}) set_target_properties(pmemkv_json_config PROPERTIES SOVERSION 1) target_link_libraries(pmemkv_json_config PRIVATE pmemkv ${RapidJSON_LIBRARIES} -Wl,--version-script=${PMEMKV_ROOT_DIR}/src/libpmemkv_json_config.map) set_target_properties(pmemkv_json_config PROPERTIES PUBLIC_HEADER "src/libpmemkv_json_config.h") configure_file(libpmemkv_json_config.pc.in libpmemkv_json_config.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpmemkv_json_config.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(TARGETS pmemkv_json_config PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() if(BUILD_EXAMPLES) add_subdirectory(examples) endif() if(BUILD_TESTS) enable_testing() add_subdirectory(tests) endif() if(BUILD_DOC) add_subdirectory(doc) endif() # ----------------------------------------------------------------- # ## Configure make install/uninstall and packages # ----------------------------------------------------------------- # string(REPLACE ";" " " PKG_CONFIG_REQUIRES "${PKG_CONFIG_REQUIRES}") string(REPLACE ";" ", " RPM_PACKAGE_REQUIRES "${RPM_DEPENDS}") string(REPLACE ";" ", " DEB_PACKAGE_REQUIRES "${DEB_DEPENDS}") configure_file(libpmemkv.pc.in libpmemkv.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpmemkv.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) set_target_properties(pmemkv PROPERTIES PUBLIC_HEADER "src/libpmemkv.h;src/libpmemkv.hpp") install(TARGETS pmemkv PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) configure_file( "${PMEMKV_ROOT_DIR}/cmake/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) if(NOT "${CPACK_GENERATOR}" STREQUAL "") include(${PMEMKV_ROOT_DIR}/cmake/packages.cmake) endif()