| # |
| # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) |
| # |
| # SPDX-License-Identifier: BSD-2-Clause |
| # |
| |
| cmake_minimum_required(VERSION 3.7.2) |
| include_guard(GLOBAL) |
| |
| # This takes a camkes produced dependency file (this means we can assume one dependency |
| # per line) and produces a cmake list of dependencies |
| function(MakefileDepsToList mdfile output_variable) |
| file(READ "${mdfile}" raw_file) |
| # First remove the target of the dependency list |
| string( |
| REGEX |
| REPLACE |
| "^[^:]*: \\\\\r?\n" |
| "" |
| string_deps |
| "${raw_file}" |
| ) |
| # Now turn the list of dependencies into a cmake list. We have assumed |
| # that this makefile dep file was generated by camkes and so it has one |
| # item per line |
| string( |
| REGEX |
| REPLACE |
| "\\\\\r?\n" |
| ";" |
| deps |
| "${string_deps}" |
| ) |
| # Strip the space from each dep |
| foreach(dep IN LISTS deps) |
| # Strip extra spacing |
| string(STRIP "${dep}" dep) |
| list(APPEND final_deps "${dep}") |
| endforeach() |
| # Write the output to the parent |
| set("${output_variable}" "${final_deps}" PARENT_SCOPE) |
| endfunction(MakefileDepsToList) |
| |
| # Wraps a call to execute_process with checks that only rerun execute_process |
| # if the command or input files are changed. It also uses a depfile to track |
| # any files that the command touches internally. This function currently won't |
| # work without a depfile. |
| macro(execute_process_with_stale_check invoc_file deps_file outfile extra_dependencies) |
| # Check all input extra_dependencies are actual files with timestamps |
| # We need to assign the input list variable to another variable so that it works with |
| # foreach( IN LISTS ). As the foreach LISTS variaint doesn't seem to work with marco arguments. |
| set(_extra_dependencies ${extra_dependencies}) |
| foreach(dep IN LISTS _extra_dependencies) |
| if(NOT (EXISTS "${dep}")) |
| message(FATAL_ERROR "extra_dependencies: could not find file: ${dep}") |
| endif() |
| endforeach() |
| |
| # We need to determine if we actually need to regenerate. We start by assuming that we do |
| set(regen TRUE) |
| if((EXISTS "${invoc_file}") AND (EXISTS "${deps_file}") AND (EXISTS "${outfile}")) |
| file(READ "${invoc_file}" old_contents) |
| if("${old_contents}" STREQUAL "${ARGN}") |
| MakefileDepsToList("${deps_file}" deps) |
| # At this point assume we do not need to regenerate, unless we found a newer file |
| set(regen FALSE) |
| foreach(dep IN LISTS deps _extra_dependencies) |
| if("${dep}" IS_NEWER_THAN "${outfile}") |
| set(regen TRUE) |
| break() |
| endif() |
| endforeach() |
| endif() |
| endif() |
| if(regen) |
| message(STATUS "${outfile} is out of date. Regenerating...") |
| execute_process(${ARGN}) |
| file(WRITE "${invoc_file}" "${ARGN}") |
| endif() |
| # Add dependencies |
| MakefileDepsToList("${deps_file}" deps) |
| set_property( |
| DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" |
| APPEND |
| PROPERTY CMAKE_CONFIGURE_DEPENDS "${deps};${extra_dependencies}" |
| ) |
| |
| endmacro(execute_process_with_stale_check) |
| |
| # For custom commands that invoke other build systems, we can create a depfile |
| # based on a find traversal of the directory. This saves using CMake to glob it |
| # which is much slower |
| macro(create_depfile_by_find ret outfile depfile dir) |
| file(RELATIVE_PATH path ${CMAKE_BINARY_DIR} ${outfile}) |
| list( |
| APPEND |
| ${ret} |
| COMMAND |
| printf |
| "${path}: " |
| > |
| ${depfile} |
| ) |
| list( |
| APPEND ${ret} COMMAND |
| find |
| -L |
| ${dir} |
| -type |
| f |
| -printf |
| "%p " |
| >> |
| ${depfile} |
| ) |
| list(APPEND ${ret} DEPFILE ${depfile}) |
| endmacro() |