From c07609fa489aa6000d26e2aa6276608b9154d518 Mon Sep 17 00:00:00 2001 From: Liss Heidrich <31625940+Clueliss@users.noreply.github.com> Date: Tue, 14 Nov 2023 10:03:55 +0100 Subject: [PATCH] Feature: conan2 (#14) --- .github/workflows/ci.yml | 166 +++++++++--------- .../publish-conan-branch-package.yml | 4 +- .github/workflows/publish-release.yml | 4 +- .gitignore | 67 +------ CMakeLists.txt | 41 +++-- cmake/boilerplate_init.cmake | 19 +- cmake/conan_cmake.cmake | 26 +++ cmake/install_interface_library.cmake | 1 - conanfile.py | 31 ++-- .../dice/sparse-map/boost_offset_pointer.hpp | 3 + include/dice/sparse-map/sparse_hash.hpp | 3 +- test_package/conanfile.py | 14 +- tests/CMakeLists.txt | 17 +- 13 files changed, 196 insertions(+), 200 deletions(-) create mode 100644 cmake/conan_cmake.cmake diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b2742fa..5f9b0d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,6 @@ name: CI -on: [push, pull_request, release] +on: [pull_request] jobs: build: @@ -8,97 +8,89 @@ jobs: fail-fast: false matrix: config: - - { - name: linux-x64-clang-9, - os: ubuntu-18.04, - cxx: clang++-9, - cmake-build-type: Release - } - - { - name: macos-x64-gcc, - os: macos-10.15, - cxx: g++, - cmake-build-type: Release - } - - { - name: macos-x64-clang, - os: macos-10.15, - cxx: clang++, - cmake-build-type: Release - } - - { - name: linux-x64-clang-12-sanitize, - os: ubuntu-20.04, - cxx: clang++-12, - cxx-flags: "-fsanitize=address,undefined", - cmake-build-type: Release - } - - { - name: linux-x64-gcc-10-coverage, - os: ubuntu-20.04, - cxx: g++-10, - cxx-flags: --coverage, - gcov-tool: gcov-10, - cmake-build-type: Debug - } - - { - name: linux-x64-clang-11, - os: ubuntu-20.04, - cxx: clang++-11, - cmake-build-type: Release - } - - { - name: linux-x64-clang-12, - os: ubuntu-22.04, - cxx: clang++-12, - cmake-build-type: Release - } - - { - name: linux-x64-clang-13, - os: ubuntu-22.04, - cxx: clang++-13, - cmake-build-type: Release - } - - { - name: linux-x64-clang-14, - os: ubuntu-22.04, - cxx: clang++-14, - cmake-build-type: Release - } - - { - name: linux-x64-gcc-11, - os: ubuntu-22.04, - cxx: g++-11, - cmake-build-type: Release - } + - name: linux-x64-clang-15 + os: ubuntu-22.04 + cxx: clang++-15 + - name: linux-x64-clang-16-sanitize + os: ubuntu-20.04 + cxx: clang++-16 + cxx-flags: "-fsanitize=address,undefined" + + - name: linux-x64-gcc-12 + os: ubuntu-22.04 + cxx: g++-12 + - name: linux-x64-gcc-13-coverage + os: ubuntu-22.04 + cxx: g++-13 + cxx-flags: -Werror --coverage + gcov-tool: gcov-10 + name: ${{matrix.config.name}} runs-on: ${{matrix.config.os}} steps: - - uses: actions/checkout@v2 + # setup env + - name: Add repos for for gcc-13 and clang-16 + run: | + # gcc-13 + sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y + + # clang-16 + source /etc/os-release + echo "deb http://apt.llvm.org/${UBUNTU_CODENAME}/ llvm-toolchain-${UBUNTU_CODENAME}-16 main" | sudo tee /etc/apt/sources.list.d/llvm-16.list + curl https://apt.llvm.org/llvm-snapshot.gpg.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/llvm-16.gpg > /dev/null + + - name: Install tools + run: | + sudo apt-get install -y python3 python3-pip + + - name: Get minimum cmake version + uses: lukka/get-cmake@v3.24.3 + with: + cmakeVersion: 3.22.6 + + - name: Install compiler + id: install_cc + uses: rlalik/setup-cpp-compiler@v1.2 + with: + compiler: ${{ matrix.config.cxx }} + + - name: Install mold + uses: rui314/setup-mold@v1 + + - name: Configure conan + run: | + pip3 install "conan==1.60.1" + conan profile new --detect default + conan profile update settings.compiler.libcxx=libstdc++11 default + + - name: Cache conan data + id: cache-conan + uses: actions/cache@v3 + with: + path: ~/.conan/data + key: ${{ matrix.config.os }}-${{ matrix.config.cxx }}-conan - # Linux or macOS - - name: Install boost (Linux or macOS) - run: vcpkg install boost-test boost-container boost-interprocess - if: runner.os == 'Linux' || runner.os == 'macOS' + - name: Check out sources + uses: actions/checkout@v3 - - name: Configure CMake (Linux or macOS) - run: cmake -DCMAKE_BUILD_TYPE=${{matrix.config.cmake-build-type}} -DCMAKE_TOOLCHAIN_FILE="$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" -S ${{github.workspace}}/tests -B ${{github.workspace}}/build - env: - CXX: ${{matrix.config.cxx}} - CXXFLAGS: ${{matrix.config.cxx-flags}} - if: runner.os == 'Linux' || runner.os == 'macOS' + - name: Configure CMake + env: + CC: ${{ steps.install_cc.outputs.cc }} + CXX: ${{ steps.install_cc.outputs.cxx }} + CXXFLAGS: ${{ matrix.config.cxx-flags }} + run: cmake -B build_dir -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON - - name: Build (Linux or macOS) - run: cmake --build ${{github.workspace}}/build --verbose - if: runner.os == 'Linux' || runner.os == 'macOS' + - name: Build + working-directory: build_dir + run: cmake --build . --parallel 2 - - name: Test (Linux or macOS) - run: ${{github.workspace}}/build/tsl_sparse_map_tests - if: runner.os == 'Linux' || runner.os == 'macOS' + - name: Run tests + working-directory: build_dir + run: ctest --parallel 2 --verbose - - name: Coverage - run: | - sudo apt-get install -y lcov - lcov -c -b ${{github.workspace}}/include -d ${{github.workspace}}/build -o ${{github.workspace}}/coverage.info --no-external --gcov-tool ${{matrix.config.gcov-tool}} - bash <(curl -s https://codecov.io/bash) -f ${{github.workspace}}/coverage.info - if: ${{matrix.config.name == 'linux-x64-gcc-10-coverage'}} + #- name: Coverage + # run: | + # sudo apt-get install -y lcov + # lcov -c -b ${{github.workspace}}/include -d ${{github.workspace}}/build -o ${{github.workspace}}/coverage.info --no-external --gcov-tool ${{matrix.config.gcov-tool}} + # bash <(curl -s https://codecov.io/bash) -f ${{github.workspace}}/coverage.info + # if: ${{matrix.config.name == 'linux-x64-gcc-13-coverage'}} diff --git a/.github/workflows/publish-conan-branch-package.yml b/.github/workflows/publish-conan-branch-package.yml index 8b43077..2d3b693 100644 --- a/.github/workflows/publish-conan-branch-package.yml +++ b/.github/workflows/publish-conan-branch-package.yml @@ -7,14 +7,14 @@ concurrency: cancel-in-progress: true jobs: - publish-release: + publish-conan-branch-package: uses: dice-group/cpp-conan-release-reusable-workflow/.github/workflows/publish-conan-branch-package.yml@main with: public_artifactory: true os: ubuntu-22.04 compiler: clang-14 cmake-version: 3.22.6 - conan-version: 1.59 + conan-version: 2.0.13 secrets: CONAN_USER: ${{ secrets.CONAN_USER }} CONAN_PW: ${{ secrets.CONAN_PW }} diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index ae225b7..34d9790 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -12,14 +12,14 @@ concurrency: group: publish-release-${{ github.workflow }}-${{ github.ref }} jobs: - publish-conan-branch-package: + publish-release: uses: dice-group/cpp-conan-release-reusable-workflow/.github/workflows/publish-release.yml@main with: public_artifactory: true os: ubuntu-22.04 compiler: clang-14 cmake-version: 3.22.6 - conan-version: 1.59 + conan-version: 2.0.13 secrets: CONAN_USER: ${{ secrets.CONAN_USER }} CONAN_PW: ${{ secrets.CONAN_PW }} diff --git a/.gitignore b/.gitignore index df56dfa..e6eb29e 100644 --- a/.gitignore +++ b/.gitignore @@ -75,55 +75,9 @@ deactivate_run.sh environment_run.ps1.env environment_run.sh.env -### Intellij+all ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# AWS User-specific -.idea/**/aws.xml - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr - # CMake cmake-build-*/ -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - # File-based project format *.iws @@ -148,23 +102,12 @@ crashlytics.properties crashlytics-build.properties fabric.properties -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser - -### Intellij+all Patch ### -# Ignore everything but code style settings and run configurations -# that are supposed to be shared within teams. - -.idea/* - -!.idea/codeStyles -!.idea/runConfigurations - ### Ninja ### .ninja_deps .ninja_log -# End of https://www.toptal.com/developers/gitignore/api/c++,ninja,cmake,intellij+all,conan \ No newline at end of file +# End of https://www.toptal.com/developers/gitignore/api/c++,ninja,cmake,intellij+all,conan + +.idea/ +test_package/build/ +test_package/CMakeUserPresets.json diff --git a/CMakeLists.txt b/CMakeLists.txt index 151bc84..68383c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.18) +cmake_minimum_required(VERSION 3.22) project(dice-sparse-map VERSION 0.2.4 DESCRIPTION "C++ implementation of a memory efficient hash map and hash set based on [tsl::sparse_map](https://github.com/Tessil/sparse-map). We added support for fancy pointers.") @@ -6,28 +6,43 @@ project(dice-sparse-map include(cmake/boilerplate_init.cmake) boilerplate_init() -find_package(Boost REQUIRED) +option(USE_CONAN "Use conan to fetch dependencies" ON) +option(BUILD_TESTING "Build tests" OFF) + +if (PROJECT_IS_TOP_LEVEL AND USE_CONAN) + include(cmake/conan_cmake.cmake) + + if (BUILD_TESTING) + set(CONAN_OPTIONS "with_test_deps=True") + endif () + + install_packages_via_conan("${CMAKE_SOURCE_DIR}/conanfile.py" "${CONAN_OPTIONS}") +endif () add_library(${PROJECT_NAME} INTERFACE) # Use dice::sparse_map as target, more consistent with other libraries conventions (Boost, Qt, ...) -add_library("${PROJECT_NAME}::${PROJECT_NAME}" ALIAS "${PROJECT_NAME}") +add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) target_include_directories(${PROJECT_NAME} - INTERFACE "$") - -target_link_libraries(${PROJECT_NAME} INTERFACE - Boost::headers + INTERFACE + "$" ) if(MSVC) - target_sources(${PROJECT_NAME} INTERFACE - "$" - "$") + target_sources(${PROJECT_NAME} + INTERFACE + "$" + "$") endif() -if (IS_TOP_LEVEL) +if (PROJECT_IS_TOP_LEVEL AND BUILD_TESTING) + message("Tests are configured to be build.") + include(CTest) + enable_testing() + add_subdirectory(tests) +endif () + +if (PROJECT_IS_TOP_LEVEL) include(cmake/install_interface_library.cmake) install_interface_library("${PROJECT_NAME}" "${PROJECT_NAME}" "${PROJECT_NAME}" "include") endif () - - diff --git a/cmake/boilerplate_init.cmake b/cmake/boilerplate_init.cmake index 4c513dc..9807ef9 100644 --- a/cmake/boilerplate_init.cmake +++ b/cmake/boilerplate_init.cmake @@ -4,11 +4,17 @@ macro(boilerplate_init) set(CMAKE_CXX_EXTENSIONS OFF) ## C++ compiler flags - if (MSVC) + if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Wall") else () - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wold-style-cast -Wcast-qual") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0") + + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + # -Wdangling-reference seems to have false positives atm + # We run sanitizers in the CI anyway, so should be fine + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-dangling-reference") + endif () endif () ## C++ language visibility configuration @@ -18,5 +24,12 @@ macro(boilerplate_init) set(CMAKE_VISIBILITY_INLINES_HIDDEN NO) endif () + # conan requires cmake build type to be specified and it is generally a good idea + if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/CMakeCache.txt) + if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE) + endif () + endif () + string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}" IS_TOP_LEVEL) -endmacro() +endmacro() \ No newline at end of file diff --git a/cmake/conan_cmake.cmake b/cmake/conan_cmake.cmake new file mode 100644 index 0000000..391adab --- /dev/null +++ b/cmake/conan_cmake.cmake @@ -0,0 +1,26 @@ +macro(install_packages_via_conan conanfile conan_options) + + list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR}) + list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR}) + + + if (NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake") + message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan") + file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/0.18.1/conan.cmake" + "${CMAKE_BINARY_DIR}/conan.cmake" + TLS_VERIFY ON) + endif () + include(${CMAKE_BINARY_DIR}/conan.cmake) + + conan_cmake_autodetect(settings) + conan_check(VERSION 1 DETECT_QUIET) + if (CONAN_CMD) + conan_cmake_install(PATH_OR_REFERENCE ${conanfile} + BUILD missing + SETTINGS ${settings} + OPTIONS "${conan_options}" + ENV_HOST "CC=${CMAKE_C_COMPILER};CXX=${CMAKE_CXX_COMPILER}") + else () + message(WARNING "No conan executable was found. Dependency retrieval via conan is disabled. System dependencies will be used if available.") + endif () +endmacro() \ No newline at end of file diff --git a/cmake/install_interface_library.cmake b/cmake/install_interface_library.cmake index d30a6c5..107b201 100644 --- a/cmake/install_interface_library.cmake +++ b/cmake/install_interface_library.cmake @@ -2,7 +2,6 @@ include(GNUInstallDirs) include(CMakePackageConfigHelpers) function(install_interface_library TARGET_NAME NAMESPACE LIBRARY_NAME INCLUDE_PATH) - target_include_directories( ${TARGET_NAME} INTERFACE $) diff --git a/conanfile.py b/conanfile.py index 96e4cba..02d0a71 100644 --- a/conanfile.py +++ b/conanfile.py @@ -2,19 +2,24 @@ import re from conan import ConanFile -from conan.tools.cmake import CMake, cmake_layout +from conan.tools.cmake import CMake from conan.tools.files import rmdir, copy, load class Recipe(ConanFile): url = "https://github.com/dice-group/dice-sparse-map" - topics = ("c++20", "hash-map", "data-structures", "header-only", "hash-table") - + topics = "c++20", "hash-map", "data-structures", "header-only", "hash-table" settings = "os", "compiler", "build_type", "arch" exports_sources = "include/*", "CMakeLists.txt", "cmake/*", "LICENSE*" - requires = "boost/1.79.0" - generators = ("CMakeDeps", "CMakeToolchain") + package_type = "header-library" + generators = "CMakeDeps", "CMakeToolchain" no_copy_source = True + options = {"with_test_deps": [True, False]} + default_options = {"with_test_deps": False} + + def requirements(self): + if self.options.with_test_deps: + self.requires("boost/1.83.0") def set_name(self): if not hasattr(self, 'name') or self.version is None: @@ -29,18 +34,20 @@ def set_version(self): cmake_file = load(self, os.path.join(self.recipe_folder, "CMakeLists.txt")) self.description = re.search(r"project\([^)]*DESCRIPTION\s+\"([^\"]+)\"[^)]*\)", cmake_file).group(1) - def layout(self): - cmake_layout(self) - - def package_id(self): - self.info.header_only() - def package(self): cmake = CMake(self) - cmake.configure() + cmake.configure(variables={"USE_CONAN": False}) cmake.install() for dir in ("lib", "res", "share"): rmdir(self, os.path.join(self.package_folder, dir)) copy(self, "LICENSE*", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses")) + + def package_info(self): + self.cpp_info.bindirs = [] + self.cpp_info.libdirs = [] + + self.cpp_info.set_property("cmake_find_mode", "both") + self.cpp_info.set_property("cmake_target_name", "dice-sparse-map::dice-sparse-map") + self.cpp_info.set_property("cmake_file_name", "dice-sparse-map") diff --git a/include/dice/sparse-map/boost_offset_pointer.hpp b/include/dice/sparse-map/boost_offset_pointer.hpp index 41b329d..7f32907 100644 --- a/include/dice/sparse-map/boost_offset_pointer.hpp +++ b/include/dice/sparse-map/boost_offset_pointer.hpp @@ -1,6 +1,8 @@ #ifndef DICE_SPARSE_MAP_BOOST_OFFSET_POINTER_HPP #define DICE_SPARSE_MAP_BOOST_OFFSET_POINTER_HPP +#if __has_include() + #include "dice/sparse-map/sparse_hash.hpp" //needed, so the basic template is already included #include @@ -21,4 +23,5 @@ struct Remove_Const> { }; } // namespace dice +#endif // __has_include() #endif // DICE_SPARSE_MAP_BOOST_OFFSET_POINTER_HPP diff --git a/include/dice/sparse-map/sparse_hash.hpp b/include/dice/sparse-map/sparse_hash.hpp index b966305..670e953 100644 --- a/include/dice/sparse-map/sparse_hash.hpp +++ b/include/dice/sparse-map/sparse_hash.hpp @@ -40,7 +40,6 @@ #include #include "dice/sparse-map/sparse_growth_policy.hpp" -#include "boost/container/vector.hpp" #ifdef __INTEL_COMPILER #include // For _popcnt32 and _popcnt64 @@ -1105,7 +1104,7 @@ class sparse_hash : private Allocator, using sparse_buckets_allocator = typename std::allocator_traits< allocator_type>::template rebind_alloc; using sparse_buckets_container = - boost::container::vector; + std::vector; public: /** * The `operator*()` and `operator->()` methods return a const reference and diff --git a/test_package/conanfile.py b/test_package/conanfile.py index 626b7fe..b068f6e 100644 --- a/test_package/conanfile.py +++ b/test_package/conanfile.py @@ -1,7 +1,8 @@ import os -from conan.tools.cmake import CMake, CMakeToolchain -from conan.tools.layout import cmake_layout from conan import ConanFile +from conan.tools.build import can_run +from conan.tools.cmake import CMake, cmake_layout + required_conan_version = ">=1.59" @@ -10,9 +11,8 @@ class TestPackageConan(ConanFile): settings = "os", "compiler", "build_type", "arch" generators = "CMakeDeps", "CMakeToolchain" - def generate(self): - tc = CMakeToolchain(self) - tc.generate() + def requirements(self): + self.requires(self.tested_reference_str) def layout(self): cmake_layout(self) @@ -23,4 +23,6 @@ def build(self): cmake.build() def test(self): - self.run(os.path.join(self.cpp.build.bindirs[0], "example"), run_environment=True) + if can_run(self): + cmd = os.path.join(self.cpp.build.bindir, "example") + self.run(cmd, env="conanrun") diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ead0538..4fe7fb8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,4 @@ -cmake_minimum_required(VERSION 3.18) - -project(tsl_sparse_map_tests) +find_package(Boost REQUIRED) add_executable(tsl_sparse_map_tests "main.cpp" "custom_allocator_tests.cpp" @@ -23,11 +21,10 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") target_compile_options(tsl_sparse_map_tests PRIVATE /bigobj /WX /W3 /DTSL_DEBUG /UNDEBUG) endif() -# Boost::unit_test_framework -set(Boost_USE_STATIC_LIBS ON) -find_package(Boost 1.54.0 REQUIRED COMPONENTS unit_test_framework) -target_link_libraries(tsl_sparse_map_tests PRIVATE Boost::unit_test_framework) +target_link_libraries(tsl_sparse_map_tests + PRIVATE + Boost::unit_test_framework + dice-sparse-map::dice-sparse-map + ) -# dice-sparse-map::dice-sparse-map -add_subdirectory(../ ${CMAKE_CURRENT_BINARY_DIR}/Dice/sparse-map) -target_link_libraries(tsl_sparse_map_tests PRIVATE dice-sparse-map::dice-sparse-map) +add_test(NAME tsl_sparse_map_tests COMMAND tsl_sparse_map_tests)