diff options
Diffstat (limited to 'cmake/delayed_configure_files.cmake')
-rw-r--r-- | cmake/delayed_configure_files.cmake | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/cmake/delayed_configure_files.cmake b/cmake/delayed_configure_files.cmake new file mode 100644 index 000000000..c75200564 --- /dev/null +++ b/cmake/delayed_configure_files.cmake @@ -0,0 +1,115 @@ +# Copyright 2022 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() |