Skip to content

Commit

Permalink
Add ZeekBundle for integrating third-party components into our builds
Browse files Browse the repository at this point in the history
This provides an experimental alternative configuration & build approach for
third-party submodules. It introduces a small CMake abstraction that will build
the library separately at configuration time to isolate it from other
targets. Then, we use `find_package` to pick up the (static) library from our
build directory.

For an example of its use, see Broker's CMakeLists.txt.

Co-authored-by: Christian Kreibich <[email protected]>
  • Loading branch information
Neverlord and ckreibich committed Jul 11, 2024
1 parent db0d527 commit ad08eb1
Showing 1 changed file with 138 additions and 0 deletions.
138 changes: 138 additions & 0 deletions ZeekBundle.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# CMake dependencies.
include(FetchContent)

# Users may override this path to place the compiled packages elsewhere.
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 fetching 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} CONFIG 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 ()

# Runs the build and install steps for an external project.
function (ZeekBundle_BuildStep name type binDir)
# Build the external project.
message(STATUS "Building bundled project: ${name} as ${type}")
execute_process(
COMMAND "${CMAKE_COMMAND}" --build "${binDir}" --config ${type}
OUTPUT_FILE "${binDir}/build${type}.out"
ERROR_FILE "${binDir}/build${type}.err"
RESULT_VARIABLE buildResult)
if (NOT buildResult EQUAL 0)
file(READ "${binDir}/build${type}.err" cmakeErr)
message(FATAL_ERROR "Failed to build ${name}:\n\n${cmakeErr}")
endif ()
# Install the external project.
message(STATUS "Installing bundled project: ${name} as ${type}")
execute_process(
COMMAND "${CMAKE_COMMAND}" --build "${binDir}" --config ${type} --target install
OUTPUT_FILE "${binDir}/install${type}.out"
ERROR_FILE "${binDir}/install${type}.err"
RESULT_VARIABLE installResult)
if (NOT installResult EQUAL 0)
file(READ "${binDir}/install${type}.err" cmakeErr)
message(FATAL_ERROR "Failed to install ${name}:\n\n${cmakeErr}")
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 ()
# Make sure we can build debug and release versions of the project separately.
list(APPEND cmakeArgs "-DCMAKE_DEBUG_POSTFIX=d")
# Run CMake for the external project.
message(STATUS "Configuring bundled project: ${name}")
execute_process(
COMMAND
"${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" ${cmakeArgs} -DBUILD_SHARED_LIBS=OFF
-DCMAKE_POSITION_INDEPENDENT_CODE=ON -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)
file(READ "${binDir}/cmake.err" cmakeErr)
message(FATAL_ERROR "Failed to configure external project ${name}:\n\n${cmakeErr}")
endif ()
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if (isMultiConfig)
zeekbundle_buildstep(${name} Debug ${binDir})
zeekbundle_buildstep(${name} Release ${binDir})
else ()
# On Windows, we cannot mix debug and release libraries.
if (WIN32)
zeekbundle_buildstep(${name} ${CMAKE_BUILD_TYPE} ${binDir})
else ()
zeekbundle_buildstep(${name} Release ${binDir})
endif ()
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}
CONFIG
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}
CONFIG
QUIET
REQUIRED
NO_DEFAULT_PATH
PATHS
${ZEEK_BUNDLE_PREFIX})
endfunction ()

0 comments on commit ad08eb1

Please sign in to comment.