Within a Makefile, I would like to write a log file, but also have it print to stdout.
I tried something like:
my.log: prereqs
myprogram | tee temp-my.log
mv temp-my.log my.log
But if myprogram is killed or interrupted, tee still succeeds, and the target is created.
That means if I rerun with make my.log
, it does not do anything, and I have a broken my.log.
Using .DELETE_ON_ERROR
probably would work:
my.log: prereqs
myprogram > my.log
.DELETE_ON_ERROR: my.log
But it does not print to stdout.
Is there a way to write a log to a file and stdout, but on error delete it, so that no broken files remain and rerunning rebuilds?
It seems wrong to me to delete a log file if the process fails...?? Don't you want that information about the failure to be in the log? I wonder if you shouldn't reconsider using the log as a target and instead choose some sentinel file and let the log be a side-effect.
Anyway, this is really a shell question: it's a long-standing source of frustration that each element in a pipeline is run in its own shell (there are some shells that run the final command in the current shell but this is not standard). If you use bash or another shell that provides support for POSIX.1 2024 you can enable -o pipefail
which will cause a pipeline to fail if any part of it fails:
SHELL := bash
.SHELLFLAGS := -o pipefail -c
If you can't do that you'll have to use a very fancy command line to communicate the failure of the program out to the invoking shell.
Edit to add: this recipe works:
SHELL := bash
.SHELLFLAGS = -o pipefail -c
my-temp.log: prereqs
myprogram | tee my-temp.log
my.log: my-temp.log
mv my-temp.log my.log