forked from gromacs/gromacs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgmxCustomCommandUtilities.cmake
251 lines (246 loc) · 11.3 KB
/
gmxCustomCommandUtilities.cmake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#
# This file is part of the GROMACS molecular simulation package.
#
# Copyright 2014- The GROMACS Authors
# and the project initiators Erik Lindahl, Berk Hess and David van der Spoel.
# Consult the AUTHORS/COPYING files and https://www.gromacs.org for details.
#
# GROMACS is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1
# of the License, or (at your option) any later version.
#
# GROMACS is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with GROMACS; if not, see
# https://www.gnu.org/licenses, or write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# If you want to redistribute modifications to GROMACS, please
# consider that scientific software is very special. Version
# control is crucial - bugs must be traceable. We will be happy to
# consider code for inclusion in the official distribution, but
# derived work must not be called official GROMACS. Details are found
# in the README & COPYING files - if they are missing, get the
# official version at https://www.gromacs.org.
#
# To help us fund GROMACS development, we humbly ask that you cite
# the research papers on the package. Check out https://www.gromacs.org.
# Helper functions for creating custom commands
#
# CMake semantics of add_custom_command() and add_custom_target() are not
# always very convenient or intuitive for creating commands that do not always
# run. This file provides a gmx_add_custom_output_target() to simplify the
# task. The function also provides some convenience features to remove code
# duplication in some parts of the GROMACS build system.
#
# Additionally, gmx_get_stamp_filename() and gmx_get_files_with_gitattribute()
# are provided independently to help in creating custom commands.
# Helper function to create a stamp file name for a target.
#
# Usage:
# gmx_get_stamp_filename(<variable> <targetname>)
#
# <variable> - name of variable to receive the stamp name
# <targetname> - name of target for which to generate the stamp name
#
# This is used internally by gmx_add_custom_target(... OUTPUT STAMP ...), but
# can also be called directly to create uniform stamp file names throughout the
# build system.
# <targetname> can be any string that is a part of a valid file name; it does
# not need to name an existing or to-be-created target.
function (gmx_get_stamp_filename variable targetname)
set(_filename "${targetname}")
if (NOT "${targetname}" MATCHES "stamp$")
set(_filename "${targetname}-timestamp")
endif()
set(${variable} "${CMAKE_CURRENT_BINARY_DIR}/${_filename}.txt"
PARENT_SCOPE)
endfunction()
# Helper function to tell gmx_add_custom_output_target() the name of an output
# file for a custom target.
#
# Usage:
# gmx_set_custom_target_output(<targetname> <output>)
#
# <targetname> - name of an existing custom target
# <output> - path to the output file produced by the custom target
#
# This is used internally by gmx_add_custom_output_target(), but can also be
# called for targets created with add_custom_target() to make them work with
# the dependency resolution mechanism in gmx_add_custom_output_target() if
# those targets for some reason cannot be created with that command.
function (gmx_set_custom_target_output targetname output)
# Store the output file name in a custom property to be used in dependency
# resolution later.
if (NOT IS_ABSOLUTE ${output})
set(output ${CMAKE_CURRENT_BINARY_DIR}/${output})
endif()
set_property(TARGET ${targetname}
PROPERTY GMX_CUSTOM_TARGET_OUTPUT_FILE ${output})
endfunction()
# More flexible alternative to add_custom_command() and add_custom_target()
# for dependent custom commands. It adds a few convenience features:
# - Adds file-level dependencies between custom targets added with this
# command such that if there is a target-level dependency, it also implies
# that the custom command should always be run if the output file of the
# dependency has been updated.
# - Support for creating custom targets that produce stamp files whenever
# they run successfully, so that other targets can depend on those stamp
# files.
#
# Usage:
# gmx_add_custom_output_target(<target> [RUN_ALWAYS] [ADD_FAST_TARGET]
# OUTPUT <STAMP | <output> >
# [COMMAND <command1> [<args1...>]]
# [COMMAND <command2> [<args2...>]]
# [WORKING_DIRECTORY <dir>]
# [DEPENDS <deps...>]
# [DEPENDS_FILE_LIST <list>]
# [COMMENT <comment>] [USES_TERMINAL])
#
# <target>
# - Name of the custom target to create.
# RUN_ALWAYS
# - Create the command such that it always runs, and may update the output
# file in the process.
# The dependencies listed with DEPENDS are ignored in this case.
# ADD_FAST_TARGET
# - In addition to creating <target>, create a secondary target
# <target>-fast that always runs the same commands, but does not have
# any dependencies. Desired dependencies can be added separately using
# add_dependencies(). This supports cases where some of the dependencies
# are time-consuming to build, and it is possible to build the target
# even without up-to-date dependencies for testing only that part of the
# build.
# OUTPUT
# - Sets the name of the output file from this custom target.
# Can be set to STAMP, in which case a stamp file name is automatically
# generated and commands to touch that stamp whenever the target is made
# are added.
# COMMAND
# - Passed to add_custom_command()/add_custom_target().
# If OUTPUT STAMP is used, then a command to touch the stamp is
# automatically added. In this case, it is allowed to not specify any
# commands explicitly.
# WORKING_DIRECTORY
# - Passed to add_custom_command()/add_custom_target()
# COMMENT
# - Passed to add_custom_command()/add_custom_target()
# USES_TERMINAL
# - Passed to add_custom_command()/add_custom_target()
# DEPENDS
# - Dependencies passed to add_custom_command(). Any targets in this list
# that have been created with gmx_add_custom_output_target() are
# automatically expanded such that the custom command always runs if the
# output of the dependent target changes. It is not necessary to list
# those output files here explicitly.
# DEPENDS_FILE_LIST
# - Names of variables from which dependencies are added verbatim.
# The target expansion described above is not performed for these
# dependencies, and the value passed to the function is the name of a
# list variable, not the list itself. This provides much better
# performance if the dependency list is a long list of source files.
#
# This function does not need a VERBATIM argument; that is always used when
# creating the underlying custom commands/targets.
function (gmx_add_custom_output_target targetname)
# Parse the arguments
# CMakeParseArguments is not suitable, since it does not support the use of
# multiple COMMAND parameters that add_custom_target/command() supports.
set(_option "")
set(_command_args "")
set(_deps "")
set(_output "")
set(_stamp OFF)
set(_always OFF)
set(_add_fast OFF)
foreach (_arg ${ARGN})
if ("x${_arg}" STREQUAL "xRUN_ALWAYS")
set(_always ON)
elseif ("x${_arg}" STREQUAL "xADD_FAST_TARGET")
set(_add_fast ON)
elseif ("x${_arg}" MATCHES "^x(OUTPUT|DEPENDS|DEPENDS_FILE_LIST)$")
set(_option ${_arg})
elseif ("x${_arg}" MATCHES "^x(COMMAND|COMMENT|WORKING_DIRECTORY|USES_TERMINAL)$")
set(_option "PASS")
list(APPEND _command_args "${_arg}")
elseif ("x${_option}" STREQUAL "xDEPENDS")
list(APPEND _deps "${_arg}")
# If the dependency is a target created with this command, also add
# the output file as a dependency.
if (TARGET "${_arg}")
get_property(_target_output
TARGET "${_arg}" PROPERTY GMX_CUSTOM_TARGET_OUTPUT_FILE)
if (_target_output)
list(APPEND _deps ${_target_output})
endif()
endif()
elseif ("x${_option}" STREQUAL "xPASS")
list(APPEND _command_args "${_arg}")
elseif ("x${_option}" STREQUAL "xDEPENDS_FILE_LIST")
list(APPEND _deps ${${_arg}})
elseif ("x${_option}" STREQUAL "xOUTPUT")
if (_output)
message(FATAL_ERROR "Multiple OUTPUTs not supported")
endif()
if ("x${_arg}" STREQUAL "xSTAMP")
gmx_get_stamp_filename(_output ${targetname})
set(_stamp ON)
else()
set(_output ${_arg})
endif()
else()
message(FATAL_ERROR "Unknown option ${_arg}")
endif()
endforeach()
# Add automatically a command to update the stamp if requested
if (_stamp)
list(APPEND _command_args COMMAND ${CMAKE_COMMAND} -E touch ${_output})
endif()
# Create the actual command as requested.
if (NOT _always)
add_custom_command(OUTPUT ${_output}
${_command_args} DEPENDS ${_deps} VERBATIM)
add_custom_target(${targetname} DEPENDS ${_output})
else()
add_custom_target(${targetname} BYPRODUCTS ${_output}
${_command_args} VERBATIM)
endif()
# Store the output file name in a custom property to be used in dependency
# resolution later.
gmx_set_custom_target_output(${targetname} ${_output})
# Create the fast target if requested.
if (_add_fast)
add_custom_target(${targetname}-fast ${_command_args} VERBATIM)
endif()
endfunction()
# Gets list of files in the source tree with the given git attribute set
#
# Usage:
# gmx_get_files_with_gitattribute(<variable> <attribute>)
#
# <variable> - name of variable to receive the file list
# <attribute> - name of git attribute to use
#
# This is useful to generate a list of dependencies for custom commands when
# there is a long list of files that cannot be easily just globbed.
# Using git attributes allows keeping complicated logic out of the build
# system, as expressing such logic in a CMake script that would be reasonably
# fast to evaluate for a long file list is convenient or easy.
function (gmx_get_files_with_gitattribute variable attribute)
execute_process(
COMMAND ${GIT_EXECUTABLE} ls-files
COMMAND ${GIT_EXECUTABLE} check-attr ${attribute} --stdin
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
OUTPUT_VARIABLE _files)
string(REGEX MATCHALL "[^\n]*: ${attribute}: set\n"
_files_with_attr "${_files}")
string(REGEX REPLACE "([^;]*): ${attribute}: set\n" "${PROJECT_SOURCE_DIR}/\\1"
_files "${_files_with_attr}")
set(${variable} ${_files} PARENT_SCOPE)
endfunction()