OpenTTD-patches/cmake/AddCustomXXXTimestamp.cmake
Patric Stout 56d54cf60e Add: introduce CMake for project management
CMake works on all our supported platforms, like MSVC, Mingw, GCC,
Clang, and many more. It allows for a single way of doing things,
so no longer we need shell scripts and vbs scripts to work on all
our supported platforms.

Additionally, CMake allows to generate project files for like MSVC,
KDevelop, etc.

This heavily reduces the lines of code we need to support multiple
platforms from a project perspective.

Addtiionally, this heavily improves our detection of libraries, etc.
2020-06-05 19:36:05 +02:00

146 lines
6.3 KiB
CMake

macro(_parse_arguments_with_multi_hack ORIGINAL_COMMAND_LINE)
# cmake_parse_arguments() put all the MULTIS in a single variable; you
# lose the ability to see for example multiple COMMANDs. To be able to
# passthrough multiple MULTIS, we add a marker after every MULTI. This
# allows us to reassemble the correct amount again before giving it to
# the wrapped command with _reassemble_command_line().
set(COMMAND_LINE "${ORIGINAL_COMMAND_LINE}")
foreach(MULTI IN LISTS MULTIS)
string(REPLACE "${MULTI}" "${MULTI};:::" COMMAND_LINE "${COMMAND_LINE}")
endforeach(MULTI)
cmake_parse_arguments(PARAM "${OPTIONS}" "${SINGLES}" "${MULTIS}" ${COMMAND_LINE})
endmacro()
macro(_reassemble_command_line)
# Reassemble the command line as we original got it.
set(NEW_COMMAND_LINE ${PARAM_UNPARSED_ARGUMENTS})
foreach(OPTION IN LISTS OPTIONS)
if (PARAM_${OPTION})
list(APPEND NEW_COMMAND_LINE "${OPTION}")
endif (PARAM_${OPTION})
endforeach(OPTION)
foreach(SINGLE IN LISTS SINGLES)
if (PARAM_${SINGLE})
list(APPEND NEW_COMMAND_LINE "${SINGLE}" "${PARAM_${SINGLE}}")
endif (PARAM_${SINGLE})
endforeach(SINGLE)
foreach(MULTI IN LISTS MULTIS)
if (PARAM_${MULTI})
# Replace our special marker with the name of the MULTI again. This
# restores for example multiple COMMANDs again.
string(REPLACE ":::" "${MULTI}" PARAM_${MULTI} "${PARAM_${MULTI}}")
list(APPEND NEW_COMMAND_LINE "${PARAM_${MULTI}}")
endif (PARAM_${MULTI})
endforeach(MULTI)
endmacro()
# Generated files can be older than their dependencies, causing useless
# regenerations. This function replaces each file in OUTPUT with a .timestamp
# file, adds a command to touch it and move the original file in BYPRODUCTS,
# before calling add_custom_command().
#
# Note: Any add_custom_target() depending on files in original OUTPUT must use
# add_custom_target_timestamp() instead to have the correct dependencies.
#
# add_custom_command_timestamp(OUTPUT output1 [output2 ...]
# COMMAND command1 [ARGS] [args1...]
# [COMMAND command2 [ARGS] [args2...] ...]
# [MAIN_DEPENDENCY depend]
# [DEPENDS [depends...]]
# [BYPRODUCTS [files...]]
# [IMPLICIT_DEPENDS <lang1> depend1
# [<lang2> depend2] ...]
# [WORKING_DIRECTORY dir]
# [COMMENT comment]
# [VERBATIM] [APPEND] [USES_TERMINAL])
function(add_custom_command_timestamp)
set(OPTIONS VERBATIM APPEND USES_TERMINAL)
set(SINGLES MAIN_DEPENDENCY WORKING_DIRECTORY COMMENT)
set(MULTIS OUTPUT COMMAND DEPENDS BYPRODUCTS IMPLICIT_DEPENDS)
_parse_arguments_with_multi_hack("${ARGN}")
# Create a list of all the OUTPUTs (by removing our magic marker)
string(REPLACE ":::;" "" OUTPUTS "${PARAM_OUTPUT}")
# Reset the OUTPUT and BYPRODUCTS as an empty list (if needed).
# Because they are MULTIS, we need to add our special marker here.
set(PARAM_OUTPUT ":::")
if (NOT PARAM_BYPRODUCTS)
set(PARAM_BYPRODUCTS ":::")
endif ()
foreach(OUTPUT IN LISTS OUTPUTS)
# For every output, we add a 'cmake -E touch' entry to update the
# timestamp on each run.
get_filename_component(OUTPUT_FILENAME ${OUTPUT} NAME)
string(APPEND PARAM_COMMAND ";:::;${CMAKE_COMMAND};-E;touch;${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILENAME}.timestamp")
# We change the OUTPUT to a '.timestamp' variant, and make the real
# output a byproduct.
list(APPEND PARAM_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILENAME}.timestamp)
list(APPEND PARAM_BYPRODUCTS ${OUTPUT})
# Mark this file as being a byproduct; we use this again with
# add_custom_target_timestamp() to know if we should point to the
# '.timestamp' variant or not.
set_source_files_properties(${OUTPUT} PROPERTIES BYPRODUCT ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILENAME}.timestamp)
endforeach(OUTPUT)
# Reassemble and call the wrapped command
_reassemble_command_line()
add_custom_command(${NEW_COMMAND_LINE})
endfunction(add_custom_command_timestamp)
# Generated files can be older than their dependencies, causing useless
# regenerations. This function adds a .timestamp file for each file in DEPENDS
# replaced by add_custom_command_timestamp(), before calling add_custom_target().
#
# add_custom_target_timestamp(Name [ALL] [command1 [args1...]]
# [COMMAND command2 [args2...] ...]
# [DEPENDS depend depend depend ... ]
# [BYPRODUCTS [files...]]
# [WORKING_DIRECTORY dir]
# [COMMENT comment]
# [VERBATIM] [USES_TERMINAL]
# [SOURCES src1 [src2...]])
function(add_custom_target_timestamp)
set(OPTIONS VERBATIM USES_TERMINAL)
set(SINGLES WORKING_DIRECTORY COMMENT)
set(MULTIS COMMAND DEPENDS BYPRODUCTS SOURCES)
# ALL is missing, as the order is important here. It will be picked up
# by ${PARAM_UNPARSED_ARGUMENTS} when reassembling the command line.
_parse_arguments_with_multi_hack("${ARGN}")
# Create a list of all the DEPENDs (by removing our magic marker)
string(REPLACE ":::;" "" DEPENDS "${PARAM_DEPENDS}")
# Reset the DEPEND as an empty list.
# Because it is a MULTI, we need to add our special marker here.
set(PARAM_DEPENDS ":::")
foreach(DEPEND IN LISTS DEPENDS)
# Check if the output is produced by add_custom_command_timestamp()
get_source_file_property(BYPRODUCT ${DEPEND} BYPRODUCT)
if (BYPRODUCT STREQUAL "NOTFOUND")
# If it is not, just keep it as DEPEND
list(APPEND PARAM_DEPENDS "${DEPEND}")
else (BYPRODUCT STREQUAL "NOTFOUND")
# If it is, the BYPRODUCT property points to the timestamp we want to depend on
list(APPEND PARAM_DEPENDS "${BYPRODUCT}")
endif (BYPRODUCT STREQUAL "NOTFOUND")
endforeach(DEPEND)
# Reassemble and call the wrapped command
_reassemble_command_line()
add_custom_target(${NEW_COMMAND_LINE})
endfunction(add_custom_target_timestamp)