CommandExecution.cmake 3.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. #
  2. # Copyright (c) Contributors to the Open 3D Engine Project.
  3. # For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. #
  5. # SPDX-License-Identifier: Apache-2.0 OR MIT
  6. #
  7. #
  8. # CMake utility that provides functionality around command execution
  9. # It provides:
  10. # - ability to avoid the execution altogether by creating a .stamp file and comparing it to the "file reference".
  11. # Related to https://gitlab.kitware.com/cmake/cmake/issues/18530
  12. # - ability to lock the execution by creating a .lock file of the "file reference"
  13. #
  14. # This script has to be invoked like:
  15. # cmake -DLY_LOCK_FILE=<lock file> -P cmake/CommandExecution.cmake EXEC_COMMAND commandToExecute1 <EXEC_COMMAND commandToExecute2> ...
  16. # In the above case, all the commands will be locked on <lock file>. Meaning that there could be only one instance executing at the
  17. # the same time. Since we provide flexibility on what file gets locked, multiple invocations could be done with different commands.
  18. # The lock file acts as a mutex over a certain "resource" that the caller is trying to control access to.
  19. # cmake -DLY_TIMESTAMP_REFERENCE=<referencefile> [-DLY_TIMESTAMP_FILE=<referencefile>] -P cmake/CommandExecution.cmake EXEC_COMMAND commandToExecute1 <EXEC_COMMAND commandToExecute2> ...
  20. # In this case, the file's timestamp of LY_TIMESTAMP_REFERENCE will be compared to LY_TIMESTAMP_FILE, if newer, it will execute the commands
  21. # If LY_TIMESTAMP_FILE is not passed, then ${LY_TIMESTAMP_REFERENCE}.stamp is used
  22. #
  23. # If LY_LOCK_FILE and LY_TIMESTAMP_REFERENCE are not passed, then the commands are executed.
  24. #
  25. # Find the first "EXEC_COMMAND"
  26. set(argiP 0)
  27. foreach(argi RANGE 3 ${CMAKE_ARGC}) # at least skip the command name and the "-P" argument
  28. if(CMAKE_ARGV${argi} STREQUAL EXEC_COMMAND)
  29. set(argiP ${argi})
  30. break()
  31. endif()
  32. endforeach()
  33. if(NOT argiP)
  34. message(FATAL_ERROR "Could not find argument \"EXEC_COMMAND\", please indicate at least one command to execute")
  35. endif()
  36. # Check for timestamp
  37. if(LY_TIMESTAMP_REFERENCE)
  38. if(NOT EXISTS "${LY_TIMESTAMP_REFERENCE}")
  39. message(FATAL_ERROR "File LY_TIMESTAMP_REFERENCE=${LY_TIMESTAMP_REFERENCE} does not exists")
  40. endif()
  41. if(NOT LY_TIMESTAMP_FILE)
  42. set(LY_TIMESTAMP_FILE "${LY_TIMESTAMP_REFERENCE}.stamp")
  43. endif()
  44. if(EXISTS "${LY_TIMESTAMP_FILE}" AND NOT "${LY_TIMESTAMP_REFERENCE}" IS_NEWER_THAN "${LY_TIMESTAMP_FILE}")
  45. # Stamp newer, nothing to do
  46. return()
  47. endif()
  48. endif()
  49. if(LY_LOCK_FILE)
  50. # Lock the file
  51. file(LOCK "${LY_LOCK_FILE}" TIMEOUT 1200 RESULT_VARIABLE lock_result)
  52. if(NOT ${lock_result} EQUAL 0)
  53. message(FATAL_ERROR "Lock failure ${lock_result}")
  54. endif()
  55. # There is no need to unlock the file since it will be contained to the execution of this process (cmake -P)
  56. endif()
  57. set(command_arguments)
  58. foreach(argi RANGE ${argiP}+1 ${CMAKE_ARGC})
  59. # Check if we have a new EXEC_COMMAND
  60. if(CMAKE_ARGV${argi} STREQUAL EXEC_COMMAND)
  61. list(LENGTH command_arguments command_arguments_len)
  62. if(command_arguments_len) # Check if this is the first command (or if the user passed two consecutive EXEC_COMMAND keywords)
  63. execute_process(COMMAND ${command_arguments} RESULT_VARIABLE command_result)
  64. if (NOT ${command_result} EQUAL 0)
  65. message(FATAL_ERROR "[CommandExecution] \"${command_arguments}\" returned ${command_result}")
  66. endif()
  67. endif()
  68. set(command_arguments)
  69. else()
  70. list(APPEND command_arguments ${CMAKE_ARGV${argi}})
  71. endif()
  72. endforeach()
  73. list(LENGTH command_arguments command_arguments_len)
  74. if(command_arguments_len)
  75. execute_process(COMMAND ${command_arguments} RESULT_VARIABLE command_result)
  76. endif()
  77. if(LY_TIMESTAMP_REFERENCE)
  78. # Touch the timestamp file
  79. file(TOUCH "${LY_TIMESTAMP_FILE}")
  80. endif()