2 # This file is part of the GROMACS molecular simulation package.
4 # Copyright (c) 2014, by the GROMACS development team, led by
5 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 # and including many others, as listed in the AUTHORS file in the
7 # top-level source directory and at http://www.gromacs.org.
9 # GROMACS is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU Lesser General Public License
11 # as published by the Free Software Foundation; either version 2.1
12 # of the License, or (at your option) any later version.
14 # GROMACS is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 # Lesser General Public License for more details.
19 # You should have received a copy of the GNU Lesser General Public
20 # License along with GROMACS; if not, see
21 # http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 # If you want to redistribute modifications to GROMACS, please
25 # consider that scientific software is very special. Version
26 # control is crucial - bugs must be traceable. We will be happy to
27 # consider code for inclusion in the official distribution, but
28 # derived work must not be called official GROMACS. Details are found
29 # in the README & COPYING files - if they are missing, get the
30 # official version at http://www.gromacs.org.
32 # To help us fund GROMACS development, we humbly ask that you cite
33 # the research papers on the package. Check out http://www.gromacs.org.
35 # Helper functions for creating custom commands
37 # CMake semantics of add_custom_command() and add_custom_target() are not
38 # always very convenient or intuitive for creating commands that do not always
39 # run. This file provides a gmx_add_custom_output_target() to simplify the
40 # task. The function also provides some convenience features to remove code
41 # duplication in some parts of the GROMACS build system.
43 # Additionally, gmx_get_stamp_filename() and gmx_get_files_with_gitattribute()
44 # are provided independently to help in creating custom commands.
46 # Helper function to create a stamp file name for a target.
49 # gmx_get_stamp_filename(<variable> <targetname>)
51 # <variable> - name of variable to receive the stamp name
52 # <targetname> - name of target for which to generate the stamp name
54 # This is used internally by gmx_add_custom_target(... OUTPUT STAMP ...), but
55 # can also be called directly to create uniform stamp file names throughout the
57 # <targetname> can be any string that is a part of a valid file name; it does
58 # not need to name an existing or to-be-created target.
59 function (gmx_get_stamp_filename variable targetname)
60 set(_filename "${targetname}")
61 if (NOT "${targetname}" MATCHES "stamp$")
62 set(_filename "${targetname}-timestamp")
64 set(${variable} "${CMAKE_CURRENT_BINARY_DIR}/${_filename}.txt"
68 # More flexible alternative to add_custom_command() and add_custom_target()
69 # for dependent custom commands. It adds a few convenience features:
70 # - Support for custom commands that always run (like add_custom_target()),
71 # but still have the ability to act as dependencies of other custom
72 # commands (such that the dependent commands run only if the output
73 # has been updated) also for Ninja.
74 # - Adds file-level dependencies between custom targets added with this
75 # command such that if there is a target-level dependency, it also implies
76 # that the custom command should always be run if the output file of the
77 # dependency has been updated.
78 # - Support for creating custom targets that produce stamp files whenever
79 # they run successfully, so that other targets can depend on those stamp
83 # gmx_add_custom_output_target(<target> [RUN_ALWAYS] [ADD_FAST_TARGET]
84 # OUTPUT <STAMP | <output> >
85 # [COMMAND <command1> [<args1...>]]
86 # [COMMAND <command2> [<args2...>]]
87 # [WORKING_DIRECTORY <dir>]
89 # [DEPENDS_FILE_LIST <list>]
90 # [COMMENT <comment>])
93 # - Name of the custom target to create.
95 # - Create the command such that it always runs.
96 # This takes care of differences between the Ninja generator and others,
97 # which require different rules to make this happen such that
98 # dependencies on the output of the target work correctly, also in the
99 # case the command does not always update the timestamp of the output.
100 # The dependencies listed with DEPENDS are ignored in this case.
102 # - In addition to creating <target>, create a secondary target
103 # <target>-fast that always runs the same commands, but does not have
104 # any dependencies. Desired dependencies can be added separately using
105 # add_dependencies(). This supports cases where some of the dependencies
106 # are time-consuming to build, and it is possible to build the target
107 # even without up-to-date dependencies for testing only that part of the
110 # - Sets the name of the output file from this custom target.
111 # Can be set to STAMP, in which case a stamp file name is automatically
112 # generated and commands to touch that stamp whenever the target is made
115 # - Passed to add_custom_command()/add_custom_target().
116 # If OUTPUT STAMP is used, then a command to touch the stamp is
117 # automatically added. In this case, it is allowed to not specify any
118 # commands explicitly.
120 # - Passed to add_custom_command()/add_custom_target()
122 # - Passed to add_custom_command()/add_custom_target()
124 # - Dependencies passed to add_custom_command(). Any targets in this list
125 # that have been created with gmx_add_custom_output_target() are
126 # automatically expanded such that the custom command always runs if the
127 # output of the dependent target changes. It is not necessary to list
128 # those output files here explicitly.
130 # - Names of variables from which dependencies are added verbatim.
131 # The target expansion described above is not performed for these
132 # dependencies, and the value passed to the function is the name of a
133 # list variable, not the list itself. This provides much better
134 # performance if the dependency list is a long list of source files.
136 # This function does not need a VERBATIM argument; that is always used when
137 # creating the underlying custom commands/targets.
138 function (gmx_add_custom_output_target targetname)
139 # Parse the arguments
140 # CMakeParseArguments is not suitable, since it does not support the use of
141 # multiple COMMAND parameters that add_custom_target/command() supports.
143 set(_command_args "")
149 foreach (_arg ${ARGN})
150 if ("x${_arg}" STREQUAL "xRUN_ALWAYS")
152 elseif ("x${_arg}" STREQUAL "xADD_FAST_TARGET")
154 elseif ("x${_arg}" MATCHES "^x(OUTPUT|DEPENDS|DEPENDS_FILE_LIST)$")
156 elseif ("x${_arg}" MATCHES "^x(COMMAND|COMMENT|WORKING_DIRECTORY)$")
158 list(APPEND _command_args "${_arg}")
159 elseif ("${_option}" STREQUAL "DEPENDS")
160 list(APPEND _deps "${_arg}")
161 # If the dependency is a target created with this command, also add
162 # the output file as a dependency.
163 if (TARGET "${_arg}")
164 get_property(_target_output
165 TARGET "${_arg}" PROPERTY GMX_CUSTOM_TARGET_OUTPUT_FILE)
167 list(APPEND _deps ${_target_output})
170 elseif ("${_option}" STREQUAL "PASS")
171 list(APPEND _command_args "${_arg}")
172 elseif ("${_option}" STREQUAL "DEPENDS_FILE_LIST")
173 list(APPEND _deps ${${_arg}})
174 elseif ("${_option}" STREQUAL "OUTPUT")
176 message(FATAL_ERROR "Multiple OUTPUTs not supported")
178 if ("${_arg}" STREQUAL "STAMP")
179 gmx_get_stamp_filename(_output ${targetname})
185 message(FATAL_ERROR "Unknown option ${_arg}")
188 # Add automatically a command to update the stamp if requested
190 list(APPEND _command_args COMMAND ${CMAKE_COMMAND} -E touch ${_output})
192 # Create the actual command as requested.
194 # If the command does not need to run always, the standard CMake
195 # mechanism is sufficient.
196 add_custom_command(OUTPUT ${_output}
197 ${_command_args} DEPENDS ${_deps} VERBATIM)
198 add_custom_target(${targetname} DEPENDS ${_output})
199 elseif (CMAKE_GENERATOR STREQUAL "Ninja")
200 # Ninja requires all generated files mentioned in dependencies of custom
201 # commands to be actually mentioned in the build system, and luckily
202 # add_custom_command() makes that possible.
203 # But it seems impossible to create a robust custom command that would be
204 # always run, so other generators that do not have this constraint simply
205 # use an add_custom_target().
207 # The second, phony file is never created, so the rule is always
208 # triggered again. TODO: Figure out why this works, even though ninja
209 # very eagerly complains about missing files.
210 # This unfortunately does not work with the make generator, as
211 # the non-existent second file causes some part of the generated system
212 # erase the first file at the beginning of every build, causing a full
213 # rebuild of the dependencies.
214 add_custom_command(OUTPUT ${_output} ${targetname}-phony
215 ${_command_args} VERBATIM)
216 # The generated Ninja build system would probably work fine even
217 # without this target, but CMake requires all custom commands to belong
218 # to a target in the same CMakeLists.txt to generate anything for them.
219 add_custom_target(${targetname} DEPENDS ${_output})
221 # For other generators, a target-level dependency on the custom target
222 # ensures that the output is created before the dependent targets'
223 # dependencies are even evaluated.
224 add_custom_target(${targetname} ${_command_args} VERBATIM)
226 # Store the output file name in a custom property to be used in dependency
228 if (NOT IS_ABSOLUTE ${_output})
229 set(_output ${CMAKE_CURRENT_BINARY_DIR}/${_output})
231 set_property(TARGET ${targetname}
232 PROPERTY GMX_CUSTOM_TARGET_OUTPUT_FILE ${_output})
233 # Create the fast target if requested.
235 add_custom_target(${targetname}-fast ${_command_args} VERBATIM)
239 # Gets list of files in the source tree with the given git attribute set
242 # gmx_get_files_with_gitattribute(<variable> <attribute>)
244 # <variable> - name of variable to receive the file list
245 # <attribute> - name of git attribute to use
247 # This is useful to generate a list of dependencies for custom commands when
248 # there is a long list of files that cannot be easily just globbed.
249 # Using git attributes allows keeping complicated logic out of the build
250 # system, as expressing such logic in a CMake script that would be reasonably
251 # fast to evaluate for a long file list is convenient or easy.
252 function (gmx_get_files_with_gitattribute variable attribute)
254 COMMAND ${GIT_EXECUTABLE} ls-files
255 COMMAND ${GIT_EXECUTABLE} check-attr ${attribute} --stdin
256 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
257 OUTPUT_VARIABLE _files)
258 string(REGEX MATCHALL "[^\n]*: ${attribute}: set\n"
259 _files_with_attr "${_files}")
260 string(REGEX REPLACE "([^;]*): ${attribute}: set\n" "${PROJECT_SOURCE_DIR}/\\1"
261 _files "${_files_with_attr}")
262 set(${variable} ${_files} PARENT_SCOPE)