Skip to content

Commit

Permalink
Revise CMake integration for prometheus-cpp
Browse files Browse the repository at this point in the history
The prometheus-cpp library does not really play nice as a sub-module.
For one, the embedded civetweb prints to console when using build type
debug. We also must make sure to not install prometheus-cpp alongside
Zeek/Broker. Furthermore, prometheus-cpp has packages in several Linux
distributions and package maintainers should be able to have Zeek/Broker
pick up prometheus-cpp as system dependency.

To better separate prometheus-cpp from our targets, we introduce a small
CMake abstraction that will build the library separately to isolate it
from other targets. Then, we use `find_package` to pick up the (static)
library from our build directory. Further, by setting
`prometheus-cpp_ROOT`, users can cause CMake to pick up an existing
installation of the library.
  • Loading branch information
Neverlord committed May 4, 2024
1 parent 2433a72 commit 7a48113
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 43 deletions.
68 changes: 25 additions & 43 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
$<BUILD_INTERFACE:${dl_prometheus_cpp_SOURCE_DIR}/core/include>
$<BUILD_INTERFACE:${dl_prometheus_cpp_BINARY_DIR}/core/include>
$<BUILD_INTERFACE:${dl_prometheus_cpp_SOURCE_DIR}/pull/include>
$<BUILD_INTERFACE:${dl_prometheus_cpp_BINARY_DIR}/pull/include>)
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
$<BUILD_INTERFACE:prometheus-cpp::core>
$<BUILD_INTERFACE: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)
# 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
Expand Down
117 changes: 117 additions & 0 deletions ZeekBundle.cmake
Original file line number Diff line number Diff line change
@@ -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 <name>
# FETCH (URL <url> | GIT_REPOSITORY <repo> GIT_TAG <tag> | SOURCE_DIR <path>)
# [CONFIGURE <args>]
# )
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 ()

0 comments on commit 7a48113

Please sign in to comment.