cmake_minimum_required(VERSION 3.18) project( versioned-map VERSION 0.0.1 DESCRIPTION "A data structure for mvcc reads on bitwise-lexicographically-ordered keys." HOMEPAGE_URL "https://git.weaselab.dev/weaselab/versioned-map" LANGUAGES C CXX) set(CMAKE_CXX_STANDARD 20) file(WRITE ${CMAKE_BINARY_DIR}/version.txt ${PROJECT_VERSION}) include(CMakePushCheckState) include(CheckCXXSourceCompiles) set(DEFAULT_BUILD_TYPE "Release") if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message( STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.") set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() add_compile_options(-fdata-sections -ffunction-sections -Wswitch-enum -Werror=switch-enum -fvisibility=hidden -fPIC) set(full_relro_flags "-pie;LINKER:-z,relro,-z,now,-z,noexecstack") cmake_push_check_state() list(APPEND CMAKE_REQUIRED_LINK_OPTIONS ${full_relro_flags}) check_cxx_source_compiles("int main(){}" HAS_FULL_RELRO FAIL_REGEX "warning:") if(HAS_FULL_RELRO) add_link_options(${full_relro_flags}) endif() cmake_pop_check_state() set(version_script_flags LINKER:--version-script=${CMAKE_SOURCE_DIR}/linker.map) cmake_push_check_state() list(APPEND CMAKE_REQUIRED_LINK_OPTIONS ${version_script_flags}) check_cxx_source_compiles("int main(){}" HAS_VERSION_SCRIPT FAIL_REGEX "warning:") cmake_pop_check_state() # This is encouraged according to # https://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.clientreq include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/third_party/valgrind) if(CMAKE_BUILD_TYPE STREQUAL Release) if(APPLE) add_link_options(-Wl,-dead_strip) else() add_link_options(-Wl,--gc-sections) endif() endif() set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "") add_subdirectory(third_party) set(SOURCES VersionedMap.cpp RootSet.cpp) add_executable(versioned_map_main ${SOURCES}) target_include_directories(versioned_map_main PRIVATE ${CMAKE_SOURCE_DIR}/include) target_link_libraries(versioned_map_main PRIVATE nanobench) target_compile_definitions(versioned_map_main PRIVATE ENABLE_MAIN) if(CMAKE_BUILD_TYPE STREQUAL "Debug") target_compile_options(versioned_map_main PRIVATE -fsanitize=address,undefined) target_link_options(versioned_map_main PRIVATE -fsanitize=address,undefined) endif() add_library(${PROJECT_NAME}-object OBJECT ${SOURCES}) target_compile_options(${PROJECT_NAME}-object PRIVATE -fno-exceptions -fno-rtti) target_include_directories(${PROJECT_NAME}-object PRIVATE ${CMAKE_SOURCE_DIR}/include) add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.o COMMAND ld -r $ -o ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.o DEPENDS $ COMMAND_EXPAND_LISTS) add_library(${PROJECT_NAME} SHARED ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.o) target_include_directories( ${PROJECT_NAME} PUBLIC $) set_target_properties( ${PROJECT_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${PROJECT_NAME}") set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE C) # Not thread-safe add_library(fdb-${PROJECT_NAME} SHARED FdbVersionedMap.cpp) target_include_directories( fdb-${PROJECT_NAME} PUBLIC $) set_target_properties(fdb-${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) set_target_properties( fdb-${PROJECT_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/fdb-${PROJECT_NAME}") if(HAS_VERSION_SCRIPT) target_link_options(${PROJECT_NAME} PRIVATE LINKER:--version-script=${CMAKE_SOURCE_DIR}/linker.map) endif() add_library(${PROJECT_NAME}-static STATIC ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.o) target_include_directories( ${PROJECT_NAME}-static PUBLIC $) set_target_properties(${PROJECT_NAME}-static PROPERTIES LINKER_LANGUAGE C) if(NOT APPLE) add_custom_command( TARGET ${PROJECT_NAME}-static POST_BUILD COMMAND ${CMAKE_OBJCOPY} --keep-global-symbols=${CMAKE_SOURCE_DIR}/symbol-exports.txt $ || echo "Proceeding with all symbols global in static library") endif() set(TEST_FLAGS -Wall -Wextra -Wunreachable-code -Wpedantic -UNDEBUG) include(CTest) option(BUILD_TREE_VIS "Build tree visualization" OFF) if(BUILD_TREE_VIS) find_package(SDL2 REQUIRED) find_package(SDL2_ttf REQUIRED) add_executable(tree_vis TreeVis.cpp) target_link_libraries(tree_vis PRIVATE SDL2::SDL2) target_link_libraries(tree_vis PRIVATE SDL2_ttf::SDL2_ttf) endif() if(BUILD_TESTING) # corpus tests, which are tests curated by libfuzzer. The goal is to get broad # coverage with a small number of tests. file(GLOB CORPUS_TESTS ${CMAKE_SOURCE_DIR}/corpus/*) if(NOT APPLE) # libfuzzer target, to generate/manage corpus set(FUZZ_FLAGS "-fsanitize=fuzzer-no-link,address,undefined") include(CheckCXXCompilerFlag) cmake_push_check_state() set(CMAKE_REQUIRED_LINK_OPTIONS -fsanitize=fuzzer-no-link) check_cxx_compiler_flag(-fsanitize=fuzzer-no-link HAS_LIB_FUZZER) cmake_pop_check_state() if(HAS_LIB_FUZZER) add_executable(facade_fuzz FacadeFuzz.cpp ${SOURCES}) target_include_directories(facade_fuzz PRIVATE ${CMAKE_SOURCE_DIR}/include) target_compile_options(facade_fuzz PRIVATE ${FUZZ_FLAGS} ${TEST_FLAGS}) target_link_options(facade_fuzz PRIVATE ${FUZZ_FLAGS} -fsanitize=fuzzer) endif() endif() add_executable(rootset_test RootSet.cpp) target_compile_definitions(rootset_test PRIVATE ENABLE_ROOTSET_TESTS) target_compile_options(rootset_test PRIVATE -fsanitize=address,undefined ${TEST_FLAGS}) target_link_options(rootset_test PRIVATE -fsanitize=address,undefined) add_test(NAME rootset_test COMMAND rootset_test) add_executable(rootset_test_tsan RootSet.cpp) target_compile_definitions(rootset_test_tsan PRIVATE ENABLE_ROOTSET_TESTS) target_compile_options(rootset_test_tsan PRIVATE -fsanitize=thread ${TEST_FLAGS}) target_link_options(rootset_test_tsan PRIVATE -fsanitize=thread) add_test(NAME rootset_test_tsan COMMAND rootset_test) add_executable(api_test ApiTest.cpp) target_link_libraries(api_test PRIVATE ${PROJECT_NAME}) target_compile_options(api_test PRIVATE -fsanitize=address,undefined ${TEST_FLAGS}) target_link_options(api_test PRIVATE -fsanitize=address,undefined) add_test(NAME api_test COMMAND api_test) add_executable(facade_test FacadeTest.cpp) target_link_libraries(facade_test PRIVATE ${PROJECT_NAME}) target_compile_options(facade_test PRIVATE -fsanitize=address,undefined ${TEST_FLAGS}) target_link_options(facade_test PRIVATE -fsanitize=address,undefined) # blackbox tests add_executable(driver TestDriver.cpp FacadeFuzz.cpp) target_compile_options(driver PRIVATE ${TEST_FLAGS}) target_link_libraries(driver PRIVATE ${PROJECT_NAME}) set_target_properties(driver PROPERTIES SKIP_BUILD_RPATH ON) add_dependencies(driver fdb-${PROJECT_NAME}) if(APPLE) set(LD_PATH DYLD_LIBRARY_PATH) else() set(LD_PATH LD_LIBRARY_PATH) endif() foreach(TEST ${CORPUS_TESTS}) get_filename_component(hash ${TEST} NAME) add_test(NAME blackbox_${hash} COMMAND driver ${TEST}) set_tests_properties( blackbox_${hash} PROPERTIES ENVIRONMENT ${LD_PATH}=${CMAKE_BINARY_DIR}/${PROJECT_NAME}) add_test(NAME fdb_blackbox_${hash} COMMAND driver ${TEST}) set_tests_properties( fdb_blackbox_${hash} PROPERTIES ENVIRONMENT ${LD_PATH}=${CMAKE_BINARY_DIR}/fdb-${PROJECT_NAME}) endforeach() # whitebox tests add_executable(whitebox_driver TestDriver.cpp FacadeFuzz.cpp ${SOURCES}) target_compile_options(whitebox_driver PRIVATE ${TEST_FLAGS}) target_include_directories(whitebox_driver PRIVATE ${CMAKE_SOURCE_DIR}/include) foreach(TEST ${CORPUS_TESTS}) get_filename_component(hash ${TEST} NAME) add_test(NAME whitebox_${hash} COMMAND whitebox_driver ${TEST}) endforeach() add_executable(bench Bench.cpp) target_link_libraries(bench PRIVATE ${PROJECT_NAME} nanobench) set_target_properties(bench PROPERTIES SKIP_BUILD_RPATH ON) # symbol visibility tests if(NOT CMAKE_BUILD_TYPE STREQUAL Debug) if(APPLE) set(symbol_exports ${CMAKE_SOURCE_DIR}/apple-symbol-exports.txt) set(symbol_imports ${CMAKE_SOURCE_DIR}/apple-symbol-imports.txt) else() set(symbol_exports ${CMAKE_SOURCE_DIR}/symbol-exports.txt) if(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64) set(symbol_imports ${CMAKE_SOURCE_DIR}/aarch64-symbol-imports.txt) else() set(symbol_imports ${CMAKE_SOURCE_DIR}/symbol-imports.txt) endif() endif() add_test( NAME shared_symbols COMMAND ${CMAKE_SOURCE_DIR}/test_symbols.sh $ ${symbol_exports} ${symbol_imports}) add_test( NAME static_symbols COMMAND ${CMAKE_SOURCE_DIR}/test_symbols.sh $ ${symbol_exports} ${symbol_imports}) endif() endif()