shellloggingmakefile

log file as makefile target


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?


Solution

  • 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