From ad4f309825ce43d35894807e2828d1d2946e9fb0 Mon Sep 17 00:00:00 2001 From: Tanner Kvarfordt Date: Mon, 18 Jul 2022 23:31:50 -0600 Subject: [PATCH] Added installation instructions --- CMakeLists.txt | 130 +++++++++++++++++++------------ README.md | 22 ++++-- cmake/concurrencyConfig.cmake.in | 4 + tools/install.sh | 44 +++++++++++ 4 files changed, 145 insertions(+), 55 deletions(-) create mode 100644 cmake/concurrencyConfig.cmake.in create mode 100755 tools/install.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 557cbce..535eefd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,12 @@ # ------------------------------ Setup ------------------------------- # cmake_minimum_required(VERSION 3.16.3) -project(concurrency) +project(concurrency VERSION 0.0.1 + DESCRIPTION "Sharded, thread-safe implementations of STL containers." + HOMEPAGE_URL "https://github.com/TannerKvarfordt/Concurrency") + set(CMAKE_CXX_STANDARD 17) option(CodeCoverage "CodeCoverage" OFF) +option(INSTALL "Set up to install the library headers on the system. The target path for installation can be set by setting the CMAKE_INSTALL_PREFIX variable." OFF) set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules/) if(NOT CMAKE_BUILD_TYPE) @@ -29,55 +33,85 @@ else() endif() # ----------------------------- Library ------------------------------ # -add_library(${CMAKE_PROJECT_NAME} INTERFACE) -set(header_files - include/concurrency/UnorderedMap.hpp - include/concurrency/ShardedUnorderedMap.hpp) -target_sources(${CMAKE_PROJECT_NAME} INTERFACE ${header_files}) -target_include_directories(${CMAKE_PROJECT_NAME} INTERFACE include/) - - -# -------------------------- Build Examples -------------------------- # -set("SIMPLE_EXAMPLE_SRC" - examples/simple/main.cpp -) -add_executable(${CMAKE_PROJECT_NAME}_simple_example ${SIMPLE_EXAMPLE_SRC}) -target_link_libraries(${CMAKE_PROJECT_NAME}_simple_example PRIVATE ${CMAKE_PROJECT_NAME}) +if(INSTALL MATCHES ON) + include(GNUInstallDirs) + add_library(${CMAKE_PROJECT_NAME} INTERFACE) + target_include_directories(${CMAKE_PROJECT_NAME} INTERFACE $ $) + target_compile_features(${CMAKE_PROJECT_NAME} INTERFACE cxx_std_17) + + target_sources(${CMAKE_PROJECT_NAME} + INTERFACE + $ + $ + $ + $) + + install(TARGETS ${CMAKE_PROJECT_NAME} + EXPORT ${PROJECT_NAME}_Targets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + + include(CMakePackageConfigHelpers) + write_basic_package_version_file("concurrencyConfigVersion.cmake" VERSION ${PROJECT_VERSION} COMPATIBILITY SameMajorVersion) + configure_package_config_file( + "${PROJECT_SOURCE_DIR}/cmake/concurrencyConfig.cmake.in" + "${PROJECT_BINARY_DIR}/concurrencyConfig.cmake" + INSTALL_DESTINATION + ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) + + install(EXPORT ${PROJECT_NAME}_Targets + FILE ${PROJECT_NAME}Targets.cmake + NAMESPACE ${PROJECT_NAME}:: + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) + + install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) + + install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME} DESTINATION include) +else() + include_directories(include) + # -------------------------- Build Examples -------------------------- # + set("SIMPLE_EXAMPLE_SRC" + examples/simple/main.cpp + ) + add_executable(${CMAKE_PROJECT_NAME}_simple_example ${SIMPLE_EXAMPLE_SRC}) -set("MAP_BENCHMARK_SRC" - examples/map_benchmark/main.cpp - examples/map_benchmark/Benchmark.cpp -) -find_package(Threads REQUIRED) -add_executable(${CMAKE_PROJECT_NAME}_map_benchmark ${MAP_BENCHMARK_SRC}) -target_include_directories(${CMAKE_PROJECT_NAME}_map_benchmark PRIVATE benchmark examples/map_benchmark) -target_link_libraries(${CMAKE_PROJECT_NAME}_map_benchmark PRIVATE Threads::Threads) -target_link_libraries(${CMAKE_PROJECT_NAME}_map_benchmark PRIVATE ${CMAKE_PROJECT_NAME}) + set("MAP_BENCHMARK_SRC" + examples/map_benchmark/main.cpp + examples/map_benchmark/Benchmark.cpp + ) + find_package(Threads REQUIRED) + add_executable(${CMAKE_PROJECT_NAME}_map_benchmark ${MAP_BENCHMARK_SRC}) + target_include_directories(${CMAKE_PROJECT_NAME}_map_benchmark PRIVATE benchmark examples/map_benchmark) + target_link_libraries(${CMAKE_PROJECT_NAME}_map_benchmark PRIVATE Threads::Threads) -# --------------------------- Build Tests ---------------------------- # -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip -) -IF (WIN32) - set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -ENDIF() -FetchContent_MakeAvailable(googletest) -set("TEST_SRC" - tests/UnorderedConcurrentMapTests.cpp -) -enable_testing() -add_executable(${CMAKE_PROJECT_NAME}_test ${TEST_SRC}) -target_link_libraries(${CMAKE_PROJECT_NAME}_test PRIVATE gtest_main) -target_link_libraries(${CMAKE_PROJECT_NAME}_test PRIVATE ${CMAKE_PROJECT_NAME}) -include(GoogleTest) -gtest_discover_tests(${CMAKE_PROJECT_NAME}_test) + # --------------------------- Build Tests ---------------------------- # + include(FetchContent) + FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip + ) + IF (WIN32) + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + ENDIF() + FetchContent_MakeAvailable(googletest) + set("TEST_SRC" + tests/UnorderedConcurrentMapTests.cpp + ) + enable_testing() + add_executable(${CMAKE_PROJECT_NAME}_test ${TEST_SRC}) + target_link_libraries(${CMAKE_PROJECT_NAME}_test PRIVATE gtest_main) + include(GoogleTest) + gtest_discover_tests(${CMAKE_PROJECT_NAME}_test) -# -------------------------- Code Coverage --------------------------- # -if (CMAKE_BUILD_TYPE MATCHES Debug) - if (CodeCoverage MATCHES ON) - include(CodeCoverage) - setup_target_for_coverage(${PROJECT_NAME}_coverage ${CMAKE_PROJECT_NAME}_test coverage --gtest_output=xml:coverage.junit.xml) + # -------------------------- Code Coverage --------------------------- # + if (CMAKE_BUILD_TYPE MATCHES Debug) + if (CodeCoverage MATCHES ON) + include(CodeCoverage) + setup_target_for_coverage(${PROJECT_NAME}_coverage ${CMAKE_PROJECT_NAME}_test coverage --gtest_output=xml:coverage.junit.xml) + endif() endif() endif() + diff --git a/README.md b/README.md index ee001cc..3bbd6c8 100644 --- a/README.md +++ b/README.md @@ -6,18 +6,26 @@ This project provides thread-safe wrappers around C++ standard library container some exceptions have to be made to remove footguns in the context of concurrent access. Notably, iterator access is not supported for most wrappers. -## [`std::unordered_map`](https://en.cppreference.com/w/cpp/container/unordered_map) +## Installation -The following wrappers around `std::unordered_map` are provided. +**NOTE** - This library requires C++17. -### [`::concurrency::UnorderedMap`](include/concurrency/UnorderedMap.hpp) +This is a header-only library. There are several ways to make use of the provided headers. -`::concurrency::UnorderedMap` is a simple wrapper around `std::unordered_map` which -allows thread-safe access via an internal [`std::shared_mutex`](https://en.cppreference.com/w/cpp/thread/shared_mutex). +- [`./tools/install.sh`](./tools/install.sh). Invoke this script, optionally providing an installation directory with the `-p` option. +- Alternatively, simply copy the contents of `include/` to your system. + +Either way, you'll have to make sure that the location of the headers is known your build environment. At that point, you +can include the headers as you would any others. + +## Container Wrappers -### [`::concurrency::ShardedUnorderedMap`](include/concurrency/ShardedUnorderedMap.hpp) +### [`std::unordered_map`](https://en.cppreference.com/w/cpp/container/unordered_map) + +[`::concurrency::UnorderedMap`](include/concurrency/UnorderedMap.hpp) is a simple wrapper around `std::unordered_map` which +allows thread-safe access via an internal [`std::shared_mutex`](https://en.cppreference.com/w/cpp/thread/shared_mutex). -`::concurrency::ShardedUnorderedMap` provides the same interfaces as `::concurrency::UnorderedMap`, but employs sharding in an effort to improve +[`::concurrency::ShardedUnorderedMap`](include/concurrency/ShardedUnorderedMap.hpp) provides the same interfaces as `::concurrency::UnorderedMap`, but employs sharding in an effort to improve write-access performance. By splitting the underlying data into multiple `::concurrency::UnorderedMap`s, multiple threads may obtain write access at once, provided the respective keys they are accessing are stored in different shards. See the [map_benchmark example](examples/map_benchmark/) for performance metrics. diff --git a/cmake/concurrencyConfig.cmake.in b/cmake/concurrencyConfig.cmake.in new file mode 100644 index 0000000..ff0fa67 --- /dev/null +++ b/cmake/concurrencyConfig.cmake.in @@ -0,0 +1,4 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +check_required_components("@PROJECT_NAME@") \ No newline at end of file diff --git a/tools/install.sh b/tools/install.sh new file mode 100755 index 0000000..737a2d8 --- /dev/null +++ b/tools/install.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -e + +function usage() { + echo "${0}" + echo + echo "Usage" + echo " ${0} [-h] [-p]" + echo + echo "Options" + echo " -h Prints this usage" + echo " -p INSTALL_PREFIX Sets the target path for installation. If unspecified, uses the system default." +} + +INSTALL_PREFIX="" +while getopts ":hp:" opt; do + case "${opt}" in + p) + INSTALL_PREFIX="${OPTARG}" + ;; + h) + usage + exit 0 + ;; + *) + usage + exit 1 + ;; + esac +done +shift $((OPTIND - 1)) + +if [[ -n "${INSTALL_PREFIX}" ]] && ! [[ -d "${INSTALL_PREFIX}" ]]; then + echo "No such directory: ${INSTALL_PREFIX}" + exit 1 +fi + +mkdir -p "$(dirname "${BASH_SOURCE[0]}")/../build" +pushd "$(dirname "${BASH_SOURCE[0]}")/../build" >/dev/null +rm -rf ./* # Start from clean slate +cmake .. "-DCMAKE_INSTALL_PREFIX:PATH=${INSTALL_PREFIX}" -DINSTALL=ON +cmake --build . --config Release --target install -- -j "$(nproc)" +rm -rf ./* # Clean up build files +popd >/dev/null