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()
|