From d83036ae4c2bd4ba6bdddcd1cc1a06320e46b18a Mon Sep 17 00:00:00 2001 From: Matthew Johnson Date: Wed, 6 Dec 2023 17:30:54 -0500 Subject: [PATCH] switch build to conan 1.x The Conan 1.x package manager for C++ is a bit easier to work with than the Bazel system. This allows us to more easily update dependencies, to keep them in-sync with the atlas-system-agent project, which also uses Conan. The Address Sanitizer has been disabled for MacOS as a part of this change, because there were some issues with segfaults when running tests locally on the Apple silicon platform. One line of thinking is that the Address Sanitizer compiler flags are not propagating fully through the dependency tree, but we also do not see this issue on Linux. Otherwise, the project builds and the tests pass. The Address Sanitizer remains engaged for the Linux builds triggered by the Github Actions. --- .bazeliskrc | 1 - .bazelrc | 40 ----------------------- .clang-format | 3 +- .github/workflows/build.yml | 39 ++++++++++++++++------ .gitignore | 8 ++--- BUILD.bazel | 51 ----------------------------- CMakeLists.txt | 50 +++++++++++++++++++++++++++++ README.md | 12 +++++++ WORKSPACE | 5 --- bazel/BUILD | 0 bazel/abseil.patch | 42 ------------------------ build.sh | 46 ++++++++++++++++++++++++-- conanfile.py | 16 ++++++++++ dependencies.bzl | 64 ------------------------------------- requirements.txt | 1 + scripts/gen-compdb | 7 ---- setup-venv.sh | 17 ++++++++++ spectator/registry.h | 4 +-- third_party/BUILD.bazel | 0 third_party/asio.BUILD | 9 ------ third_party/backward.BUILD | 10 ------ third_party/fmtlib.BUILD | 14 -------- third_party/spdlog.BUILD | 13 -------- 23 files changed, 175 insertions(+), 277 deletions(-) delete mode 100644 .bazeliskrc delete mode 100644 .bazelrc delete mode 100644 BUILD.bazel create mode 100644 CMakeLists.txt delete mode 100644 WORKSPACE delete mode 100644 bazel/BUILD delete mode 100644 bazel/abseil.patch create mode 100644 conanfile.py delete mode 100644 dependencies.bzl create mode 100644 requirements.txt delete mode 100755 scripts/gen-compdb create mode 100755 setup-venv.sh delete mode 100644 third_party/BUILD.bazel delete mode 100644 third_party/asio.BUILD delete mode 100644 third_party/backward.BUILD delete mode 100644 third_party/fmtlib.BUILD delete mode 100644 third_party/spdlog.BUILD diff --git a/.bazeliskrc b/.bazeliskrc deleted file mode 100644 index 95447bd..0000000 --- a/.bazeliskrc +++ /dev/null @@ -1 +0,0 @@ -USE_BAZEL_VERSION=5.4.0 \ No newline at end of file diff --git a/.bazelrc b/.bazelrc deleted file mode 100644 index b51b048..0000000 --- a/.bazelrc +++ /dev/null @@ -1,40 +0,0 @@ -build --cxxopt='-std=c++17' --cxxopt='-Wall' --cxxopt='-fno-omit-frame-pointer' - -# Address sanitizer -# To use it: bazel build --config asan -build:asan --strip=never -build:asan --copt -fsanitize=address -build:asan --copt -DADDRESS_SANITIZER -build:asan --copt -O1 -build:asan --copt -g -build:asan --copt -fno-omit-frame-pointer -build:asan --linkopt -fsanitize=address - -# Thread sanitizer -# bazel build --config tsan -build:tsan --strip=never -build:tsan --copt -fsanitize=thread -build:tsan --copt -DTHREAD_SANITIZER -build:tsan --copt -DDYNAMIC_ANNOTATIONS_ENABLED=1 -build:tsan --copt -DDYNAMIC_ANNOTATIONS_EXTERNAL_IMPL=1 -build:tsan --copt -O1 -build:tsan --copt -fno-omit-frame-pointer -build:tsan --linkopt -fsanitize=thread - -# --config msan: Memory sanitizer -build:msan --strip=never -build:msan --copt -fsanitize=memory -build:msan --copt -DADDRESS_SANITIZER -build:msan --copt -O1 -build:msan --copt -fno-omit-frame-pointer -build:msan --linkopt -fsanitize=memory - -# --config ubsan: Undefined Behavior Sanitizer -build:ubsan --strip=never -build:ubsan --copt -fsanitize=undefined -build:ubsan --copt -O1 -build:ubsan --copt -fno-omit-frame-pointer -build:ubsan --linkopt -fsanitize=undefined -build:ubsan --linkopt -lubsan - -test --test_output=streamed diff --git a/.clang-format b/.clang-format index 1996112..865f732 100644 --- a/.clang-format +++ b/.clang-format @@ -21,7 +21,7 @@ BinPackArguments: true BinPackParameters: true BraceWrapping: AfterClass: false - AfterControlStatement: false + AfterControlStatement: Never AfterEnum: false AfterFunction: false AfterNamespace: false @@ -86,4 +86,3 @@ Standard: Auto TabWidth: 8 UseTab: Never ... - diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 51959c5..f80fca2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,30 +11,49 @@ jobs: if: ${{ github.repository == 'Netflix/spectator-cpp' }} runs-on: ubuntu-latest env: + BUILD_DIR: "cmake-build" CC: "gcc-11" CXX: "g++-11" LANG: "en_US.UTF-8" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - name: Bazel Cache + - name: Conan+Cmake Cache uses: actions/cache@v3 with: - path: ~/.cache/bazel - key: ${{ runner.os }}-bazel + path: | + ~/.conan + ~/work/spectatord/spectatord/cmake-build + key: ${{ runner.os }}-conan-cmake - name: Install System Dependencies run: | - curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor > bazel.gpg - sudo mv bazel.gpg /etc/apt/trusted.gpg.d/ - echo "deb [arch=amd64] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test - sudo apt-get update && sudo apt-get install -y bazel-5.4.0 binutils-dev g++-11 + sudo apt-get update && sudo apt-get install -y binutils-dev g++-11 libiberty-dev + + echo "==== cmake ====" + cmake -version + + echo "==== python ====" + python3 -V + + echo "==== conan ====" + pip install "conan==1.61.0" + conan --version + if [[ ! -f ~/.conan/profiles/default ]]; then conan profile new default --detect; fi + conan profile update settings.compiler.libcxx=libstdc++11 default + + - name: Install Project Dependencies + run: | + conan install . --build=missing --install-folder $BUILD_DIR - name: Build spectator-cpp run: | - bazel-5.4.0 --output_user_root=~/.cache/bazel --batch build --config asan spectator_test spectator + cd $BUILD_DIR + cmake .. -DCMAKE_BUILD_TYPE=Debug + cmake --build . - name: Test spectator-cpp run: | - GTEST_COLOR=1 ./bazel-bin/spectator_test + cd $BUILD_DIR + GTEST_COLOR=1 ctest --verbose diff --git a/.gitignore b/.gitignore index 54b6549..0b6bfbc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -.clwb/ +.DS_Store .idea/ -.vscode/ -bazel-* -build-* +cmake-build-debug/ +cmake-build/ +venv/ diff --git a/BUILD.bazel b/BUILD.bazel deleted file mode 100644 index 1955d40..0000000 --- a/BUILD.bazel +++ /dev/null @@ -1,51 +0,0 @@ -cc_library( - name = "spectator", - srcs = [ - "spectator/logger.cc", - "spectator/publisher.cc", - ], - hdrs = [ - "spectator/config.h", - "spectator/id.h", - "spectator/logger.h", - "spectator/measurement.h", - "spectator/meter_type.h", - "spectator/publisher.h", - "spectator/registry.h", - "spectator/stateful_meters.h", - "spectator/stateless_meters.h", - ], - visibility = ["//visibility:public"], - deps = [ - "@asio", - "@com_github_fmtlib_fmt//:fmtlib", - "@com_github_gabime_spdlog//:spdlog", - "@com_google_absl//absl/container:flat_hash_map", - "@com_google_absl//absl/strings", - ], -) - -cc_test( - name = "spectator_test", - srcs = glob([ - "spectator/*_test.cc", - "spectator/test_*.cc", - "spectator/test_*.h", - ]), - linkopts = select({ - "@bazel_tools//src/conditions:linux_x86_64": [ - "-lbfd", - "-ldl", - ], - "//conditions:default": [], - }), - local_defines = select({ - "@bazel_tools//src/conditions:linux_x86_64": ["BACKWARD_HAS_BFD=1"], - "//conditions:default": [], - }), - deps = [ - ":spectator", - "@com_github_bombela_backward//:backward", - "@com_google_googletest//:gtest", - ], -) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..8317b8a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.13) + +project(spectator) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +if(APPLE) + # Address Sanitizer is finicky on MacOS Apple Silicon, so skip it + add_compile_options(-fno-omit-frame-pointer) + add_link_options(-fno-omit-frame-pointer) +else() + add_compile_options(-fno-omit-frame-pointer "$<$:-fsanitize=address>") + add_link_options(-fno-omit-frame-pointer "$<$:-fsanitize=address>") +endif() + +include(CTest) +include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) +conan_basic_setup() + +#-- spectator_test test executable +file(GLOB spectator_test_source_files + "spectator/*_test.cc" + "spectator/test_*.cc" + "spectator/test_*.h" +) +add_executable(spectator_test ${spectator_test_source_files}) +target_link_libraries(spectator_test spectator ${CONAN_LIBS}) +add_test( + NAME spectator_test + COMMAND spectator_test + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} +) + +#-- spectator library +add_library(spectator + "spectator/logger.cc" + "spectator/publisher.cc" + "spectator/config.h" + "spectator/id.h" + "spectator/logger.h" + "spectator/measurement.h" + "spectator/meter_type.h" + "spectator/publisher.h" + "spectator/registry.h" + "spectator/stateful_meters.h" + "spectator/stateless_meters.h" +) +target_link_libraries(spectator ${CONAN_LIBS}) +target_link_options(spectator PRIVATE "$<$:-static-libstdc++>") diff --git a/README.md b/README.md index 6d5616f..5bdfc57 100644 --- a/README.md +++ b/README.md @@ -84,3 +84,15 @@ int main() { By default, the library sends every meter change to the spectatord sidecar immediately. This involves a blocking `send` call and underlying system calls, and may not be the most efficient way to publish metrics in high-volume use cases. For this purpose a simple buffering functionality in `Publisher` is implemented, and it can be turned on by passing a buffer size to the `spectator::Config` constructor. It is important to note that, until this buffer fills up, the `Publisher` will not send nay meters to the sidecar. Therefore, if your application doesn't emit meters at a high rate, you should either keep the buffer very small, or do not configure a buffer size at all, which will fall back to the "publish immediately" mode of operation. + +## Local Development + +```shell +./setup-venv.sh +source venv/bin/activate +./build.sh # [clean|skiptest] +``` + +* CLion > Preferences > Plugins > Marketplace > Conan > Install +* CLion > Preferences > Build, Execution, Deploy > Conan > Conan Executable: $PROJECT_HOME/venv/bin/conan +* CLion > Bottom Bar: Conan > Left Button: Match Profile > CMake Profile: Debug, Conan Profile: default diff --git a/WORKSPACE b/WORKSPACE deleted file mode 100644 index 3ef93e2..0000000 --- a/WORKSPACE +++ /dev/null @@ -1,5 +0,0 @@ -workspace(name = "spectator") - -load("@spectator//:dependencies.bzl", "spectator_dependencies") - -spectator_dependencies() diff --git a/bazel/BUILD b/bazel/BUILD deleted file mode 100644 index e69de29..0000000 diff --git a/bazel/abseil.patch b/bazel/abseil.patch deleted file mode 100644 index d525564..0000000 --- a/bazel/abseil.patch +++ /dev/null @@ -1,42 +0,0 @@ -# Force internal versions of std classes per -# https://abseil.io/docs/cpp/guides/options -diff --git a/absl/base/options.h b/absl/base/options.h -index 230bf1e..6e1b9e5 100644 ---- a/absl/base/options.h -+++ b/absl/base/options.h -@@ -100,7 +100,7 @@ - // User code should not inspect this macro. To check in the preprocessor if - // absl::any is a typedef of std::any, use the feature macro ABSL_USES_STD_ANY. - --#define ABSL_OPTION_USE_STD_ANY 2 -+#define ABSL_OPTION_USE_STD_ANY 0 - - - // ABSL_OPTION_USE_STD_OPTIONAL -@@ -127,7 +127,7 @@ - // absl::optional is a typedef of std::optional, use the feature macro - // ABSL_USES_STD_OPTIONAL. - --#define ABSL_OPTION_USE_STD_OPTIONAL 2 -+#define ABSL_OPTION_USE_STD_OPTIONAL 0 - - - // ABSL_OPTION_USE_STD_STRING_VIEW -@@ -154,7 +154,7 @@ - // absl::string_view is a typedef of std::string_view, use the feature macro - // ABSL_USES_STD_STRING_VIEW. - --#define ABSL_OPTION_USE_STD_STRING_VIEW 2 -+#define ABSL_OPTION_USE_STD_STRING_VIEW 0 - - // ABSL_OPTION_USE_STD_VARIANT - // -@@ -180,7 +180,7 @@ - // absl::variant is a typedef of std::variant, use the feature macro - // ABSL_USES_STD_VARIANT. - --#define ABSL_OPTION_USE_STD_VARIANT 2 -+#define ABSL_OPTION_USE_STD_VARIANT 0 - - - // ABSL_OPTION_USE_INLINE_NAMESPACE diff --git a/build.sh b/build.sh index 22e3435..de691d4 100755 --- a/build.sh +++ b/build.sh @@ -1,4 +1,44 @@ -#!/bin/bash +#!/usr/bin/env bash -bazel --output_user_root=$HOME/.cache/bazel --batch build --config asan spectator_test spectator -GTEST_COLOR=1 ./bazel-bin/spectator_test +BUILD_DIR=cmake-build +# Choose: Debug, Release, RelWithDebInfo and MinSizeRel +BUILD_TYPE=Debug + +BLUE="\033[0;34m" +NC="\033[0m" + +if [[ "$1" == "clean" ]]; then + echo -e "${BLUE}==== clean ====${NC}" + rm -rf $BUILD_DIR +fi + +if [[ "$OSTYPE" == "linux-gnu"* ]]; then + export CC=gcc-11 + export CXX=g++-11 +fi + +if [[ ! -d $BUILD_DIR ]]; then + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + echo -e "${BLUE}==== configure default profile ====${NC}" + conan profile new default --detect + conan profile update settings.compiler.libcxx=libstdc++11 default + fi + + echo -e "${BLUE}==== install required dependencies ====${NC}" + conan install . --build=missing --install-folder $BUILD_DIR +fi + +pushd $BUILD_DIR || exit 1 + +echo -e "${BLUE}==== generate build files ====${NC}" +cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE || exit 1 + +echo -e "${BLUE}==== build ====${NC}" +cmake --build . || exit 1 + +if [[ "$1" != "skiptest" ]]; then + echo -e "${BLUE}==== test ====${NC}" + GTEST_COLOR=1 ctest --verbose +fi + +popd || exit 1 diff --git a/conanfile.py b/conanfile.py new file mode 100644 index 0000000..42a1603 --- /dev/null +++ b/conanfile.py @@ -0,0 +1,16 @@ +from conans import ConanFile + + +class SpectatorDConan(ConanFile): + settings = "os", "compiler", "build_type", "arch" + requires = ( + "abseil/20230125.3", + "asio/1.28.1", + "backward-cpp/1.6", + "benchmark/1.8.3", + "fmt/10.1.1", + "gtest/1.14.0", + "spdlog/1.12.0" + ) + generators = "cmake" + default_options = {} diff --git a/dependencies.bzl b/dependencies.bzl deleted file mode 100644 index c0244fd..0000000 --- a/dependencies.bzl +++ /dev/null @@ -1,64 +0,0 @@ -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") - -def spectator_dependencies(): - http_archive( - name = "com_github_fmtlib_fmt", - build_file = "@spectator//third_party:fmtlib.BUILD", - strip_prefix = "fmt-8.0.1", - sha256 = "a627a56eab9554fc1e5dd9a623d0768583b3a383ff70a4312ba68f94c9d415bf", - urls = ["https://github.com/fmtlib/fmt/releases/download/8.0.1/fmt-8.0.1.zip"], - ) - - http_archive( - name = "com_github_gabime_spdlog", - build_file = "@spectator//third_party:spdlog.BUILD", - strip_prefix = "spdlog-1.9.1", - sha256 = "9a452cfa24408baccc9b2bc2d421d68172a7630c99e9504a14754be840d31a62", - urls = ["https://github.com/gabime/spdlog/archive/v1.9.1.tar.gz"], - ) - - http_archive( - name = "com_google_googletest", - urls = ["https://github.com/google/googletest/archive/release-1.10.0.tar.gz"], - strip_prefix = "googletest-release-1.10.0", - sha256 = "9dc9157a9a1551ec7a7e43daea9a694a0bb5fb8bec81235d8a1e6ef64c716dcb", - ) - - http_archive( - name = "com_google_benchmark", - urls = ["https://github.com/google/benchmark/archive/v1.5.1.tar.gz"], - strip_prefix = "benchmark-1.5.1", - sha256 = "23082937d1663a53b90cb5b61df4bcc312f6dee7018da78ba00dd6bd669dfef2", - ) - - http_archive( - name = "asio", - build_file = "@spectator//third_party:asio.BUILD", - urls = ["https://github.com/chriskohlhoff/asio/archive/asio-1-14-0.zip"], - strip_prefix = "asio-asio-1-14-0", - sha256 = "7887c91704a92dc8425385b1ff6f3e432e8869745b2ee2f896a1e7eb2a60e729", - ) - - http_archive( - name = "com_google_absl", - urls = ["https://github.com/abseil/abseil-cpp/archive/17c954d90d5661e27db8fc5f086085690a8372d9.zip"], - strip_prefix = "abseil-cpp-17c954d90d5661e27db8fc5f086085690a8372d9", - sha256 = "aee7688bb669402c1322d9512d7992a6f361a70444e54d98a8709a8ad4dd60c3", - patches = ["@//bazel:abseil.patch"], - patch_args = ["-p1"], - ) - - http_archive( - name = "com_github_bombela_backward", - urls = ["https://github.com/bombela/backward-cpp/archive/1efdd145b5fa84f457fb6727677ce0bc9f2c7b5b.zip"], - strip_prefix = "backward-cpp-1efdd145b5fa84f457fb6727677ce0bc9f2c7b5b", - build_file = "@spectator//third_party:backward.BUILD", - sha256 = "97ddc265cc42afadf870ccfa9b079382766eb9e46e8fc1994a61a92ff547c851", - ) - - http_archive( - name = "com_grail_bazel_compdb", - strip_prefix = "bazel-compilation-database-71edeae2eda57e4be679394d22b8ef7a60ca3860", - sha256 = "7504feffad927af7ba54213e741975b4e1e890c6cc7d1bc186ea4024508acd4c", - urls = ["https://github.com/grailbio/bazel-compilation-database/archive/71edeae2eda57e4be679394d22b8ef7a60ca3860.zip"], - ) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f50948a --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +conan==1.61.0 diff --git a/scripts/gen-compdb b/scripts/gen-compdb deleted file mode 100755 index 348b07e..0000000 --- a/scripts/gen-compdb +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -bazel build spectator_compdb -outfile="$(bazel info bazel-bin)/compile_commands.json" -execroot=$(bazel info execution_root) -sed -i.bak "s@__EXEC_ROOT__@${execroot}@" "${outfile}" -echo "Compilation Database: ${outfile}" diff --git a/setup-venv.sh b/setup-venv.sh new file mode 100755 index 0000000..7f50e7f --- /dev/null +++ b/setup-venv.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +PYTHON3=$(which python3) + +if [[ -z $PYTHON3 ]]; then + echo "python3 is not available - please install" + exit 1 +fi + +python3 -m venv venv + +source venv/bin/activate + +if [[ -f requirements.txt ]]; then + pip3 install --upgrade pip wheel + pip3 install --requirement requirements.txt +fi diff --git a/spectator/registry.h b/spectator/registry.h index 0154bd3..4e54780 100644 --- a/spectator/registry.h +++ b/spectator/registry.h @@ -102,11 +102,11 @@ struct single_table_state { } absl::Mutex mutex_; - // use a single table so we can easily check whether a meter + // use a single table, so we can easily check whether a meter // was previously registered as a different type absl::flat_hash_map, std::hash, std::equal_to> - meters_ GUARDED_BY(mutex_); + meters_ ABSL_GUARDED_BY(mutex_); }; template diff --git a/third_party/BUILD.bazel b/third_party/BUILD.bazel deleted file mode 100644 index e69de29..0000000 diff --git a/third_party/asio.BUILD b/third_party/asio.BUILD deleted file mode 100644 index 1f36e06..0000000 --- a/third_party/asio.BUILD +++ /dev/null @@ -1,9 +0,0 @@ -cc_library( - name = "asio", - hdrs = glob([ - "**/*.hpp", - "**/*.ipp", - ]), - includes = ["asio/include"], - visibility = ["//visibility:public"], -) diff --git a/third_party/backward.BUILD b/third_party/backward.BUILD deleted file mode 100644 index 82393da..0000000 --- a/third_party/backward.BUILD +++ /dev/null @@ -1,10 +0,0 @@ -load("@rules_cc//cc:defs.bzl", "cc_library") - -licenses(["notice"]) # MIT License - -cc_library( - name = "backward", - srcs = ["backward.cpp"], - hdrs = ["backward.hpp"], - visibility = ["//visibility:public"], -) diff --git a/third_party/fmtlib.BUILD b/third_party/fmtlib.BUILD deleted file mode 100644 index 17832ea..0000000 --- a/third_party/fmtlib.BUILD +++ /dev/null @@ -1,14 +0,0 @@ -# https://github.com/envoyproxy/envoy/blob/master/bazel/external/fmtlib.BUILD. - -cc_library( - name = "fmtlib", - srcs = glob([ - "fmt/*.cc", - ]), - hdrs = glob([ - "include/fmt/*.h", - ]), - defines = ["FMT_HEADER_ONLY"], - includes = ["include"], - visibility = ["//visibility:public"], -) diff --git a/third_party/spdlog.BUILD b/third_party/spdlog.BUILD deleted file mode 100644 index 6b12bc8..0000000 --- a/third_party/spdlog.BUILD +++ /dev/null @@ -1,13 +0,0 @@ -# https://github.com/envoyproxy/envoy/blob/master/bazel/external/spdlog.BUILD. - -cc_library( - name = "spdlog", - hdrs = glob([ - "include/**/*.cc", - "include/**/*.h", - ]), - defines = ["SPDLOG_FMT_EXTERNAL"], - includes = ["include"], - visibility = ["//visibility:public"], - deps = ["@com_github_fmtlib_fmt//:fmtlib"], -)