From 530a9b9f0e69557abd64324c55a898967ecb93ee Mon Sep 17 00:00:00 2001 From: Michael de Lang Date: Sun, 6 Nov 2022 20:27:21 +0100 Subject: [PATCH] Add cmake boilerplate to install ichor Also fix a threading issue in HttpHost --- CMakeLists.txt | 228 +++++++++++++----- IchorConfig.cmake.in | 24 ++ LICENSE | 2 +- build.sh | 4 +- cloc.sh | 4 +- docs/GettingStarted.md | 25 +- examples/common/TestMsgJsonSerializer.h | 12 +- .../http_ping_pong/PingMsgJsonSerializer.h | 12 +- include/ichor/Service.h | 2 +- .../services/network/http/HttpHostService.h | 1 + ...tpScopeGuardFinish.h => HttpScopeGuards.h} | 0 include/{ichor/sole.hpp => sole/sole.h} | 0 sonar-project.properties | 3 - .../network/http/HttpConnectionService.cpp | 2 +- src/services/network/http/HttpHostService.cpp | 15 +- test/CMakeLists.txt | 1 + 16 files changed, 249 insertions(+), 86 deletions(-) create mode 100644 IchorConfig.cmake.in rename include/ichor/services/network/http/{HttpScopeGuardFinish.h => HttpScopeGuards.h} (100%) rename include/{ichor/sole.hpp => sole/sole.h} (100%) delete mode 100644 sonar-project.properties diff --git a/CMakeLists.txt b/CMakeLists.txt index c3026c75..d9d6f3d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,6 @@ -cmake_minimum_required(VERSION 3.12) -project(ichor) +cmake_minimum_required(VERSION 3.12) #might need 3.13 due to https://gitlab.kitware.com/cmake/cmake/-/issues/14444 +cmake_policy(SET CMP0048 NEW) +project(ichor VERSION 0.1.0 DESCRIPTION "C++20 dependency injection framework" HOMEPAGE_URL https://github.com/volt-software/Ichor LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE CXX STANDARD REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) @@ -10,6 +11,8 @@ endif() set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) cmake_policy(SET CMP0077 NEW) include(CMakeDependentOption) +include(CMakePackageConfigHelpers) + if(NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE Debug CACHE STRING @@ -50,6 +53,7 @@ option(ICHOR_REMOVE_SOURCE_NAMES "Remove compiling source file names and line nu option(ICHOR_USE_MOLD "Use mold when linking, recommended to use with gcc 12+ or clang" OFF) option(ICHOR_USE_SDEVENT "Add sd-event based queue/integration" OFF) option(ICHOR_USE_ABSEIL "Use abseil provided classes where applicable" OFF) +option(ICHOR_DISABLE_RTTI "Disable RTTI. Reduces memory usage, disables dynamic_cast<>()" ON) cmake_dependent_option(ICHOR_USE_MIMALLOC "Use mimalloc for significant performance improvements" ON "NOT ICHOR_USE_SANITIZERS" OFF) cmake_dependent_option(ICHOR_USE_SYSTEM_MIMALLOC "Use system or vendored mimalloc" OFF "NOT ICHOR_USE_SANITIZERS" OFF) set(BUILD_TESTING OFF) #disable Catch 2 testing @@ -64,32 +68,45 @@ set(ICHOR_SERIALIZATION_FRAMEWORK OFF CACHE STRING "Enable serialization support set_property(CACHE ICHOR_SERIALIZATION_FRAMEWORK PROPERTY STRINGS OFF RAPIDJSON BOOST_JSON) set(ICHOR_ARCH_OPTIMIZATION OFF CACHE STRING "Tell compiler to optimize for target") -set_property(CACHE ICHOR_ARCH_OPTIMIZATION PROPERTY STRINGS OFF NATIVE X86_64 X86_64_AVX2 MODERN_ARM_GENERIC) +set_property(CACHE ICHOR_ARCH_OPTIMIZATION PROPERTY STRINGS OFF NATIVE X86_64 X86_64_SSE4 X86_64_AVX2 X86_64_AVX512 MODERN_ARM_GENERIC) if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND ICHOR_RUN_CLANG_TIDY) set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-checks=*,-llvmlibc-*,-readability-function-cognitive-complexity,-altera-*,-modernize-use-trailing-return-type,-concurrency-mt-unsafe,-fuchsia-default-arguments-calls,-android-*,-readability-identifier-length,-clang-analyzer-optin.cplusplus.UninitializedObject") endif() +set(FMT_SOURCES ${ICHOR_EXTERNAL_DIR}/fmt/src/format.cc ${ICHOR_EXTERNAL_DIR}/fmt/src/os.cc) +file(GLOB_RECURSE ICHOR_FRAMEWORK_SOURCES ${ICHOR_TOP_DIR}/src/ichor/*.cpp) +file(GLOB_RECURSE ICHOR_OPTIONAL_ETCD_SOURCES ${ICHOR_TOP_DIR}/src/services/etcd/*.cpp ${ICHOR_TOP_DIR}/src/services/etcd/*.cc) +file(GLOB_RECURSE ICHOR_LOGGING_SOURCES ${ICHOR_TOP_DIR}/src/services/logging/*.cpp) +file(GLOB_RECURSE ICHOR_NETWORK_SOURCES ${ICHOR_TOP_DIR}/src/services/network/*.cpp) +file(GLOB_RECURSE ICHOR_METRICS_SOURCES ${ICHOR_TOP_DIR}/src/services/metrics/*.cpp) +file(GLOB_RECURSE ICHOR_SERIALIZATION_SOURCES ${ICHOR_TOP_DIR}/src/services/serialization/*.cpp) +file(GLOB_RECURSE ICHOR_TIMER_SOURCES ${ICHOR_TOP_DIR}/src/services/timer/*.cpp) + +file(GLOB SPDLOG_SOURCES ${ICHOR_EXTERNAL_DIR}/spdlog/src/*.cpp) + +add_library(ichor ${FMT_SOURCES} ${ICHOR_FRAMEWORK_SOURCES} ${ICHOR_LOGGING_SOURCES} ${ICHOR_NETWORK_SOURCES} ${ICHOR_METRICS_SOURCES} ${ICHOR_SERIALIZATION_SOURCES} ${ICHOR_TIMER_SOURCES}) + if(ICHOR_ENABLE_INTERNAL_DEBUGGING) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DICHOR_ENABLE_INTERNAL_DEBUGGING ") + target_compile_definitions(ichor PUBLIC ICHOR_ENABLE_INTERNAL_DEBUGGING) endif() if(ICHOR_USE_SPDLOG) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSPDLOG_COMPILED_LIB -DSPDLOG_NO_EXCEPTIONS -DSPDLOG_FMT_EXTERNAL -DSPDLOG_DISABLE_DEFAULT_LOGGER -DSPDLOG_NO_ATOMIC_LEVELS -DICHOR_USE_SPDLOG -DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE ") + target_compile_definitions(ichor PUBLIC SPDLOG_COMPILED_LIB SPDLOG_NO_EXCEPTIONS SPDLOG_FMT_EXTERNAL SPDLOG_DISABLE_DEFAULT_LOGGER SPDLOG_NO_ATOMIC_LEVELS ICHOR_USE_SPDLOG SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE) endif() if(ICHOR_SERIALIZATION_FRAMEWORK STREQUAL "RAPIDJSON") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_RAPIDJSON ") + target_compile_definitions(ichor PUBLIC ICHOR_USE_RAPIDJSON) elseif(ICHOR_SERIALIZATION_FRAMEWORK STREQUAL "BOOST_JSON") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_BOOST_JSON -DBOOST_JSON_STANDALONE") + target_compile_definitions(ichor PUBLIC ICHOR_USE_BOOST_JSON BOOST_JSON_STANDALONE) endif() if(ICHOR_REMOVE_SOURCE_NAMES) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DICHOR_REMOVE_SOURCE_NAMES_FROM_LOGGING ") + target_compile_definitions(ichor PUBLIC ICHOR_REMOVE_SOURCE_NAMES_FROM_LOGGING) endif() if(ICHOR_USE_UGLY_HACK_EXCEPTION_CATCHING) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DICHOR_USE_UGLY_HACK_EXCEPTION_CATCHING ") + target_compile_definitions(ichor PUBLIC ICHOR_USE_UGLY_HACK_EXCEPTION_CATCHING) endif() if(ICHOR_USE_ETCD) @@ -105,17 +122,15 @@ if(ICHOR_USE_ETCD) set(ETCD_TARGET gRPC::grpc++ ${PROTOBUF_LIBRARIES}) endif() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DICHOR_USE_ETCD ") + target_compile_definitions(ichor PUBLIC ICHOR_USE_ETCD) endif() if(ICHOR_USE_BOOST_BEAST) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DICHOR_USE_BOOST_BEAST ") endif() -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DCATCH_CONFIG_FAST_COMPILE ") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wno-unused-variable -Wno-long-long -Wno-unused-parameter -Wnull-dereference -pedantic -Wformat -Wformat-security -Wcast-align -Woverloaded-virtual ") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread ") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti ") # gcc added support for mold in version 12, but it throws catch off guard when using gcc, mold and sanitizers. if(ICHOR_USE_MOLD AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU") @@ -128,34 +143,42 @@ endif() if(ICHOR_ARCH_OPTIMIZATION STREQUAL "NATIVE") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native ") + target_compile_options(ichor PUBLIC -march=native) elseif(ICHOR_ARCH_OPTIMIZATION STREQUAL "X86_64") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64 ") + target_compile_options(ichor PUBLIC -march=x86-64) +elseif(ICHOR_ARCH_OPTIMIZATION STREQUAL "X86_64_SSE4") + target_compile_options(ichor PUBLIC -march=x86-64-v2) elseif(ICHOR_ARCH_OPTIMIZATION STREQUAL "X86_64_AVX2") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64-v3 ") + target_compile_options(ichor PUBLIC -march=x86-64-v3) +elseif(ICHOR_ARCH_OPTIMIZATION STREQUAL "X86_64_AVX512") + target_compile_options(ichor PUBLIC -march=x86-64-v4) elseif(ICHOR_ARCH_OPTIMIZATION STREQUAL "MODERN_ARM_GENERIC") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv8-a ") + target_compile_options(ichor PUBLIC -march=armv8-a) +endif() + +if(ICHOR_DISABLE_RTTI) + target_compile_options(ichor PUBLIC -fno-rtti) endif() if(ICHOR_USE_SANITIZERS) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,undefined -fno-omit-frame-pointer") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie") + target_compile_options(ichor PUBLIC -fsanitize=address,undefined -fno-omit-frame-pointer) + target_link_options(ichor PUBLIC -fsanitize=address,undefined -no-pie) if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no-pie") + target_compile_options(ichor PUBLIC -no-pie) endif() if(ICHOR_USE_BOOST_BEAST) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBOOST_USE_ASAN -DBOOST_USE_UCONTEXT") + target_compile_definitions(ichor PUBLIC BOOST_USE_ASAN BOOST_USE_UCONTEXT) endif() endif() if(ICHOR_USE_THREAD_SANITIZER) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -fno-omit-frame-pointer") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie") + target_compile_options(ichor PUBLIC -fsanitize=thread -fno-omit-frame-pointer) + target_link_options(ichor PUBLIC -fsanitize=thread -no-pie) if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no-pie") + target_compile_options(ichor PUBLIC -no-pie) endif() endif() @@ -169,9 +192,9 @@ endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fconcepts-diagnostics-depth=3 ") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcoroutines") + target_compile_options(ichor PUBLIC -fcoroutines) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcoroutines-ts") + target_compile_options(ichor PUBLIC -fcoroutines-ts) endif() # gcc uses gdwarf-4 by default, which messes up using the coz profiler, add "-gdwarf-3" if using coz @@ -180,24 +203,11 @@ set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -ggdb") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-ggdb3 -Og") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG") -set(FMT_SOURCES ${ICHOR_EXTERNAL_DIR}/fmt/src/format.cc ${ICHOR_EXTERNAL_DIR}/fmt/src/os.cc) -file(GLOB_RECURSE ICHOR_FRAMEWORK_SOURCES ${ICHOR_TOP_DIR}/src/ichor/*.cpp) -file(GLOB_RECURSE ICHOR_OPTIONAL_ETCD_SOURCES ${ICHOR_TOP_DIR}/src/services/etcd/*.cpp ${ICHOR_TOP_DIR}/src/services/etcd/*.cc) -file(GLOB_RECURSE ICHOR_LOGGING_SOURCES ${ICHOR_TOP_DIR}/src/services/logging/*.cpp) -file(GLOB_RECURSE ICHOR_NETWORK_SOURCES ${ICHOR_TOP_DIR}/src/services/network/*.cpp) -file(GLOB_RECURSE ICHOR_METRICS_SOURCES ${ICHOR_TOP_DIR}/src/services/metrics/*.cpp) -file(GLOB_RECURSE ICHOR_SERIALIZATION_SOURCES ${ICHOR_TOP_DIR}/src/services/serialization/*.cpp) -file(GLOB_RECURSE ICHOR_TIMER_SOURCES ${ICHOR_TOP_DIR}/src/services/timer/*.cpp) - -file(GLOB SPDLOG_SOURCES ${ICHOR_EXTERNAL_DIR}/spdlog/src/*.cpp) - -add_library(ichor ${FMT_SOURCES} ${ICHOR_FRAMEWORK_SOURCES} ${ICHOR_LOGGING_SOURCES} ${ICHOR_NETWORK_SOURCES} ${ICHOR_METRICS_SOURCES} ${ICHOR_SERIALIZATION_SOURCES} ${ICHOR_TIMER_SOURCES}) - # Gcc 12.1 and 12.2 have bugs that prevent compilation with Werror at -O2 and higher: # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107138 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105329 if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_VERSION VERSION_LESS "12") - target_compile_options(ichor PUBLIC "-Werror") #prevent externally compiled sources to error out on warnings + target_compile_options(ichor PRIVATE "-Werror") #prevent externally compiled sources to error out on warnings endif() # By default, we build a bundled mimalloc and statically-link it to @@ -212,22 +222,25 @@ if(ICHOR_USE_MIMALLOC) function(ichor_add_mimalloc) set(MI_BUILD_STATIC ON) set(MI_BUILD_SHARED OFF) + set(MI_BUILD_OBJECT OFF) + set(MI_BUILD_TESTS OFF) set(MI_USE_CXX ON) option(MI_BUILD_TESTS "Build test executables" OFF) add_subdirectory(external/mimalloc EXCLUDE_FROM_ALL) target_compile_definitions(mimalloc-static PRIVATE MI_USE_ENVIRON=0) - target_link_libraries(ichor mimalloc-static) + target_link_libraries(ichor PUBLIC mimalloc-static) endfunction() ichor_add_mimalloc() + set(MIMALLOC_TARGET mimalloc-static) endif() endif() if(ICHOR_USE_ABSEIL) find_package(absl REQUIRED) - target_link_libraries(ichor absl::flat_hash_map absl::flat_hash_set absl::btree absl::hash) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DICHOR_USE_ABSEIL") + target_link_libraries(ichor PUBLIC absl::flat_hash_map absl::flat_hash_set absl::btree absl::hash) + target_compile_definitions(ichor PUBLIC ICHOR_USE_ABSEIL) endif() if(ICHOR_USE_SPDLOG) @@ -236,7 +249,7 @@ endif() if(ICHOR_USE_ETCD) target_sources(ichor PRIVATE ${ICHOR_OPTIONAL_ETCD_SOURCES}) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGOOGLE_PROTOBUF_NO_RTTI") + target_compile_definitions(ichor PUBLIC GOOGLE_PROTOBUF_NO_RTTI) endif() if(ICHOR_USE_SDEVENT) @@ -245,32 +258,46 @@ if(ICHOR_USE_SDEVENT) if(NOT TARGET PkgConfig::Systemd) message(FATAL_ERROR "libsystemd was not found") endif() - target_link_libraries(ichor PkgConfig::Systemd) - target_compile_definitions(ichor PUBLIC "ICHOR_USE_SDEVENT") + target_link_libraries(ichor PUBLIC PkgConfig::Systemd) + target_compile_definitions(ichor PUBLIC ICHOR_USE_SDEVENT) endif() if(ICHOR_USE_BOOST_BEAST) #TODO figure out how to make asio/beast compile as libraries, rather than header only. This would hopefully save some compilation time. # target_link_libraries(ichor asio beast) - target_link_libraries(ichor boost_coroutine) - target_compile_definitions(ichor PUBLIC "BOOST_BEAST_USE_STD_STRING_VIEW") + target_link_libraries(ichor PUBLIC boost_coroutine) + target_compile_definitions(ichor PUBLIC BOOST_BEAST_USE_STD_STRING_VIEW) endif() -target_link_libraries(ichor ${CMAKE_THREAD_LIBS_INIT}) -target_link_libraries(ichor -ldl -lrt) +target_link_libraries(ichor PUBLIC ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries(ichor PUBLIC -ldl -lrt) + +target_include_directories(ichor PUBLIC + $ + $) + +target_include_directories(ichor PUBLIC + $ + $) -target_include_directories(ichor PUBLIC "${ICHOR_EXTERNAL_DIR}/wyhash") -target_include_directories(ichor PUBLIC "${ICHOR_EXTERNAL_DIR}/fmt/include") -target_include_directories(ichor PUBLIC "${ICHOR_TOP_DIR}/include") +target_include_directories(ichor PUBLIC + $ + $) if(ICHOR_USE_SPDLOG) - target_include_directories(ichor PUBLIC "${ICHOR_EXTERNAL_DIR}/spdlog/include") + target_include_directories(ichor PUBLIC + $ + $) endif() if(ICHOR_SERIALIZATION_FRAMEWORK STREQUAL "RAPIDJSON") - target_include_directories(ichor PUBLIC "${ICHOR_EXTERNAL_DIR}/rapidjson/include") + target_include_directories(ichor PUBLIC + $ + $) elseif(ICHOR_SERIALIZATION_FRAMEWORK STREQUAL "BOOST_JSON") - target_include_directories(ichor PUBLIC "${ICHOR_EXTERNAL_DIR}/json/include") + target_include_directories(ichor PUBLIC + $ + $) endif() if(ICHOR_USE_ETCD) @@ -293,8 +320,95 @@ if(ICHOR_BUILD_TESTING) endif() if(hasParent) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}" PARENT_SCOPE) set(ICHOR_TOP_DIR "${ICHOR_TOP_DIR}" PARENT_SCOPE) set(ICHOR_EXTERNAL_DIR "${ICHOR_EXTERNAL_DIR}" PARENT_SCOPE) endif() +configure_package_config_file( + IchorConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/IchorConfig.cmake + INSTALL_DESTINATION lib/cmake/ichor + PATH_VARS + ) +write_basic_package_version_file( + IchorConfigVersion.cmake + VERSION ${PACKAGE_VERSION} + COMPATIBILITY SameMinorVersion + ) + +install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/ichor" # source directory + DESTINATION "include" # target directory + FILES_MATCHING # install only matched files + PATTERN "*.h" # select header files + ) + +install(DIRECTORY "${CMAKE_SOURCE_DIR}/external/fmt/include/fmt" # source directory + DESTINATION "include/ichor/external" # target directory + FILES_MATCHING # install only matched files + PATTERN "*.h" # select header files + ) + +install(DIRECTORY "${CMAKE_SOURCE_DIR}/external/wyhash" # source directory + DESTINATION "include/ichor/external" # target directory + FILES_MATCHING # install only matched files + PATTERN "*.h" # select header files + ) + +install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/tl" # source directory + DESTINATION "include/ichor/external" # target directory + FILES_MATCHING # install only matched files + PATTERN "*.h" # select header files + ) + +install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/sole" # source directory + DESTINATION "include/ichor/external" # target directory + FILES_MATCHING # install only matched files + PATTERN "*.h" # select header files + ) + +if(ICHOR_USE_SPDLOG) + install(DIRECTORY "${CMAKE_SOURCE_DIR}/external/spdlog/include/spdlog" # source directory + DESTINATION "include/ichor/external" # target directory + FILES_MATCHING # install only matched files + PATTERN "*.h" # select header files + ) +endif() + +if(ICHOR_SERIALIZATION_FRAMEWORK STREQUAL "RAPIDJSON") + install(DIRECTORY "${CMAKE_SOURCE_DIR}/external/rapidjson/include/rapidjson" # source directory + DESTINATION "include/ichor/external" # target directory + FILES_MATCHING # install only matched files + PATTERN "*.h" # select header files + ) +elseif(ICHOR_SERIALIZATION_FRAMEWORK STREQUAL "BOOST_JSON") + install(DIRECTORY "${CMAKE_SOURCE_DIR}/external/json/include/boost" # source directory + DESTINATION "include/ichor/external" # target directory + FILES_MATCHING # install only matched files + PATTERN "*.h" # select header files + ) +endif() + +install(TARGETS ichor ${MIMALLOC_TARGET} + EXPORT IchorTargets + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + RUNTIME DESTINATION bin + INCLUDES DESTINATION include + ) + +if(ICHOR_USE_MIMALLOC AND NOT ICHOR_USE_SYSTEM_MIMALLOC) + set(mi_version "2.0") + set(mi_install_incdir "${CMAKE_INSTALL_INCLUDEDIR}/mimalloc-${mi_version}") + install(FILES external/mimalloc/include/mimalloc.h DESTINATION ${mi_install_incdir}) + install(FILES external/mimalloc/include/mimalloc-override.h DESTINATION ${mi_install_incdir}) + install(FILES external/mimalloc/include/mimalloc-new-delete.h DESTINATION ${mi_install_incdir}) +endif() + +install(EXPORT IchorTargets + FILE IchorTargets.cmake + NAMESPACE Ichor:: + DESTINATION lib/cmake/ichor + ) +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/IchorConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/IchorConfigVersion.cmake" + DESTINATION lib/cmake/ichor + ) \ No newline at end of file diff --git a/IchorConfig.cmake.in b/IchorConfig.cmake.in new file mode 100644 index 00000000..725e153d --- /dev/null +++ b/IchorConfig.cmake.in @@ -0,0 +1,24 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) + +set(ICHOR_USE_SYSTEM_MIMALLOC @ICHOR_USE_SYSTEM_MIMALLOC@) +set(ICHOR_USE_ABSEIL @ICHOR_USE_ABSEIL@) +set(ICHOR_USE_SDEVENT @ICHOR_USE_SDEVENT@) +set(ICHOR_USE_BOOST_BEAST @ICHOR_USE_BOOST_BEAST@) + +if(ICHOR_USE_SYSTEM_MIMALLOC) + find_dependency(mimalloc REQUIRED) +endif() +if(ICHOR_USE_ABSEIL) + find_dependency(absl REQUIRED) +endif() +if(ICHOR_USE_SDEVENT) + find_dependency(PkgConfig REQUIRED) + pkg_check_modules(Systemd IMPORTED_TARGET GLOBAL libsystemd) +endif() +if(ICHOR_USE_BOOST_BEAST) + find_dependency(boost_coroutine REQUIRED) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/IchorTargets.cmake") \ No newline at end of file diff --git a/LICENSE b/LICENSE index 2d01f214..7d948f11 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 Michael de Lang +Copyright (c) 2022 Michael de Lang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/build.sh b/build.sh index 6472cb41..c5de3051 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,5 @@ #!/bin/bash - +#sudo rm -rf * ../bin/* /usr/include/ichor/ ../../ichor-install/ /usr/lib/cmake/ichor && cmake -GNinja -DICHOR_BUILD_TESTING=OFF -DICHOR_BUILD_EXAMPLES=OFF -DICHOR_BUILD_BENCHMARKS=OFF -DCMAKE_BUILD_TYPE=Debug -DICHOR_USE_SANITIZERS=ON -DICHOR_ARCH_OPTIMIZATION=X86_64_AVX512 -DICHOR_USE_ABSEIL=ON -DICHOR_SERIALIZATION_FRAMEWORK=BOOST_JSON -DICHOR_USE_BOOST_BEAST=ON -DICHOR_USE_SPDLOG=ON -DCMAKE_INSTALL_PREFIX=/usr .. && ninja && sudo ninja install cleanup () { kill -s SIGTERM $! @@ -63,4 +63,4 @@ for i in ${!ccompilers[@]}; do ninja test || exit 1 run_examples run_benchmarks -done \ No newline at end of file +done diff --git a/cloc.sh b/cloc.sh index 8163c97d..7ac34be0 100755 --- a/cloc.sh +++ b/cloc.sh @@ -1,4 +1,4 @@ #!/bin/bash -cloc src/ include/ test/ examples/ benchmarks/ --exclude-dir=etcd,etcd_example,tl +cloc src/ include/ test/ examples/ benchmarks/ --exclude-dir=etcd,etcd_example,tl,sole echo "" -cloc src/ include/ test/ examples/ benchmarks/ --exclude-dir=etcd,etcd_example,tl --by-file +cloc src/ include/ test/ examples/ benchmarks/ --exclude-dir=etcd,etcd_example,tl,sole --by-file diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md index 80592023..3a1f1854 100644 --- a/docs/GettingStarted.md +++ b/docs/GettingStarted.md @@ -3,6 +3,7 @@ ## Compiling Ichor Compiling is done through the help of CMake. Ichor requires at least gcc 11.3 (due to [this gcc bug](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95137)) or clang 14, and is tested with gcc 11.3, 12.1, clang 14, clang 15 and clang 16. + ### Dependencies #### Ubuntu 20.04: @@ -62,6 +63,20 @@ sudo apt install libabsl-dev Tried with MSVC 19.33, but it seemed like coroutines and concepts are not fully implemented yet. +#### CMakeLists.txt + +To use Ichor, compile and install it in a location that cmake can find (e.g. /usr) and use the following CMakeLists.txt: + +```cmake +cmake_minimum_required(VERSION 3.12) +project(my_project) + +set(CMAKE_CXX_STANDARD 20) +find_package(my_exe CONFIG REQUIRED) + +add_executable(my_exe main.cpp) +target_link_libraries(my_exe Ichor::ichor) +``` ### CMake Options @@ -134,6 +149,10 @@ Enables the use of the [sdevent event queue](../include/ichor/event_queues/Sdeve Enables the use of the abseil containers in Ichor. Requires having abseil headers and libraries installed on your system. +#### ICHOR_DISABLE_RTTI + +Disables `dynamic_cast<>()` in most cases as well as `typeid`. Ichor is an opinionated piece of software and we strongly encourage you to disable RTTI. We believe `dynamic_cast<>()` is wrong in almost all instances. Virtual methods and double dispatch should be used instead. If, however, you really want to use RTTI, use this option to re-enable it. + #### ICHOR_USE_MIMALLOC If `ICHOR_USE_SANITIZERS` is turned OFF, Ichor by default compiles itself with mimalloc, speeding up the runtime a lot and reducing peak memory usage. @@ -273,7 +292,7 @@ struct MyTimerService final : public IMyTimerService, public Ichor::Service handleEvent(Ichor::TimerEvent const * const) { + Ichor::AsyncGenerator handleEvent(Ichor::TimerEvent const &) { co_return; } @@ -339,7 +358,7 @@ struct MyTimerService final : public IMyTimerService, public Ichor::Service handleEvent(Ichor::TimerEvent const * const) { + Ichor::AsyncGenerator handleEvent(Ichor::TimerEvent const &) { getManager().pushEvent(getServiceId()); // Add this co_return; } @@ -409,7 +428,7 @@ Pushing an event with a priority is done with the `pushPrioritisedEvent` functio getManager().pushPrioritisedEvent(getServiceId(), 10); ``` -The default priority for events is 1000. For dependency related things (like start service, dependency online events) this is 100. +The default priority for events is 1000. For dependency related things (like start service, dependency online events) it is 100. ### Memory allocation diff --git a/examples/common/TestMsgJsonSerializer.h b/examples/common/TestMsgJsonSerializer.h index c8d2446f..1dc49c4f 100644 --- a/examples/common/TestMsgJsonSerializer.h +++ b/examples/common/TestMsgJsonSerializer.h @@ -7,10 +7,10 @@ #include #include "TestMsg.h" -#ifdef USE_RAPIDJSON +#ifdef ICHOR_USE_RAPIDJSON #include #include -#elif USE_BOOST_JSON +#elif ICHOR_USE_BOOST_JSON #pragma GCC diagnostic push #ifndef __clang__ #pragma GCC diagnostic ignored "-Wduplicated-branches" @@ -35,7 +35,7 @@ class TestMsgJsonSerializer final : public ISerializer, public Service serialize(const void* obj) final { auto msg = static_cast(obj); -#ifdef USE_RAPIDJSON +#ifdef ICHOR_USE_RAPIDJSON rapidjson::StringBuffer sb; rapidjson::Writer writer(sb); @@ -50,7 +50,7 @@ class TestMsgJsonSerializer final : public ISerializer, public Service(ret, ret + sb.GetSize() + 1); -#elif USE_BOOST_JSON +#elif ICHOR_USE_BOOST_JSON boost::json::value jv{}; boost::json::serializer sr; jv = {{"id", msg->id}, {"val", msg->val}}; @@ -84,7 +84,7 @@ class TestMsgJsonSerializer final : public ISerializer, public Service &&stream) final { -#ifdef USE_RAPIDJSON +#ifdef ICHOR_USE_RAPIDJSON rapidjson::Document d; d.ParseInsitu(reinterpret_cast(stream.data())); @@ -93,7 +93,7 @@ class TestMsgJsonSerializer final : public ISerializer, public Service #include "PingMsg.h" -#ifdef USE_RAPIDJSON +#ifdef ICHOR_USE_RAPIDJSON #include #include -#elif USE_BOOST_JSON +#elif ICHOR_USE_BOOST_JSON #pragma GCC diagnostic push #ifndef __clang__ #pragma GCC diagnostic ignored "-Wduplicated-branches" @@ -35,7 +35,7 @@ class PingMsgJsonSerializer final : public ISerializer, public Service serialize(const void* obj) final { auto msg = static_cast(obj); -#ifdef USE_RAPIDJSON +#ifdef ICHOR_USE_RAPIDJSON rapidjson::StringBuffer sb; rapidjson::Writer writer(sb); @@ -47,7 +47,7 @@ class PingMsgJsonSerializer final : public ISerializer, public Service(ret, ret + sb.GetSize() + 1); -#elif USE_BOOST_JSON +#elif ICHOR_USE_BOOST_JSON boost::json::value jv{}; boost::json::serializer sr; jv = {{"sequence", msg->sequence}}; @@ -81,7 +81,7 @@ class PingMsgJsonSerializer final : public ISerializer, public Service &&stream) final { -#ifdef USE_RAPIDJSON +#ifdef ICHOR_USE_RAPIDJSON rapidjson::Document d; d.ParseInsitu(reinterpret_cast(stream.data())); @@ -90,7 +90,7 @@ class PingMsgJsonSerializer final : public ISerializer, public Service #include -#include "sole.hpp" +#include #include #include #include diff --git a/include/ichor/services/network/http/HttpHostService.h b/include/ichor/services/network/http/HttpHostService.h index bc7b57a9..b91dde88 100644 --- a/include/ichor/services/network/http/HttpHostService.h +++ b/include/ichor/services/network/http/HttpHostService.h @@ -50,6 +50,7 @@ namespace Ichor { friend DependencyRegister; std::unique_ptr _httpAcceptor{}; + // _httpStreams should only be modified from the boost thread unordered_map> _httpStreams{}; std::atomic _priority{INTERNAL_EVENT_PRIORITY}; std::atomic _quit{}; diff --git a/include/ichor/services/network/http/HttpScopeGuardFinish.h b/include/ichor/services/network/http/HttpScopeGuards.h similarity index 100% rename from include/ichor/services/network/http/HttpScopeGuardFinish.h rename to include/ichor/services/network/http/HttpScopeGuards.h diff --git a/include/ichor/sole.hpp b/include/sole/sole.h similarity index 100% rename from include/ichor/sole.hpp rename to include/sole/sole.h diff --git a/sonar-project.properties b/sonar-project.properties deleted file mode 100644 index bf456538..00000000 --- a/sonar-project.properties +++ /dev/null @@ -1,3 +0,0 @@ -sonar.projectKey=volt-software_cppelix -sonar.organization=volt-software -sonar.projectName=cppelix \ No newline at end of file diff --git a/src/services/network/http/HttpConnectionService.cpp b/src/services/network/http/HttpConnectionService.cpp index 6be698e3..64404345 100644 --- a/src/services/network/http/HttpConnectionService.cpp +++ b/src/services/network/http/HttpConnectionService.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include namespace Ichor { diff --git a/src/services/network/http/HttpHostService.cpp b/src/services/network/http/HttpHostService.cpp index d8bbf125..1c565c3e 100644 --- a/src/services/network/http/HttpHostService.cpp +++ b/src/services/network/http/HttpHostService.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include Ichor::HttpHostService::HttpHostService(DependencyRegister ®, Properties props, DependencyManager *mng) : Service(std::move(props), mng) { reg.registerDependency(this, true); @@ -41,9 +41,12 @@ Ichor::StartBehaviour Ichor::HttpHostService::stop() { if (_httpAcceptor->is_open()) { _httpAcceptor->close(); } - for(auto &[id, stream] : _httpStreams) { - stream->cancel(); - } + net::spawn(*_httpContextService->getContext(), [this](net::yield_context _yield) { + // _httpStreams should only be modified from the boost thread + for (auto &[id, stream]: _httpStreams) { + stream->cancel(); + } + }); _httpAcceptor = nullptr; _cleanedupStream = true; @@ -52,6 +55,7 @@ Ichor::StartBehaviour Ichor::HttpHostService::stop() { if(_finishedListenAndRead.load(std::memory_order_acquire) != 0 || !_cleanedupStream) { return Ichor::StartBehaviour::FAILED_AND_RETRY; } + // _httpStreams should only be modified from the boost thread, except here where we know there are no fibers running _httpStreams.clear(); return Ichor::StartBehaviour::SUCCEEDED; @@ -182,6 +186,7 @@ void Ichor::HttpHostService::read(tcp::socket socket, net::yield_context yield) beast::error_code ec; auto addr = socket.remote_endpoint().address().to_string(); uint64_t streamId = _streamIdCounter++; + // _httpStreams should only be modified from the boost thread auto *httpStream = _httpStreams.emplace(streamId, std::make_unique(std::move(socket))).first->second.get(); // This buffer is required to persist across reads @@ -265,6 +270,7 @@ void Ichor::HttpHostService::read(tcp::socket socket, net::yield_context yield) co_return; }); } + // _httpStreams should only be modified from the boost thread _httpStreams.erase(streamId); // At this point the connection is closed gracefully @@ -291,6 +297,7 @@ void Ichor::HttpHostService::sendInternal(uint64_t streamId, http::response