The psuedo-target is the “decision maker”, where we selectively replace the intermediate target (parameter 3):
.PHONY: $(1)_$(2)_FILEGEN
$(1)_$(2)_FILEGEN : $(3).fresh $(3)
@{ diff -q $$^ >/dev/null || cp $$^ ; } && rm $(3).fresh
Here we’ve taken advantage of shell syntax to allow the behavior to exist on one line. Note that the decision to update the intermediate target file is based on a simple “diff”; any decision-making code could be used instead, depending on the application.
Here’s how to interpret the command:
- The curly braces are used for grouping. A result is produced by the group which feeds the ‘
&&
‘. - The diff command “fails” if the files are different.
- If the diff fails, the copy to executes (because of the ‘
||
‘). - If the files are the same (or if not but the copy succeeds), the temporary file is removed.
- The ‘
@
‘ at the start of the command is the standard Make syntax for suppressing the command line echo when executing the recipe. - The ‘
$$^
‘ is a cheap shorthand for the two prerequisites, and as usual the automatic variable must be escaped.
Presumably, echoing the commands for these “trial” builds would be noise to the end user. Feel free to omit the ‘@
‘ while trying out this function to watch it in action!
For the test file creation, we’ve used a parameter for the command that actually generates it. We could have hard-coded the command here, but what fun would that be?! 🙂 Actually, it is quite likely that the command requires detail that would be problematic to code directly in the rule here. Instead, we use function parameter #4 to hold the shell command line that creates the intermediate target:
$(3).fresh :
@mkdir -p $$(@D)
@$$($(4)) >> $$@ || { \
echo "ERROR: $(3) generation FAILED!" ; exit 2 ; }
Actually, parameter 4 holds the name of the
variable holding the shell command line for the recipe. The parameter
gets expanded during reading. Then during the function call the
variable is expanded so that the recipe contains the desired command
line. Other creation mechanisms are possible. For example, if the
creation program uses ‘-o outfile
‘ instead of writing
to stdout, the command line in this recipe would have to be adjusted
accordingly. These variations are left as an exercise for the reader 😉.
Now let’s put this function to use…