diff --git a/CMakeLists.txt b/CMakeLists.txt index 86eaef6472..4a1255e056 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,8 @@ option(YDB_SDK_TESTS "Build YDB C++ SDK tests" Off) option(YDB_SDK_EXAMPLES "Build YDB C++ SDK examples" On) set(YDB_SDK_GOOGLE_COMMON_PROTOS_TARGET "" CACHE STRING "Name of cmake target preparing google common proto library") option(YDB_SDK_USE_RAPID_JSON "Search for rapid json library in system" ON) +option(YDB_SDK_DOWNLOAD_PACKAGES "Download with CPM if there is no system-provided libraries" ON) # todo изменить сообщение +option(YDB_SDK_FORCE_DOWNLOAD_PACKAGES "Download all possible third party packages even if a system package is available" ON) set(BUILD_SHARED_LIBS Off) set(CMAKE_CXX_STANDARD 20) @@ -69,6 +71,11 @@ if (YDB_SDK_TESTS) add_subdirectory(tests) endif() +if(CPM_PACKAGES) + include(DownloadUsingCPM) + _ydb_sdk_print_cpm_packages() +endif() + if (YDB_SDK_INSTALL) _ydb_sdk_install_headers(${CMAKE_INSTALL_INCLUDEDIR}) install(EXPORT ydb-cpp-sdk-targets diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake new file mode 100644 index 0000000000..84748734ce --- /dev/null +++ b/cmake/CPM.cmake @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: MIT +# +# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors + +set(CPM_DOWNLOAD_VERSION 0.42.0) +set(CPM_HASH_SUM "2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a") + +if(CPM_SOURCE_CACHE) + set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +elseif(DEFINED ENV{CPM_SOURCE_CACHE}) + set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +else() + set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +endif() + +# Expand relative path. This is important if the provided path contains a tilde (~) +get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) + +file(DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake + ${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM} +) + +include(${CPM_DOWNLOAD_LOCATION}) diff --git a/cmake/DownloadUsingCPM.cmake b/cmake/DownloadUsingCPM.cmake new file mode 100644 index 0000000000..31be00c77e --- /dev/null +++ b/cmake/DownloadUsingCPM.cmake @@ -0,0 +1,75 @@ +include_guard() + +if(NOT DEFINED CPM_USE_NAMED_CACHE_DIRECTORIES) + set(CPM_USE_NAMED_CACHE_DIRECTORIES ON) +endif() + +# Workaround for https://github.com/cpm-cmake/CPM.cmake/issues/505 +if(${CMAKE_VERSION} VERSION_LESS "3.17.0") + include(FetchContent) +endif() + +include(cmake/CPM.cmake) + +if(NOT COMMAND CPMAddPackage) + message(FATAL_ERROR "Failed to find CPM to download a package. You can turn off " + "YDB_SDK_DOWNLOAD_PACKAGES to avoid automatic downloads." + ) +endif() + +# If A uses find_package(B), and we install A and B using CPM, then: 1. make sure to call write_package_stub in SetupB +# 2. make sure to call SetupB at the beginning of SetupA +function(write_package_stub PACKAGE_NAME) + file(WRITE "${CMAKE_BINARY_DIR}/package_stubs/${PACKAGE_NAME}Config.cmake" ) +endfunction() + +function(_list_subdirectories directory result_list) + set(result "${directory}") + get_property( + subdirectories + DIRECTORY "${directory}" + PROPERTY SUBDIRECTORIES + ) + foreach(subdirectory IN LISTS subdirectories) + _list_subdirectories("${subdirectory}" partial_result) + list(APPEND result ${partial_result}) + endforeach() + set("${result_list}" + ${result} + PARENT_SCOPE + ) +endfunction() + +function(mark_targets_as_system directory) + if(NOT directory OR NOT EXISTS "${directory}") + message(FATAL_ERROR "Trying to mark a non-existent subdirectory '${directory}' as SYSTEM") + endif() + _list_subdirectories("${directory}" subdirectories) + foreach(subdirectory IN LISTS subdirectories) + get_property( + targets + DIRECTORY "${subdirectory}" + PROPERTY BUILDSYSTEM_TARGETS + ) + # Disable warnings in public headers + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.25.0") + set_target_properties(${targets} PROPERTIES SYSTEM TRUE) + endif() + # Disable warnings in sources + foreach(target IN LISTS targets) + get_target_property(target_sources "${target}" SOURCES) + get_target_property(target_type "${target}" TYPE) + if(target_sources AND NOT target_type STREQUAL "INTERFACE_LIBRARY") + target_compile_options("${target}" PRIVATE -w) + endif() + endforeach() + endforeach() +endfunction() + +function(_ydb_sdk_print_cpm_packages) + message(STATUS "Dependencies from CPM:") + foreach(PACKAGE ${CPM_PACKAGES}) + message(STATUS "- ${PACKAGE}") + endforeach() +endfunction() + diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake new file mode 100644 index 0000000000..44cd5ccda3 --- /dev/null +++ b/cmake/dependencies.cmake @@ -0,0 +1,15 @@ +include(DownloadUsingCPM) + +if(NOT "${CMAKE_BINARY_DIR}/${STUB_DIR}" IN_LIST CMAKE_PREFIX_PATH) + set(CMAKE_PREFIX_PATH + "${CMAKE_BINARY_DIR}/${STUB_DIR}" ${CMAKE_PREFIX_PATH} + ) +endif() + +# todo сделать нормально без этих страшных путей +include(${CMAKE_CURRENT_LIST_DIR}/dependencies/SetupBrotli.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/dependencies/SetupBase64.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/dependencies/SetupAbseil.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/dependencies/SetupJwtCpp.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/dependencies/SetupProtobuf.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/dependencies/SetupGrpc.cmake) diff --git a/cmake/dependencies/SetupAbseil.cmake b/cmake/dependencies/SetupAbseil.cmake new file mode 100644 index 0000000000..bb650882c3 --- /dev/null +++ b/cmake/dependencies/SetupAbseil.cmake @@ -0,0 +1,37 @@ +option(YDB_SDK_DOWNLOAD_PACKAGE_ABSEIL "Download and setup Abseil if no Abseil matching version was found" + ${YDB_SDK_DOWNLOAD_PACKAGES} +) +option(YDB_SDK_FORCE_DOWNLOAD_ABSEIL "Download Abseil even if it exists in a system" ${YDB_SDK_DOWNLOAD_PACKAGES}) + +if(NOT YDB_SDK_FORCE_DOWNLOAD_ABSEIL) + set(ABSL_PROPAGATE_CXX_STD ON) + + if(YDB_SDK_DOWNLOAD_PACKAGE_ABSEIL) + find_package(absl QUIET) + else() + find_package(absl REQUIRED) + endif() + + if(absl_FOUND) + return() + endif() +endif() + +include(DownloadUsingCPM) + +cpmaddpackage( + NAME + abseil-cpp + VERSION + 20230802.0 + GIT_TAG + 20230802.0 + GITHUB_REPOSITORY + abseil/abseil-cpp + OPTIONS + "ABSL_PROPAGATE_CXX_STD ON" + "ABSL_ENABLE_INSTALL ON" +) + +mark_targets_as_system("${abseil-cpp_SOURCE_DIR}") +write_package_stub(absl) \ No newline at end of file diff --git a/cmake/dependencies/SetupBase64.cmake b/cmake/dependencies/SetupBase64.cmake new file mode 100644 index 0000000000..9a4c4c5ac2 --- /dev/null +++ b/cmake/dependencies/SetupBase64.cmake @@ -0,0 +1,33 @@ +option(YDB_SDK_DOWNLOAD_PACKAGE_BASE64 "Download and setup Base64 if no Base64 of matching version was found" + ${YDB_SDK_DOWNLOAD_PACKAGES} +) + +set(YDB_SDK_BASE64_VERSION 0.5.2) + +if(NOT YDB_SDK_FORCE_DOWNLOAD_PACKAGES) + if(YDB_SDK_DOWNLOAD_PACKAGE_BASE64) + find_package(base64 QUIET) + else() + find_package(base64 REQUIRED) + endif() + + if(base64_FOUND) + return() + endif() +endif() + +include(DownloadUsingCPM) +cpmaddpackage( + NAME base64 + VERSION ${YDB_SDK_BASE64_VERSION} + GITHUB_REPOSITORY + aklomp/base64 + OPTIONS + "CMAKE_SKIP_INSTALL_RULES ON" +) +write_package_stub(base64) +add_library(aklomp::base64 ALIAS base64) +set(base64_FOUND TRUE) + + + diff --git a/cmake/dependencies/SetupBrotli.cmake b/cmake/dependencies/SetupBrotli.cmake new file mode 100644 index 0000000000..f219be7676 --- /dev/null +++ b/cmake/dependencies/SetupBrotli.cmake @@ -0,0 +1,42 @@ +option(YDB_SDK_DOWNLOAD_PACKAGE_BROTLI "Download and setup Brotli if no Brotli of matching version was found" + ${YDB_SDK_DOWNLOAD_PACKAGES} +) + +set(YDB_SDK_BROTLI_VERSION 1.1.0) + +if(NOT YDB_SDK_FORCE_DOWNLOAD_PACKAGES) + if(YDB_SDK_DOWNLOAD_PACKAGE_BROTLI) + find_package(Brotli ${YDB_SDK_BROTLI_VERSION} QUIET) + else() + find_package(Brotli ${YDB_SDK_BROTLI_VERSION} REQUIRED) + endif() + + if(Brotli_FOUND) + return() + endif() +endif() + +include(DownloadUsingCPM) +cpmaddpackage( + NAME + Brotli + VERSION + ${YDB_SDK_BROTLI_VERSION} + GITHUB_REPOSITORY + google/brotli + OPTIONS + "BROTLI_DISABLE_TESTS TRUE" + "BUILD_SHARED_LIBS OFF" +) + +set(Brotli_FOUND TRUE) +set(Brotli_VERSION ${YDB_SDK_BROTLI_VERSION}) +add_custom_target(Brotli) +write_package_stub(Brotli) + +if(NOT TARGET Brotli::dec) + add_library(Brotli::dec ALIAS brotlidec) +endif() +if(NOT TARGET Brotli::enc) + add_library(Brotli::enc ALIAS brotlienc) +endif() \ No newline at end of file diff --git a/cmake/dependencies/SetupCares.cmake b/cmake/dependencies/SetupCares.cmake new file mode 100644 index 0000000000..e10e387190 --- /dev/null +++ b/cmake/dependencies/SetupCares.cmake @@ -0,0 +1 @@ +# возможно нужен для grpc \ No newline at end of file diff --git a/cmake/dependencies/SetupGrpc.cmake b/cmake/dependencies/SetupGrpc.cmake new file mode 100644 index 0000000000..c34c754524 --- /dev/null +++ b/cmake/dependencies/SetupGrpc.cmake @@ -0,0 +1,111 @@ +cmake_policy(SET CMP0079 NEW) + +option(YDB_SDK_DOWNLOAD_PACKAGE_GRPC "Download and setup gRPC" ${YDB_SDK_DOWNLOAD_PACKAGES}) +option(YDB_SDK_FORCE_DOWNLOAD_GRPC "Download gRPC even if there is an installed system package" + ${YDB_SDK_FORCE_DOWNLOAD_PACKAGES} +) + +set(YDB_SDK_GRPC_VERSION 1.54.3) + +macro(try_find_cmake_grpc) + find_package(gRPC QUIET CONFIG) + if(NOT gRPC_FOUND) + find_package(gRPC QUIET) + endif() + + if(gRPC_FOUND) + # Use the found CMake-enabled gRPC package + get_target_property(PROTO_GRPC_CPP_PLUGIN gRPC::grpc_cpp_plugin LOCATION) + endif() +endmacro() + +macro(try_find_system_grpc) + # Find the system gRPC package + set(GRPC_USE_SYSTEM_PACKAGE + ON + CACHE INTERNAL "" + ) + + if(YDB_SDK_DOWNLOAD_PACKAGE_GRPC) + find_package(YdbSdkGrpc QUIET) + else() + find_package(YdbSdkGrpc REQUIRED) + endif() + + if(YdbSdkGrpc_FOUND) + set(gRPC_VERSION + "${YdbSdkGrpc_VERSION}" + CACHE INTERNAL "" + ) + + if(NOT TARGET gRPC::grpc++) + add_library(gRPC::grpc++ ALIAS YdbSdkGrpc) + endif() + + find_program(PROTO_GRPC_CPP_PLUGIN grpc_cpp_plugin) + find_program(PROTO_GRPC_PYTHON_PLUGIN grpc_python_plugin) + endif() +endmacro() + +if(NOT YDB_SDK_FORCE_DOWNLOAD_GRPC) + try_find_cmake_grpc() + if(gRPC_FOUND) + return() + endif() + + try_find_system_grpc() + if(YdbSdkGrpc_FOUND) + return() + endif() +endif() + + +# include(${CMAKE_CURRENT_LIST_DIR}/SetupAbseil.cmake) +# include(${CMAKE_CURRENT_LIST_DIR}/SetupCAres.cmake) +# include(${CMAKE_CURRENT_LIST_DIR}/SetupProtobuf.cmake) +include(DownloadUsingCPM) + +set(YDB_SDK_GPRC_BUILD_FROM_SOURCE ON) + +cpmaddpackage( + NAME gRPC + VERSION ${YDB_SDK_GRPC_VERSION} + GITHUB_REPOSITORY + grpc/grpc + OPTIONS + "BUILD_SHARED_LIBS OFF" + "CARES_BUILD_TOOLS OFF" + "RE2_BUILD_TESTING OFF" + "OPENSSL_NO_ASM ON" + "gRPC_BUILD_TESTS OFF" + "gRPC_BUILD_GRPC_NODE_PLUGIN OFF" + "gRPC_BUILD_GRPC_OBJECTIVE_C_PLUGIN OFF" + "gRPC_BUILD_GRPC_PHP_PLUGIN OFF" + "gRPC_BUILD_GRPC_RUBY_PLUGIN OFF" + "gRPC_BUILD_GRPC_CSHARP_PLUGIN OFF" + "gRPC_ZLIB_PROVIDER package" + "gRPC_CARES_PROVIDER package" + "gRPC_RE2_PROVIDER package" + "gRPC_SSL_PROVIDER package" + "gRPC_PROTOBUF_PROVIDER package" + "gRPC_BENCHMARK_PROVIDER none" + "gRPC_ABSL_PROVIDER package" + "gRPC_CARES_LIBRARIES c-ares::cares" + "gRPC_INSTALL OFF" + "gRPC_BUILD_GRPC_PYTHON_PLUGIN OFF" +) + +set(gRPC_VERSION "${YDB_SDK_GRPC_VERSION}") +set(PROTO_GRPC_CPP_PLUGIN $) + +write_package_stub(gRPC) +if(NOT TARGET "gRPC::grpc++") + add_library(gRPC::grpc++ ALIAS grpc++) +endif() +if(NOT TARGET "gRPC::grpc_cpp_plugin") + add_executable(gRPC::grpc_cpp_plugin ALIAS grpc_cpp_plugin) +endif() +if(NOT TARGET "gRPC::grpcpp_channelz") + add_library(gRPC::grpcpp_channelz ALIAS grpcpp_channelz) +endif() +mark_targets_as_system("${gRPC_SOURCE_DIR}") diff --git a/cmake/dependencies/SetupJwtCpp.cmake b/cmake/dependencies/SetupJwtCpp.cmake new file mode 100644 index 0000000000..8261e85a7b --- /dev/null +++ b/cmake/dependencies/SetupJwtCpp.cmake @@ -0,0 +1,32 @@ +option(YDB_SDK_DOWNLOAD_PACKAGE_JWT_CPP "Download and setup jwt-cpp if no jwt-cpp of matching version was found" + ${YDB_SDK_DOWNLOAD_PACKAGES} +) + +set(YDB_SDK_JWT_CPP_VERSION 0.7.0) + +if(NOT YDB_SDK_FORCE_DOWNLOAD_PACKAGES) + if(YDB_SDK_DOWNLOAD_PACKAGE_JWT_CPP) + find_package(jwt-cpp QUIET) + else() + find_package(jwt-cpp REQUIRED) + endif() + + if(jwt-cpp_FOUND) + return() + endif() +endif() + +include(DownloadUsingCPM) +cpmaddpackage( + NAME + jwt-cpp + VERSION + ${YDB_SDK_JWT_CPP_VERSION} + GITHUB_REPOSITORY + Thalhammer/jwt-cpp + OPTIONS + "JWT_BUILD_EXAMPLES OFF" + "CMAKE_SKIP_INSTALL_RULES ON" +) +write_package_stub(jwt-cpp) +set(jwt-cpp_FOUND TRUE) diff --git a/cmake/dependencies/SetupProtobuf.cmake b/cmake/dependencies/SetupProtobuf.cmake new file mode 100644 index 0000000000..ff6dd9962b --- /dev/null +++ b/cmake/dependencies/SetupProtobuf.cmake @@ -0,0 +1,49 @@ +option(YDB_SDK_DOWNLOAD_PACKAGE_PROTOBUF "Download and setup Protobuf" ${YDB_SDK_DOWNLOAD_PACKAGES}) +option(YDB_SDK_FORCE_DOWNLOAD_PROTOBUF "Download Protobuf even if there is an installed system package" + ${YDB_SDK_FORCE_DOWNLOAD_PACKAGES} +) + +set(YDB_SDK_PROTOBUF_VERSION 3.21.12) + +if(NOT YDB_SDK_FORCE_DOWNLOAD_PROTOBUF) + find_package(Protobuf QUIET) +endif() + +if(NOT Protobuf_FOUND) + message(STATUS "Could not find Protobuf package. Downloading and building from source.") + + include(DownloadUsingCPM) + include(${CMAKE_CURRENT_LIST_DIR}/SetupAbseil.cmake) + + + cpmaddpackage( + NAME Protobuf + VERSION ${YDB_SDK_PROTOBUF_VERSION} + GITHUB_REPOSITORY protocolbuffers/protobuf + OPTIONS + "protobuf_BUILD_SHARED_LIBS OFF" + "protobuf_BUILD_TESTS OFF" + "protobuf_INSTALL OFF" + "protobuf_ABSL_PROVIDER package" + ) + + if(NOT TARGET Protobuf::libprotobuf) + add_library(Protobuf::libprotobuf ALIAS libprotobuf) + endif() + if(NOT TARGET Protobuf::libprotoc) + add_library(Protobuf::libprotoc ALIAS libprotoc) + endif() + if(NOT TARGET Protobuf::protoc) + add_executable(Protobuf::protoc ALIAS protoc) + endif() +endif() + +if(NOT Protobuf_VERSION) + set(Protobuf_VERSION ${YDB_SDK_PROTOBUF_VERSION}) +endif() + + +set(PROTOBUF_PROTOC $) + +set(Protobuf_FOUND TRUE CACHE INTERNAL "Protobuf library is found") +message(STATUS "Using Protobuf version ${Protobuf_VERSION} (compiler: ${PROTOBUF_PROTOC})") \ No newline at end of file diff --git a/cmake/external_libs.cmake b/cmake/external_libs.cmake index dc46fdb1d5..ec28d91799 100644 --- a/cmake/external_libs.cmake +++ b/cmake/external_libs.cmake @@ -1,17 +1,16 @@ +include(${CMAKE_CURRENT_LIST_DIR}/dependencies.cmake) + find_package(IDN REQUIRED) find_package(Iconv REQUIRED) find_package(OpenSSL REQUIRED) -find_package(Protobuf REQUIRED) -find_package(gRPC 1.41.0 REQUIRED) +find_package(Protobuf REQUIRED) # потом удалить +find_package(gRPC 1.41.0 REQUIRED) # потом удалить find_package(ZLIB REQUIRED) find_package(xxHash REQUIRED) find_package(ZSTD REQUIRED) find_package(BZip2 REQUIRED) find_package(LZ4 REQUIRED) find_package(Snappy 1.1.8 REQUIRED) -find_package(base64 REQUIRED) -find_package(Brotli 1.1.0 REQUIRED) -find_package(jwt-cpp REQUIRED) find_package(double-conversion REQUIRED) # RapidJSON diff --git a/cmake/testing.cmake b/cmake/testing.cmake index 1319cb1689..7428b85c0b 100644 --- a/cmake/testing.cmake +++ b/cmake/testing.cmake @@ -2,6 +2,7 @@ enable_testing() include(FetchContent) +#todo можно перенести на CPM FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git