diff --git a/CMakeLists.txt b/CMakeLists.txt index f2188624..8f2be831 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,9 +2,11 @@ cmake_minimum_required(VERSION 3.15 FATAL_ERROR) project(broker C CXX) + include(CMakePackageConfigHelpers) include(FetchContent) include(GNUInstallDirs) +include(ZeekBundle.cmake) include(cmake/CommonCMakeConfig.cmake) set(BROKER_TEST_TIMEOUT 60) @@ -209,50 +211,30 @@ function(add_bundled_caf) add_subdirectory(caf EXCLUDE_FROM_ALL) endfunction() -FetchContent_Declare( - dl_prometheus_cpp - GIT_REPOSITORY https://github.com/jupp0r/prometheus-cpp.git - GIT_TAG v1.2.4) - -# Bundle prometheus-cpp setup as an interface library. +ZeekBundle_Add( + NAME prometheus-cpp + FETCH + GIT_REPOSITORY https://github.com/jupp0r/prometheus-cpp.git + GIT_TAG v1.2.4 + CONFIGURE + ENABLE_PUSH=OFF + ENABLE_TESTING=OFF + CMAKE_POSITION_INDEPENDENT_CODE=ON) + +# Bundle all prometheus-cpp libraries that we need as single interface library. add_library(broker-prometheus-cpp INTERFACE) - -function(add_prometheus_cpp) - # Skip if already configured. - # Get prometheus-cpp if the target is not already available. - if(NOT TARGET prometheus-cpp::core) - set(BUILD_SHARED_LIBS OFF) # bundle prometheus-cpp as static library - set(ENABLE_PUSH OFF) - set(ENABLE_TESTING OFF) - set(GENERATE_PKGCONFIG OFF) - set(CIVETWEB_ENABLE_DEBUG_TOOLS OFF) - set(OVERRIDE_CXX_STANDARD_FLAGS OFF) - if(NOT dl_prometheus_cpp_POPULATED) - FetchContent_Populate(dl_prometheus_cpp) - add_subdirectory(${dl_prometheus_cpp_SOURCE_DIR} - ${dl_prometheus_cpp_BINARY_DIR} - EXCLUDE_FROM_ALL) - endif() - # Tell CMake to look for the headers in the build tree. - target_include_directories( - broker-prometheus-cpp - INTERFACE - $ - $ - $ - $) - endif() - # Link against prometheus-cpp. - target_link_libraries( - broker-prometheus-cpp - INTERFACE - prometheus-cpp::core - prometheus-cpp::pull) - # Prometheus-cpp sets cxx_std_11, but we need cxx_std_17. - target_compile_features(broker-prometheus-cpp INTERFACE cxx_std_17) -endfunction() - -add_prometheus_cpp() +target_link_libraries( + broker-prometheus-cpp + INTERFACE + $ + $) +# Prometheus-cpp sets cxx_std_11, but we need cxx_std_17. +target_compile_features(broker-prometheus-cpp INTERFACE cxx_std_17) +# Keep CMake happy: our Broker targets will depend on broker-prometheus-cpp, so +# this target also must be exported. +install(TARGETS broker-prometheus-cpp + EXPORT BrokerTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR}) # NOTE: building and linking against an external CAF version is NOT supported! # This variable is FOR DEVELOPMENT ONLY. The only officially supported CAF diff --git a/ZeekBundle.cmake b/ZeekBundle.cmake new file mode 100644 index 00000000..7eaa3cec --- /dev/null +++ b/ZeekBundle.cmake @@ -0,0 +1,117 @@ +# CMake dependencies. +include(FetchContent) + +# Override this path +set(ZEEK_BUNDLE_PREFIX "${PROJECT_BINARY_DIR}/zeek-bundle" CACHE STRING + "Path to the Zeek packages cache directory") + +# Opt-in to changed CMake behavior for fetch ZIP files. +if (POLICY CMP0135) + cmake_policy(SET CMP0135 NEW) +endif () + +# Tries to find a package in the Zeek package cache. +function(ZeekBundle_Find name) + find_package(${name} QUIET NO_DEFAULT_PATH HINTS ${ZEEK_BUNDLE_PREFIX}) + if (${name}_FOUND) + set(ZeekBundle_FOUND ON PARENT_SCOPE) + else() + set(ZeekBundle_FOUND OFF PARENT_SCOPE) + endif () +endfunction() + +# Builds an external project at configure time. +function(ZeekBundle_Build name srcDir binDir) + # Extra arguments are passed as CMake options to the external project. + set(cmakeArgs "") + foreach (arg IN LISTS ARGN) + list(APPEND cmakeArgs "-D${arg}") + endforeach () + # Run CMake for the external project. + message(STATUS "Configuring bundled project: ${name}") + execute_process( + COMMAND + "${CMAKE_COMMAND}" + -G "${CMAKE_GENERATOR}" + ${cmakeArgs} + -DCMAKE_BUILD_TYPE=Release + -DBUILD_SHARED_LIBS=OFF + -DENABLE_TESTING=OFF + "-DCMAKE_INSTALL_PREFIX=${ZEEK_BUNDLE_PREFIX}" + "${srcDir}" + WORKING_DIRECTORY "${binDir}" + OUTPUT_FILE "${binDir}/cmake.out" + ERROR_FILE "${binDir}/cmake.err" + RESULT_VARIABLE cmakeResult) + if (NOT cmakeResult EQUAL 0) + message(FATAL_ERROR "Failed to configure external project: ${srcDir}!\nSee ${binDir}/cmake.out and ${binDir}/cmake.err for details.") + endif () + # Build the external project. + message(STATUS "Building bundled project: ${name}") + execute_process( + COMMAND + "${CMAKE_COMMAND}" + --build "${binDir}" + --config Release + OUTPUT_FILE "${binDir}/build.out" + ERROR_FILE "${binDir}/build.err" + RESULT_VARIABLE buildResult) + if (NOT buildResult EQUAL 0) + message(FATAL_ERROR "Failed to build external project: ${srcDir}!\nSee ${binDir}/build.out and ${binDir}/build.err for details.") + endif () + # Install the external project. + message(STATUS "Installing bundled project: ${name}") + execute_process( + COMMAND + "${CMAKE_COMMAND}" + --build "${binDir}" + --config Release + --target install + OUTPUT_FILE "${binDir}/install.out" + ERROR_FILE "${binDir}/install.err" + RESULT_VARIABLE installResult) + if (NOT installResult EQUAL 0) + message(FATAL_ERROR "Failed to install external project: ${srcDir}!\nSee ${binDir}/install.out and ${binDir}/install.err for details.") + endif () +endfunction () + +# Adds a bundled package to Zeek. +# +# Usage: +# ZeekBundle_Add( +# NAME +# FETCH (URL | GIT_REPOSITORY GIT_TAG | SOURCE_DIR ) +# [CONFIGURE ] +# ) +function (ZeekBundle_Add) + # Parse the function arguments. + cmake_parse_arguments(arg "" "NAME" "FETCH;CONFIGURE" ${ARGN}) + if (NOT arg_NAME) + message(FATAL_ERROR "ZeekBundle_Add: mandatory argument NAME is missing!") + endif () + if (NOT arg_FETCH) + message(FATAL_ERROR "ZeekBundle_Add: mandatory argument FETCH is missing!") + endif () + # Use find_package if the user explicitly requested the package. + if (DEFINED ${arg_NAME}_ROOT) + message(STATUS "ZeekBundle: use system library for ${arg_NAME}") + find_package(${arg_NAME} QUIET REQUIRED NO_DEFAULT_PATH PATHS ${${arg_NAME}_ROOT}) + return () + endif () + # Check if we already have the package. + ZeekBundle_Find(${arg_NAME}) + if (ZeekBundle_FOUND) + return () + endif () + # Fetch the package by delegating to FetchContent. + FetchContent_Declare(dl_${arg_NAME} ${arg_FETCH}) + string(TOLOWER "dl_${arg_NAME}" internalName) + FetchContent_Populate(${internalName}) + # Build the package and verify that it was found. + ZeekBundle_Build( + ${arg_NAME} + "${${internalName}_SOURCE_DIR}" + "${${internalName}_BINARY_DIR}" + ${arg_CONFIGURE}) + find_package(${arg_NAME} QUIET REQUIRED NO_DEFAULT_PATH PATHS ${ZEEK_BUNDLE_PREFIX}) +endfunction ()