1 macro(_parse_arguments_with_multi_hack ORIGINAL_COMMAND_LINE)
2 # cmake_parse_arguments() put all the MULTIS in a single variable; you
3 # lose the ability to see for example multiple COMMANDs. To be able to
4 # passthrough multiple MULTIS, we add a marker after every MULTI. This
5 # allows us to reassemble the correct amount again before giving it to
6 # the wrapped command with _reassemble_command_line().
8 set(COMMAND_LINE "${ORIGINAL_COMMAND_LINE}")
10 foreach(MULTI IN LISTS MULTIS)
11 string(REPLACE "${MULTI}" "${MULTI};:::" COMMAND_LINE "${COMMAND_LINE}")
14 cmake_parse_arguments(PARAM "${OPTIONS}" "${SINGLES}" "${MULTIS}" ${COMMAND_LINE})
17 macro(_reassemble_command_line)
18 # Reassemble the command line as we original got it.
19 set(NEW_COMMAND_LINE ${PARAM_UNPARSED_ARGUMENTS})
21 foreach(OPTION IN LISTS OPTIONS)
23 list(APPEND NEW_COMMAND_LINE "${OPTION}")
27 foreach(SINGLE IN LISTS SINGLES)
29 list(APPEND NEW_COMMAND_LINE "${SINGLE}" "${PARAM_${SINGLE}}")
33 foreach(MULTI IN LISTS MULTIS)
35 # Replace our special marker with the name of the MULTI again. This
36 # restores for example multiple COMMANDs again.
37 string(REPLACE ":::" "${MULTI}" PARAM_${MULTI} "${PARAM_${MULTI}}")
38 list(APPEND NEW_COMMAND_LINE "${PARAM_${MULTI}}")
43 # Generated files can be older than their dependencies, causing useless
44 # regenerations. This function replaces each file in OUTPUT with a .timestamp
45 # file, adds a command to touch it and move the original file in BYPRODUCTS,
46 # before calling add_custom_command().
48 # Note: Any add_custom_target() depending on files in original OUTPUT must use
49 # add_custom_target_timestamp() instead to have the correct dependencies.
51 # add_custom_command_timestamp(OUTPUT output1 [output2 ...]
52 # COMMAND command1 [ARGS] [args1...]
53 # [COMMAND command2 [ARGS] [args2...] ...]
54 # [MAIN_DEPENDENCY depend]
55 # [DEPENDS [depends...]]
56 # [BYPRODUCTS [files...]]
57 # [IMPLICIT_DEPENDS <lang1> depend1
58 # [<lang2> depend2] ...]
59 # [WORKING_DIRECTORY dir]
61 # [VERBATIM] [APPEND] [USES_TERMINAL])
62 function(add_custom_command_timestamp)
63 set(OPTIONS VERBATIM APPEND USES_TERMINAL)
64 set(SINGLES MAIN_DEPENDENCY WORKING_DIRECTORY COMMENT)
65 set(MULTIS OUTPUT COMMAND DEPENDS BYPRODUCTS IMPLICIT_DEPENDS)
67 _parse_arguments_with_multi_hack("${ARGN}")
69 # Create a list of all the OUTPUTs (by removing our magic marker)
70 string(REPLACE ":::;" "" OUTPUTS "${PARAM_OUTPUT}")
72 # Reset the OUTPUT and BYPRODUCTS as an empty list (if needed).
73 # Because they are MULTIS, we need to add our special marker here.
74 set(PARAM_OUTPUT ":::")
75 if(NOT PARAM_BYPRODUCTS)
76 set(PARAM_BYPRODUCTS ":::")
79 foreach(OUTPUT IN LISTS OUTPUTS)
80 # For every output, we add a 'cmake -E touch' entry to update the
81 # timestamp on each run.
82 get_filename_component(OUTPUT_FILENAME ${OUTPUT} NAME)
83 string(APPEND PARAM_COMMAND ";:::;${CMAKE_COMMAND};-E;touch;${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILENAME}.timestamp")
85 # We change the OUTPUT to a '.timestamp' variant, and make the real
87 list(APPEND PARAM_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILENAME}.timestamp)
88 list(APPEND PARAM_BYPRODUCTS ${OUTPUT})
90 # Mark this file as being a byproduct; we use this again with
91 # add_custom_target_timestamp() to know if we should point to the
92 # '.timestamp' variant or not.
93 set_source_files_properties(${OUTPUT} PROPERTIES BYPRODUCT ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILENAME}.timestamp)
96 # Reassemble and call the wrapped command
97 _reassemble_command_line()
98 add_custom_command(${NEW_COMMAND_LINE})
101 # Generated files can be older than their dependencies, causing useless
102 # regenerations. This function adds a .timestamp file for each file in DEPENDS
103 # replaced by add_custom_command_timestamp(), before calling add_custom_target().
105 # add_custom_target_timestamp(Name [ALL] [command1 [args1...]]
106 # [COMMAND command2 [args2...] ...]
107 # [DEPENDS depend depend depend ... ]
108 # [BYPRODUCTS [files...]]
109 # [WORKING_DIRECTORY dir]
111 # [VERBATIM] [USES_TERMINAL]
112 # [SOURCES src1 [src2...]])
113 function(add_custom_target_timestamp)
114 set(OPTIONS VERBATIM USES_TERMINAL)
115 set(SINGLES WORKING_DIRECTORY COMMENT)
116 set(MULTIS COMMAND DEPENDS BYPRODUCTS SOURCES)
117 # ALL is missing, as the order is important here. It will be picked up
118 # by ${PARAM_UNPARSED_ARGUMENTS} when reassembling the command line.
120 _parse_arguments_with_multi_hack("${ARGN}")
122 # Create a list of all the DEPENDs (by removing our magic marker)
123 string(REPLACE ":::;" "" DEPENDS "${PARAM_DEPENDS}")
125 # Reset the DEPEND as an empty list.
126 # Because it is a MULTI, we need to add our special marker here.
127 set(PARAM_DEPENDS ":::")
129 foreach(DEPEND IN LISTS DEPENDS)
130 # Check if the output is produced by add_custom_command_timestamp()
131 get_source_file_property(BYPRODUCT ${DEPEND} BYPRODUCT)
133 if(BYPRODUCT STREQUAL "NOTFOUND")
134 # If it is not, just keep it as DEPEND
135 list(APPEND PARAM_DEPENDS "${DEPEND}")
137 # If it is, the BYPRODUCT property points to the timestamp we want to depend on
138 list(APPEND PARAM_DEPENDS "${BYPRODUCT}")
142 # Reassemble and call the wrapped command
143 _reassemble_command_line()
144 add_custom_target(${NEW_COMMAND_LINE})