mumble-voip_mumble/cmake/delayed_configure_files.cmake

116 lines
5.2 KiB
CMake

# Copyright 2022-2023 The Mumble Developers. All rights reserved.
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file at the root of the
# Mumble source tree or at <https://www.mumble.info/LICENSE>.
# This function allows to delay calls to configure_file to the post-build phase. This can become necessary, if one wants to
# use the result of generator expressions for the substitutions performed via configure_file. Generator expressions are only
# evaluated at build time, while configure_file runs at configure time. To work around this issue, this function will create
# an auxiliary target that generates a new cmake script at build time and this cmake script in turn will call configure_file.
# The variables set in that cmake script are passed as arguments to this function. Since the auxiliary script is generated
# at build time, generator expressions can be used in the variable definitions.
#
# Parameters:
# PYTHON_INTERPRETER <path> Path to a working Python interpreter. Mandatory argument.
# FILES <inFile=outFile> ... Set of files to configure as key-value-pairs (in-file=out-file). Mandatory argument.
# TARGET <target> If given, it is made sure that <target> is fully built, before the configure_file action happens
# SCRIPT_NAME <name> The name of the auxiliary cmake script. If not provided, a default name is generated
# PASSTHROUGH_VARIABLES <var> ... Set of existing variables to pass-through to the generated script so that they can be used
# in the configured file(s).
# VARIABLES <name=value> ... Set of additional variables defined as key-value-pairs. The definition of <value> may make
# use of generator expressions.
# @ONLY Passes the @ONLY parameter to the generated configure_file invocations
function(delayed_configure_files)
set(options "@ONLY")
set(oneValueArgs TARGET SCRIPT_NAME PYTHON_INTERPRETER)
set(multiValueArgs FILES PASSTHROUGH_VARIABLES VARIABLES)
cmake_parse_arguments(DELAYED_CONFIGURE_FILES "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(DELAYED_CONFIGURE_FILES_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unrecognized arguments to delayed_configure_file: \"${DELAYED_CONFIGURE_FILES_UNPARSED_ARGUMENTS}\"")
endif()
# Check required args
if(NOT DELAYED_CONFIGURE_FILES_FILES)
message(FATAL_ERROR "Called delayed_configure_files without the FILES parameter")
endif()
if(DELAYED_CONFIGURE_FILES_TARGET)
if(NOT TARGET ${DELAYED_CONFIGURE_FILES_TARGET})
message(FATAL_ERROR "delayed_configure_files: Provided target \"${DELAYED_CONFIGURE_FILES_TARGET}\" is not actually a (valid) target")
endif()
endif()
if(NOT DELAYED_CONFIGURE_FILES_PYTHON_INTERPRETER)
message(FATAL_ERROR "Called delayed_configure_files without the PYTHON_INTERPRETER parameter")
endif()
# Generate a free target name
set(AUX_TARGET_NUM 1)
set(AUX_TARGET_BASENAME "delayed_configure_files_target_")
while(TARGET "${AUX_TARGET_BASENAME}${AUX_TARGET_NUM}")
math(EXPR AUX_TARGET_NUM "${AUX_TARGET_NUM} + 1")
endwhile()
set(AUX_TARGET_NAME "${AUX_TARGET_BASENAME}${AUX_TARGET_NUM}")
# Handle defaults
if(NOT DELAYED_CONFIGURE_FILES_SCRIPT_NAME)
set(DELAYED_CONFIGURE_FILES_SCRIPT_NAME "configure_files_${AUX_TARGET_NUM}.cmake")
endif()
if(DELAYED_CONFIGURE_FILES_@ONLY)
set(AT_ONLY "--at-only")
else()
set(AT_ONLY "")
endif()
if(DELAYED_CONFIGURE_FILES_VARIABLES)
set(VARIABLES ${DELAYED_CONFIGURE_FILES_VARIABLES})
else()
set(VARIABLES "")
endif()
if(DELAYED_CONFIGURE_FILES_PASSTHROUGH_VARIABLES)
foreach(CURRENT_VAR IN LISTS DELAYED_CONFIGURE_FILES_PASSTHROUGH_VARIABLES)
if(NOT DEFINED ${CURRENT_VAR})
message(FATAL_ERROR "delayed_configure_files: Can't passthrough non-existing variable \"${CURRENT_VAR}\"")
endif()
list(APPEND VARIABLES "${CURRENT_VAR}=${${CURRENT_VAR}}")
endforeach()
endif()
if(NOT VARIABLES STREQUAL "")
set(VARIABLES --variables ${VARIABLES})
endif()
# Create a command to generate an intermediary cmake script that will take care of configuring the respective
# files, once executed
add_custom_command(
OUTPUT "${DELAYED_CONFIGURE_FILES_SCRIPT_NAME}"
COMMAND "${DELAYED_CONFIGURE_FILES_PYTHON_INTERPRETER}"
ARGS "${CMAKE_SOURCE_DIR}/scripts/generate_configure_cmake_script.py"
--files ${DELAYED_CONFIGURE_FILES_FILES} ${VARIABLES}
--output "${DELAYED_CONFIGURE_FILES_SCRIPT_NAME}"
${AT_ONLY}
COMMENT "Generating delayed configure script ${DELAYED_CONFIGURE_FILES_SCRIPT_NAME}"
)
# Create a target that will execute the generated cmake script. Make sure that this target will be
# added to the default build target, ensuring that it is always executed.
add_custom_target(
${AUX_TARGET_NAME} ALL
DEPENDS "${DELAYED_CONFIGURE_FILES_SCRIPT_NAME}"
COMMAND "${CMAKE_COMMAND}" -P "${DELAYED_CONFIGURE_FILES_SCRIPT_NAME}"
COMMENT "Executing delayed configure script ${DELAYED_CONFIGURE_FILES_SCRIPT_NAME}"
)
if(DELAYED_CONFIGURE_FILES_TARGET)
# Make our auxiliary target depend on the provided main target to ensure that the main target is always built
# before our auxiliary target executes.
add_dependencies(${AUX_TARGET_NAME} ${DELAYED_CONFIGURE_FILES_TARGET})
endif()
endfunction()