1# @HEADER 2# ************************************************************************ 3# 4# TriBITS: Tribal Build, Integrate, and Test System 5# Copyright 2013 Sandia Corporation 6# 7# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, 8# the U.S. Government retains certain rights in this software. 9# 10# Redistribution and use in source and binary forms, with or without 11# modification, are permitted provided that the following conditions are 12# met: 13# 14# 1. Redistributions of source code must retain the above copyright 15# notice, this list of conditions and the following disclaimer. 16# 17# 2. Redistributions in binary form must reproduce the above copyright 18# notice, this list of conditions and the following disclaimer in the 19# documentation and/or other materials provided with the distribution. 20# 21# 3. Neither the name of the Corporation nor the names of the 22# contributors may be used to endorse or promote products derived from 23# this software without specific prior written permission. 24# 25# THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY 26# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE 29# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 30# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 31# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 32# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36# 37# ************************************************************************ 38# @HEADER 39 40INCLUDE(CMakeParseArguments) 41 42 43# 44# @FUNCTION: TRIBITS_FIND_MOST_RECENT_FILE_TIMESTAMP() 45# 46# Find the most modified file in a set of base directories and return its 47# timestamp. 48# 49# Usage:: 50# 51# TRIBITS_FIND_MOST_RECENT_FILE_TIMESTAMP( 52# BASE_DIRS <dir0> <dir1> ... 53# [BASE_BASE_DIR <dir>] 54# [EXCLUDE_REGEXES "<re0>" "<re1>" ... 55# [SHOW_MOST_RECENT_FILES] 56# [SHOW_OVERALL_MOST_RECENT_FILE] 57# [MOST_RECENT_TIMESTAMP_OUT <mostRecentTimestamp>] 58# [MOST_RECENT_FILEPATH_BASE_DIR_OUT <mostRecentFilepathBaseDir>] 59# [MOST_RECENT_RELATIVE_FILEPATH_OUT <mostRecentRelativeFilePath>] 60# ) 61# 62# **Arguments:** 63# 64# ``BASE_DIRS <dir0> <dir1> ...`` 65# 66# Gives the absolute base directory paths that will be searched for the 67# most recently modified files, as described above. 68# 69# ``BASE_BASE_DIR <dir>``` 70# 71# Absolute path for which to print file paths relative to. This makes 72# outputting less verbose and easier to read (optional). 73# 74# ``EXCLUDE_REGEXES "<re0>" "<re1>" ...`` 75# 76# Gives the regular expressions that are used to exclude files from 77# consideration. Each "<rei>" regex is used with a `grep -v "<rei>"` 78# filter to exclude files before sorting by time stamp. 79# 80# ``SHOW_MOST_RECENT_FILES`` 81# 82# If specified, then the most recently modified file for each individual 83# directory ``<dir0>``, ``<dir1``, ... will be printed the STDOUT. 84# Setting this implies ``SHOW_OVERALL_MOST_RECENT_FILE``. 85# 86# ``SHOW_OVERALL_MOST_RECENT_FILE`` 87# 88# If specified, then only the most recent modified file over all of the 89# individual directories is printed to STDOUT. 90# 91# ``MOST_RECENT_TIMESTAMP_OUT <mostRecentTimestamp>`` 92# 93# On output, the variable `<mostRecentTimestamp>` is set that gives the 94# timestamp of the most recently modified file over all the directories. 95# This number is given as the number of seconds since Jan. 1, 1970, 00:00 96# GMT. 97# 98# ``MOST_RECENT_FILEPATH_BASE_DIR_OUT <mostRecentFilepathBaseDir>`` 99# 100# On output, the variable `<mostRecentFilepathBaseDir>` gives absolute base 101# directory of the file with the most recent timestamp over all 102# directories. 103# 104# ``MOST_RECENT_RELATIVE_FILEPATH_OUT <mostRecentRelativeFilePath>`` 105# 106# On output, the variable `<mostRecentFilepathBaseDir>` gives the file 107# name with relative path to the file with the most recent timestamp over 108# all directories. 109# 110# **Description:** 111# 112# This function uses the Linux/Unix command:: 113# 114# $ find . -type f -printf '%T@ %p\n' \ 115# | grep -v "<re0>" | grep -v "<re1>" | ... \ 116# | sort -n | tail -1 117# 118# to return the most recent file in each listed directory ``<dir0>``, 119# ``<dir1>``, etc. It then determines the most recently modified file over 120# all of the directories and prints and returns in the variables 121# ``<mostRecentTimestamp>``, ``<mostRecentFilepathBaseDir>``, and 122# ``<mostRecentRelativeFilePath>``. 123# 124FUNCTION(TRIBITS_FIND_MOST_RECENT_FILE_TIMESTAMP) 125 126 IF (TRIBITS_FIND_MOST_RECENT_FILE_TIMESTAMP_DEBUG_DUMP) 127 MESSAGE("\nSearching for most modified files in base dirs:") 128 ENDIF() 129 130 # 131 # A) Parse the input arguments 132 # 133 134 CMAKE_PARSE_ARGUMENTS( 135 #prefix 136 PARSE 137 #options 138 "SHOW_MOST_RECENT_FILES;SHOW_OVERALL_MOST_RECENT_FILES" 139 #one_value_keywords 140 "" 141 #mulit_value_keywords 142 "BASE_DIRS;BASE_BASE_DIR;EXCLUDE_REGEXES;MOST_RECENT_TIMESTAMP_OUT;MOST_RECENT_FILEPATH_BASE_DIR_OUT;MOST_RECENT_RELATIVE_FILEPATH_OUT" 143 ${ARGN} 144 ) 145 146 TRIBITS_CHECK_FOR_UNPARSED_ARGUMENTS() 147 148 IF (PARSE_SHOW_MOST_RECENT_FILES) 149 SET(PARSE_SHOW_OVERALL_MOST_RECENT_FILE ON) 150 ENDIF() 151 152 # 153 # B) Loop over each directory and find the most modified file 154 # 155 156 SET(OVERALL_MOST_RECENT_TIMESTAMP "0000000000.0000000000") 157 SET(OVERALL_MOST_RECENT_FILEPATH "") 158 SET(OVERALL_MOST_RECENT_FILEPATH_DIR "") 159 SET(OVERALL_MOST_RECENT_RELATEIVE_FILEPATH_DIR "") 160 SET(OVERALL_MOST_RECENT_FILEPATH_TIMESTAMP_HUMAN_READABLE "") 161 162 FOREACH(BASE_DIR ${PARSE_BASE_DIRS}) 163 164 IF (TRIBITS_FIND_MOST_RECENT_FILE_TIMESTAMP_DEBUG_DUMP) 165 MESSAGE("\nSearching '${BASE_DIR}' ...") 166 ENDIF() 167 168 IF (IS_DIRECTORY "${BASE_DIR}") 169 170 # Build up commands for grep -v 171 SET(GREP_V_COMMANDS) 172 FOREACH(EXCLUDE_REGEX ${PARSE_EXCLUDE_REGEXES}) 173 APPEND_SET(GREP_V_COMMANDS COMMAND grep -v "${EXCLUDE_REGEX}") 174 ENDFOREACH() 175 176 # Get the time stamp and the file name of the most recently modified file 177 # in currnet directory. 178 EXECUTE_PROCESS( 179 WORKING_DIRECTORY "${BASE_DIR}" 180 COMMAND find . -type f -printf "%T@ %p\n" 181 ${GREP_V_COMMANDS} 182 COMMAND sort -n 183 COMMAND tail -1 184 OUTPUT_VARIABLE MOST_RECENT_TIMESTAMP_AND_FILE 185 OUTPUT_STRIP_TRAILING_WHITESPACE 186 ) 187 # Here, note that %T@ gives the modification time stamp in seconds since 188 # Jan. 1, 1970, 00:00 GMT. The -printf argument %p gives the file path. 189 # This results in the return a string with the modification date (in 190 # fractional seconds) and the file name of the form: 191 # 192 # 1407353359.5651538200 ./<relative-dir>/<some-file-name> 193 194 IF (TRIBITS_FIND_MOST_RECENT_FILE_TIMESTAMP_DEBUG_DUMP) 195 PRINT_VAR(MOST_RECENT_TIMESTAMP_AND_FILE) 196 ENDIF() 197 198 IF (MOST_RECENT_TIMESTAMP_AND_FILE) 199 200 SPLIT("${MOST_RECENT_TIMESTAMP_AND_FILE}" " " 201 MOST_RECENT_TIMESTAMP_AND_FILE_SPLIT) 202 203 # Get the time stamp part 204 LIST(GET MOST_RECENT_TIMESTAMP_AND_FILE_SPLIT 0 205 CURRENT_TIMESTAMP) 206 207 # Get the relative file path 208 LIST(GET MOST_RECENT_TIMESTAMP_AND_FILE_SPLIT 1 209 CURRENT_FILEPATH) 210 211 # Get the directory relative to the base base dir 212 STRING(REPLACE "${PARSE_BASE_BASE_DIR}/" "./" RELATIVE_FILEPATH_DIR 213 "${BASE_DIR}") 214 215 IF (TRIBITS_FIND_MOST_RECENT_FILE_TIMESTAMP_DEBUG_DUMP) 216 PRINT_VAR(CURRENT_TIMESTAMP) 217 PRINT_VAR(CURRENT_FILEPATH) 218 ENDIF() 219 220 IF (PARSE_SHOW_MOST_RECENT_FILES) 221 TRIBITS_GET_HUMAN_READABLE_FILE_AND_TIMESTAMP( 222 "${BASE_DIR}" "${CURRENT_FILEPATH}" 223 HUMAN_READABLE_FILE_AND_TIMESTAMP 224 ) 225 MESSAGE("-- " "Most recent file in ${RELATIVE_FILEPATH_DIR}/" 226 " is ${CURRENT_FILEPATH}\n" 227 " ${HUMAN_READABLE_FILE_AND_TIMESTAMP}") 228 ENDIF() 229 230 IF ("${CURRENT_TIMESTAMP}" GREATER "${OVERALL_MOST_RECENT_TIMESTAMP}") 231 IF (TRIBITS_FIND_MOST_RECENT_FILE_TIMESTAMP_DEBUG_DUMP) 232 MESSAGE(" New most recent file path!") 233 ENDIF() 234 SET(OVERALL_MOST_RECENT_TIMESTAMP "${CURRENT_TIMESTAMP}") 235 SET(OVERALL_MOST_RECENT_RELATIVE_FILEPATH "${CURRENT_FILEPATH}") 236 SET(OVERALL_MOST_RECENT_FILEPATH_DIR "${BASE_DIR}") 237 SET(OVERALL_MOST_RECENT_RELATEIVE_FILEPATH_DIR "${RELATIVE_FILEPATH_DIR}") 238 IF (PARSE_SHOW_OVERALL_MOST_RECENT_FILES) 239 SET(OVERALL_MOST_RECENT_FILEPATH_TIMESTAMP_HUMAN_READABLE 240 "${HUMAN_READABLE_FILE_AND_TIMESTAMP}") 241 ENDIF() 242 ENDIF() 243 244 ENDIF() 245 246 ELSE() 247 248 IF (TRIBITS_FIND_MOST_RECENT_FILE_TIMESTAMP_DEBUG_DUMP) 249 MESSAGE("Directory does not exist, skipping ...") 250 ENDIF() 251 252 ENDIF() 253 254 ENDFOREACH() 255 256 IF (TRIBITS_FIND_MOST_RECENT_FILE_TIMESTAMP_DEBUG_DUMP) 257 PRINT_VAR(OVERALL_MOST_RECENT_TIMESTAMP) 258 PRINT_VAR(OVERALL_MOST_RECENT_RELATIVE_FILEPATH) 259 ENDIF() 260 261 IF (PARSE_SHOW_OVERALL_MOST_RECENT_FILES) 262 IF (OVERALL_MOST_RECENT_FILEPATH_DIR) 263 IF (NOT OVERALL_MOST_RECENT_FILEPATH_TIMESTAMP_HUMAN_READABLE) 264 TRIBITS_GET_HUMAN_READABLE_FILE_AND_TIMESTAMP( 265 "${OVERALL_MOST_RECENT_FILEPATH_DIR}" 266 "${OVERALL_MOST_RECENT_RELATIVE_FILEPATH}" 267 OVERALL_MOST_RECENT_FILEPATH_TIMESTAMP_HUMAN_READABLE 268 ) 269 ENDIF() 270 MESSAGE("-- " "Overall most recent modified file is in" 271 " ${OVERALL_MOST_RECENT_RELATEIVE_FILEPATH_DIR}/ and is ${OVERALL_MOST_RECENT_RELATIVE_FILEPATH}\n" 272 " ${OVERALL_MOST_RECENT_FILEPATH_TIMESTAMP_HUMAN_READABLE}") 273 ELSE() 274 MESSAGE("-- There are no unfiltered files!") 275 ENDIF() 276 ENDIF() 277 278 SET(${PARSE_MOST_RECENT_TIMESTAMP_OUT} 279 ${OVERALL_MOST_RECENT_TIMESTAMP} 280 PARENT_SCOPE) 281 282 IF (PARSE_MOST_RECENT_FILEPATH_BASE_DIR_OUT) 283 SET(${PARSE_MOST_RECENT_FILEPATH_BASE_DIR_OUT} 284 ${OVERALL_MOST_RECENT_FILEPATH_DIR} 285 PARENT_SCOPE) 286 ENDIF() 287 288 IF (PARSE_MOST_RECENT_RELATIVE_FILEPATH_OUT) 289 SET(${PARSE_MOST_RECENT_RELATIVE_FILEPATH_OUT} 290 ${OVERALL_MOST_RECENT_RELATIVE_FILEPATH} 291 PARENT_SCOPE ) 292 ENDIF() 293 294ENDFUNCTION() 295 296 297# 298# @FUNCTION: TRIBITS_FIND_MOST_RECENT_SOURCE_FILE_TIMESTAMP() 299# 300# Find the most modified source file in a set of base directories and return 301# its timestamp. 302# 303# Usage:: 304# 305# TRIBITS_FIND_MOST_RECENT_SOURCE_FILE_TIMESTAMP( 306# SOURCE_BASE_DIRS <dir0> <dir1> ... 307# [SOURCE_BASE_BASE_DIR <dir>] 308# [SHOW_MOST_RECENT_FILES] 309# [SHOW_OVERALL_MOST_RECENT_FILE] 310# [MOST_RECENT_TIMESTAMP_OUT <mostRecentTimestamp>] 311# [MOST_RECENT_FILEPATH_BASE_DIR_OUT <mostRecentFilepathBaseDir>] 312# [MOST_RECENT_RELATIVE_FILEPATH_OUT <mostRecentRelativeFilePath>] 313# ) 314# 315# This function just calls `TRIBITS_FIND_MOST_RECENT_FILE_TIMESTAMP()`_ 316# passing in a set of basic exclude regexes like ``[.]git/``, ``[.]svn/``, 317# etc. These types of version control files can not possibly directly impact 318# the source code. 319# 320FUNCTION(TRIBITS_FIND_MOST_RECENT_SOURCE_FILE_TIMESTAMP) 321 322 # 323 # A) Parse the input arguments 324 # 325 326 CMAKE_PARSE_ARGUMENTS( 327 #prefix 328 PARSE 329 #options 330 "SHOW_MOST_RECENT_FILES;SHOW_OVERALL_MOST_RECENT_FILES" 331 #one_value_keywords 332 "" 333 #multi_value_keywords 334 "SOURCE_BASE_DIRS;SOURCE_BASE_BASE_DIR;MOST_RECENT_TIMESTAMP_OUT;MOST_RECENT_FILEPATH_BASE_DIR_OUT;MOST_RECENT_RELATIVE_FILEPATH_OUT" 335 ${ARGN} 336 ) 337 338 TRIBITS_CHECK_FOR_UNPARSED_ARGUMENTS() 339 340 # 341 # B) Call the function TRIBITS_FIND_MOST_RECENT_FILE_TIMESTAMP() 342 # 343 344 SET(FILTER_OUT_SOURCE_FILE_REGEXS 345 "/[.]git/" 346 ) 347 348 SET(VARIABLE_ARGS) 349 IF (PARSE_SHOW_MOST_RECENT_FILES) 350 APPEND_SET(VARIABLE_ARGS SHOW_MOST_RECENT_FILES) 351 ENDIF() 352 IF (PARSE_SHOW_OVERALL_MOST_RECENT_FILES) 353 APPEND_SET(VARIABLE_ARGS SHOW_OVERALL_MOST_RECENT_FILES) 354 ENDIF() 355 356 #PRINT_VAR(VARIABLE_ARGS) 357 TRIBITS_FIND_MOST_RECENT_FILE_TIMESTAMP( 358 BASE_DIRS ${PARSE_SOURCE_BASE_DIRS} 359 BASE_BASE_DIR ${PARSE_SOURCE_BASE_BASE_DIR} 360 EXCLUDE_REGEXES ${FILTER_OUT_SOURCE_FILE_REGEXS} 361 MOST_RECENT_TIMESTAMP_OUT MOST_RECENT_TIMESTAMP 362 MOST_RECENT_FILEPATH_BASE_DIR_OUT MOST_RECENT_UPSTREAM_SOURCE_TIMESTAMP 363 MOST_RECENT_RELATIVE_FILEPATH_OUT MOST_RECENT_RELATIVE_FILEPATH 364 ${VARIABLE_ARGS} 365 ) 366 #PRINT_VAR(MOST_RECENT_TIMESTAMP) 367 368 SET(${PARSE_MOST_RECENT_TIMESTAMP_OUT} ${MOST_RECENT_TIMESTAMP} 369 PARENT_SCOPE) 370 371 IF (PARSE_MOST_RECENT_FILEPATH_BASE_DIR_OUT) 372 SET(${PARSE_MOST_RECENT_FILEPATH_BASE_DIR_OUT} ${MOST_RECENT_UPSTREAM_SOURCE_TIMESTAMP} 373 PARENT_SCOPE) 374 ENDIF() 375 376 IF (PARSE_MOST_RECENT_RELATIVE_FILEPATH_OUT) 377 SET(${PARSE_MOST_RECENT_RELATIVE_FILEPATH_OUT} ${MOST_RECENT_RELATIVE_FILEPATH} 378 PARENT_SCOPE ) 379 ENDIF() 380 381ENDFUNCTION() 382 383 384# 385# @FUNCTION: TRIBITS_FIND_MOST_RECENT_BINARY_FILE_TIMESTAMP() 386# 387# Find the most modified binary file in a set of base directories and return 388# its timestamp. 389# 390# Usage:: 391# 392# TRIBITS_FIND_MOST_RECENT_BINARY_FILE_TIMESTAMP( 393# BINARY_BASE_DIRS <dir0> <dir1> ... 394# [BINARY_BASE_BASE_DIR <dir>] 395# [MOST_RECENT_TIMESTAMP_OUT <mostRecentTimestamp>] 396# [MOST_RECENT_FILEPATH_BASE_DIR_OUT <mostRecentFilepathBaseDir>] 397# [MOST_RECENT_RELATIVE_FILEPATH_OUT <mostRecentRelativeFilePath>] 398# [SHOW_MOST_RECENT_FILES] 399# [SHOW_OVERALL_MOST_RECENT_FILE] 400# ) 401# 402# This function just calls `TRIBITS_FIND_MOST_RECENT_FILE_TIMESTAMP()`_ 403# passing in a set of basic exclude regexes like ``CMakeFiles/``, 404# ``[.]cmake$``, and ``/Makefile$``, etc. These types of files usually don't 405# impact the build of downstream software in CMake projects. 406# 407FUNCTION(TRIBITS_FIND_MOST_RECENT_BINARY_FILE_TIMESTAMP) 408 409 # 410 # A) Parse the input arguments 411 # 412 413 CMAKE_PARSE_ARGUMENTS( 414 #prefix 415 PARSE 416 #options 417 "SHOW_MOST_RECENT_FILES;SHOW_OVERALL_MOST_RECENT_FILES" 418 #one_value_keywords 419 "" 420 #multi_value_keywords 421 "BINARY_BASE_DIRS;BINARY_BASE_BASE_DIR;MOST_RECENT_TIMESTAMP_OUT;MOST_RECENT_FILEPATH_BASE_DIR_OUT;MOST_RECENT_RELATIVE_FILEPATH_OUT" 422 ${ARGN} 423 ) 424 425 TRIBITS_CHECK_FOR_UNPARSED_ARGUMENTS() 426 427 # 428 # B) Define filters for binary files we know are not significant 429 # 430 431 SET(FILTER_OUT_BINARY_FILE_REGEXS 432 "CMakeFiles/" "[.]cmake$" "/Makefile$" 433 ) 434 435 # 436 # C) Call the function TRIBITS_FIND_MOST_RECENT_FILE_TIMESTAMP() 437 # 438 439 SET(VARIABLE_ARGS) 440 IF (PARSE_SHOW_MOST_RECENT_FILES) 441 APPEND_SET(VARIABLE_ARGS SHOW_MOST_RECENT_FILES) 442 ENDIF() 443 IF (PARSE_SHOW_OVERALL_MOST_RECENT_FILES) 444 APPEND_SET(VARIABLE_ARGS SHOW_OVERALL_MOST_RECENT_FILES) 445 ENDIF() 446 447 #PRINT_VAR(VARIABLE_ARGS) 448 TRIBITS_FIND_MOST_RECENT_FILE_TIMESTAMP( 449 BASE_DIRS ${PARSE_BINARY_BASE_DIRS} 450 BASE_BASE_DIR ${PARSE_BINARY_BASE_BASE_DIR} 451 EXCLUDE_REGEXES ${FILTER_OUT_BINARY_FILE_REGEXS} 452 MOST_RECENT_TIMESTAMP_OUT MOST_RECENT_TIMESTAMP 453 MOST_RECENT_RELATIVE_FILEPATH_OUT MOST_RECENT_RELATIVE_FILEPATH 454 ${VARIABLE_ARGS} 455 ) 456 #PRINT_VAR(MOST_RECENT_TIMESTAMP) 457 458 SET(${PARSE_MOST_RECENT_TIMESTAMP_OUT} ${MOST_RECENT_TIMESTAMP} 459 PARENT_SCOPE) 460 461 IF (PARSE_MOST_RECENT_FILEPATH_BASE_DIR_OUT) 462 SET(${PARSE_MOST_RECENT_FILEPATH_BASE_DIR_OUT} ${MOST_RECENT_UPSTREAM_SOURCE_TIMESTAMP} 463 PARENT_SCOPE) 464 ENDIF() 465 466 IF (PARSE_MOST_RECENT_RELATIVE_FILEPATH_OUT) 467 SET(${PARSE_MOST_RECENT_RELATIVE_FILEPATH_OUT} ${MOST_RECENT_RELATIVE_FILEPATH} 468 PARENT_SCOPE ) 469 ENDIF() 470 471ENDFUNCTION() 472 473 474# 475# @FUNCTION: TRIBITS_DETERMINE_IF_CURRENT_PACKAGE_NEEDS_REBUILT() 476# 477# Determine at configure time if any of the upstream dependencies for a 478# package require the current package to be rebuilt. 479# 480# Usage:: 481# 482# TRIBITS_DETERMINE_IF_CURRENT_PACKAGE_NEEDS_REBUILT( 483# [SHOW_MOST_RECENT_FILES] 484# [SHOW_OVERALL_MOST_RECENT_FILES] 485# CURRENT_PACKAGE_OUT_OF_DATE_OUT <currentPackageOutOfDate> 486# ) 487# 488# **Arguments:** 489# 490# ``SHOW_MOST_RECENT_FILES`` 491# 492# If specified, then the most recently modified file for each individual 493# base source and binary directory searched will be will be printed the 494# STDOUT. Setting this implies ``SHOW_OVERALL_MOST_RECENT_FILE``. 495# 496# ``SHOW_OVERALL_MOST_RECENT_FILE`` 497# 498# If specified, then only the most recent modified file over all of the 499# individual directories for each category (i.e. one for upstream SE 500# package source dirs, one for upstream SE package binary dirs, one for 501# the package's source dir, and one for the package's own binary dir) is 502# printed to STDOUT. 503# 504# ``CURRENT_PACKAGE_OUT_OF_DATE_OUT <currentPackageOutOfDate>`` 505# 506# On output, the local variable ``<currentPackageOutOfDate>`` will be set 507# to ``TRUE`` if any of the upstream most modified files are more recent 508# than the most modified file in the package's binary directory. 509# Otherwise, this variable is set to ``FALSE``. 510# 511# **Description:** 512# 513# This function is designed to help take an externally configured and built 514# piece of software (that generates libraries) and wrap it as a TriBITS 515# package or subpackage. This function uses the lower-level functions: 516# 517# * `TRIBITS_FIND_MOST_RECENT_SOURCE_FILE_TIMESTAMP()`_ 518# * `TRIBITS_FIND_MOST_RECENT_BINARY_FILE_TIMESTAMP()`_ 519# 520# to determine the most recent modified files in the upstream TriBITS SE 521# packages' source and binary directories as well as the most recent source 522# file for the current package. It then compares these timestamps to the most 523# recent binary file timestamp in this package's binary directory. If any of 524# these three files are more recent than this package's most recent binary 525# file, then the output variable ``<currentPackageOutOfDate>`` is set to 526# ``TRUE``. Otherwise, it is set to ``FALSE``. 527# 528# NOTE: The source and binary directories for full packages are searched, not 529# individual subpackage dirs. This is to reduce the number of dirs searched. 530# This will, however, result in changes in non-dependent subpackages being 531# considered as well. 532# 533# See the demonstration of the usage of this function in the ``WrapExternal`` 534# package in `TribitsExampleProject`_. 535# 536FUNCTION(TRIBITS_DETERMINE_IF_CURRENT_PACKAGE_NEEDS_REBUILT) 537 538 IF (${PROJECT_NAME}_ENABLE_CONFIGURE_TIMING) 539 TIMER_GET_RAW_SECONDS(TIMER_START_SECONDS) 540 ENDIF() 541 542 543 # 544 # A) Parse the input arguments 545 # 546 547 CMAKE_PARSE_ARGUMENTS( 548 #prefix 549 PARSE 550 #options 551 "SHOW_MOST_RECENT_FILES;SHOW_OVERALL_MOST_RECENT_FILES" 552 #one_value_keywords 553 "" 554 #mulit_value_keywords 555 "CURRENT_PACKAGE_OUT_OF_DATE_OUT" 556 ${ARGN} 557 ) 558 559 TRIBITS_CHECK_FOR_UNPARSED_ARGUMENTS() 560 561 # Get pass through print level options 562 SET(SHOW_MOST_RECENT_FILES_ARGS) 563 IF (PARSE_SHOW_MOST_RECENT_FILES) 564 APPEND_SET(SHOW_MOST_RECENT_FILES_ARGS SHOW_MOST_RECENT_FILES) 565 ENDIF() 566 IF (PARSE_SHOW_OVERALL_MOST_RECENT_FILES) 567 APPEND_SET(SHOW_MOST_RECENT_FILES_ARGS SHOW_OVERALL_MOST_RECENT_FILES) 568 ENDIF() 569 #PRINT_VAR(SHOW_MOST_RECENT_FILES_ARGS) 570 571 IF (PARSE_SHOW_MOST_RECENT_FILES) 572 SET(PARSE_SHOW_OVERALL_MOST_RECENT_FILES TRUE) 573 ENDIF() 574 575 # 576 # B) Get the list of enabled upstream packages 577 # 578 579 # Only search parent packages to cut down on dirs searched 580 SET(ENABLED_UPSTREAM_PACKAGES) 581 SET(CURRENT_PARENT_PACKAGE) 582 FOREACH(UPSTREAM_SE_PACKAGE ${${PACKAGE_NAME}_FULL_ENABLED_DEP_PACKAGES}) 583 # Assume we will append 584 SET(APPEND_PACKAGE ${UPSTREAM_SE_PACKAGE}) 585 # If is a subpackage we only append the parent packages 586 SET(PARENT_PACKAGE ${${UPSTREAM_SE_PACKAGE}_PARENT_PACKAGE}) 587 IF (PARENT_PACKAGE) 588 SET(APPEND_PACKAGE ${PARENT_PACKAGE}) 589 ENDIF() 590 # Append 591 APPEND_SET(ENABLED_UPSTREAM_PACKAGES ${APPEND_PACKAGE}) 592 ENDFOREACH() 593 LIST(REMOVE_DUPLICATES ENABLED_UPSTREAM_PACKAGES) 594 #PRINT_VAR(ENABLED_UPSTREAM_PACKAGES) 595 596 # 597 # C) Determine the most recent files on the upstream SE packages 598 # 599 600 IF (PARSE_SHOW_OVERALL_MOST_RECENT_FILES) 601 MESSAGE("\nDetermining most recent source file in upstream SE packages" 602 " from ${PACKAGE_NAME}:") 603 ENDIF() 604 SET(UPSTREAM_SOURCE_BASE_DIRS) 605 FOREACH(UPSTREAM_PACKAGE ${ENABLED_UPSTREAM_PACKAGES}) 606 APPEND_SET(UPSTREAM_SOURCE_BASE_DIRS "${${UPSTREAM_PACKAGE}_SOURCE_DIR}") 607 ENDFOREACH() 608 TRIBITS_FIND_MOST_RECENT_SOURCE_FILE_TIMESTAMP( 609 SOURCE_BASE_DIRS ${UPSTREAM_SOURCE_BASE_DIRS} 610 SOURCE_BASE_BASE_DIR "${PROJECT_SOURCE_DIR}" 611 ${SHOW_MOST_RECENT_FILES_ARGS} 612 MOST_RECENT_TIMESTAMP_OUT MOST_RECENT_UPSTREAM_SOURCE_TIMESTAMP 613 MOST_RECENT_RELATIVE_FILEPATH_OUT MOST_RECENT_UPSTREAM_SOURCE_FILEPATH 614 ) 615 #PRINT_VAR(MOST_RECENT_UPSTREAM_SOURCE_FILEPATH) 616 617 IF (PARSE_SHOW_OVERALL_MOST_RECENT_FILES) 618 MESSAGE("\nDetermining most recent binary file in upstream SE packages" 619 " from ${PACKAGE_NAME}:") 620 ENDIF() 621 SET(UPSTREAM_BINARY_BASE_DIRS) 622 FOREACH(UPSTREAM_PACKAGE ${ENABLED_UPSTREAM_PACKAGES}) 623 APPEND_SET(UPSTREAM_BINARY_BASE_DIRS "${${UPSTREAM_PACKAGE}_BINARY_DIR}") 624 ENDFOREACH() 625 TRIBITS_FIND_MOST_RECENT_BINARY_FILE_TIMESTAMP( 626 BINARY_BASE_DIRS ${UPSTREAM_BINARY_BASE_DIRS} 627 BINARY_BASE_BASE_DIR "${PROJECT_BINARY_DIR}" 628 ${SHOW_MOST_RECENT_FILES_ARGS} 629 MOST_RECENT_TIMESTAMP_OUT MOST_RECENT_UPSTREAM_BINARY_TIMESTAMP 630 MOST_RECENT_RELATIVE_FILEPATH_OUT MOST_RECENT_UPSTREAM_BINARY_FILEPATH 631 ) 632 #PRINT_VAR(MOST_RECENT_UPSTREAM_BINARY_FILEPATH) 633 634 # 635 # D) Determine the most recent files for the current package 636 # 637 638 IF (PARSE_SHOW_OVERALL_MOST_RECENT_FILES) 639 MESSAGE("\nDetermining most recent source file for current" 640 " package ${PACKAGE_NAME}:") 641 ENDIF() 642 TRIBITS_FIND_MOST_RECENT_SOURCE_FILE_TIMESTAMP( 643 SOURCE_BASE_DIRS ${${PACKAGE_NAME}_SOURCE_DIR} 644 SOURCE_BASE_BASE_DIR "${PROJECT_SOURCE_DIR}" 645 ${SHOW_MOST_RECENT_FILES_ARGS} 646 MOST_RECENT_TIMESTAMP_OUT MOST_RECENT_THIS_PACKAGE_SOURCE_TIMESTAMP 647 MOST_RECENT_RELATIVE_FILEPATH_OUT MOST_RECENT_THIS_SOURCE_FILEPATH 648 ) 649 650 IF (PARSE_SHOW_OVERALL_MOST_RECENT_FILES) 651 MESSAGE("\nDetermining most recent binary file for current" 652 " package ${PACKAGE_NAME}:") 653 ENDIF() 654 TRIBITS_FIND_MOST_RECENT_BINARY_FILE_TIMESTAMP( 655 BINARY_BASE_DIRS ${${PACKAGE_NAME}_BINARY_DIR} 656 BINARY_BASE_BASE_DIR "${PROJECT_BINARY_DIR}" 657 ${SHOW_MOST_RECENT_FILES_ARGS} 658 MOST_RECENT_TIMESTAMP_OUT MOST_RECENT_THIS_PACKAGE_BINARY_TIMESTAMP 659 MOST_RECENT_RELATIVE_FILEPATH_OUT MOST_RECENT_THIS_BINARY_FILEPATH 660 ) 661 662 # 663 # E) Compare most recent file time stamps to determine if a rebuild is needed 664 # 665 666 SET(CURRENT_PACKAGE_OUT_OF_DATE_OUT FALSE) 667 668 MESSAGE("\nComparing timestamps of recently updated files:") 669 670 IF (MOST_RECENT_THIS_BINARY_FILEPATH) 671 672 TRIBITS_UPDATE_PACKAGE_OUT_OF_DATE( 673 "upstream SE package source" ${MOST_RECENT_UPSTREAM_SOURCE_TIMESTAMP} 674 "${MOST_RECENT_UPSTREAM_SOURCE_FILEPATH}" 675 ${MOST_RECENT_THIS_PACKAGE_BINARY_TIMESTAMP} "${MOST_RECENT_THIS_BINARY_FILEPATH}" 676 CURRENT_PACKAGE_OUT_OF_DATE_OUT ) 677 678 TRIBITS_UPDATE_PACKAGE_OUT_OF_DATE( 679 "upstream SE package binary" ${MOST_RECENT_UPSTREAM_BINARY_TIMESTAMP} 680 "${MOST_RECENT_UPSTREAM_BINARY_FILEPATH}" 681 ${MOST_RECENT_THIS_PACKAGE_BINARY_TIMESTAMP} "${MOST_RECENT_THIS_BINARY_FILEPATH}" 682 CURRENT_PACKAGE_OUT_OF_DATE_OUT ) 683 684 TRIBITS_UPDATE_PACKAGE_OUT_OF_DATE( 685 "this package's source" ${MOST_RECENT_THIS_PACKAGE_SOURCE_TIMESTAMP} 686 "${MOST_RECENT_THIS_SOURCE_FILEPATH}" 687 ${MOST_RECENT_THIS_PACKAGE_BINARY_TIMESTAMP} "${MOST_RECENT_THIS_BINARY_FILEPATH}" 688 CURRENT_PACKAGE_OUT_OF_DATE_OUT ) 689 690 IF (NOT CURRENT_PACKAGE_OUT_OF_DATE_OUT) 691 MESSAGE("-- This package's most recent binary file" 692 " ${MOST_RECENT_THIS_BINARY_FILEPATH}" 693 " is more recent than its upstream SE package source or binary files" 694 " or this package's source files!") 695 ENDIF() 696 697 ELSE() 698 699 MESSAGE("-- This package has no unfiltered binary files so consider out of date!") 700 701 ENDIF() 702 703 SET(${PARSE_CURRENT_PACKAGE_OUT_OF_DATE_OUT} ${CURRENT_PACKAGE_OUT_OF_DATE_OUT} 704 PARENT_SCOPE) 705 706 IF (${PROJECT_NAME}_ENABLE_CONFIGURE_TIMING) 707 TIMER_GET_RAW_SECONDS(TIMER_STOP_SECONDS) 708 TIMER_PRINT_REL_TIME(${TIMER_START_SECONDS} ${TIMER_STOP_SECONDS} 709 "\nTotal time to check for most recent modified files") 710 ENDIF() 711 712ENDFUNCTION() 713 714 715# 716# Utility functions 717# 718 719 720FUNCTION(TRIBITS_UPDATE_PACKAGE_OUT_OF_DATE 721 DEPENDENCY_TYPE_STRING DEP_FILE_TIMESTAMP DEP_FILEPATH 722 THIS_BINARY_FILE_TIMESTAMP THIS_BINARY_FILEPATH 723 CURRENT_PACKAGE_IS_OUT_OF_DATE_INOUT 724 ) 725 IF ("${DEP_FILE_TIMESTAMP}" GREATER "${THIS_BINARY_FILE_TIMESTAMP}") 726 MESSAGE("-- The ${DEPENDENCY_TYPE_STRING} file ${DEP_FILEPATH} is more recent than" 727 " this package's binary file ${THIS_BINARY_FILEPATH}!") 728 SET(${CURRENT_PACKAGE_IS_OUT_OF_DATE_INOUT} TRUE PARENT_SCOPE) 729 ENDIF() 730ENDFUNCTION() 731 732 733FUNCTION(TRIBITS_GET_HUMAN_READABLE_FILE_AND_TIMESTAMP 734 BASE_DIR CURRENT_FILEPATH 735 HUMAN_READABLE_FILE_AND_TIMESTAMP_OUT 736 ) 737 EXECUTE_PROCESS( 738 WORKING_DIRECTORY "${BASE_DIR}" 739 COMMAND ls --full-time "${CURRENT_FILEPATH}" 740 OUTPUT_STRIP_TRAILING_WHITESPACE 741 OUTPUT_VARIABLE HUMAN_READABLE_FILE_AND_TIMESTAMP 742 ) 743 SET(${HUMAN_READABLE_FILE_AND_TIMESTAMP_OUT} 744 ${HUMAN_READABLE_FILE_AND_TIMESTAMP} 745 PARENT_SCOPE) 746ENDFUNCTION() 747 748 749 750 751 752# LocalWords: ENDFOREACH subpackage subpackages TriBITS timestamp 753