[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Make does not clean up the target when stderr is piped. Why?

From: Masahiro Yamada
Subject: Re: Make does not clean up the target when stderr is piped. Why?
Date: Thu, 10 Jun 2021 13:20:40 +0900

Hi Paul,

On Sun, Jun 6, 2021 at 12:40 AM Paul Smith <> wrote:
> On Sat, 2021-06-05 at 23:00 +0900, Masahiro Yamada wrote:
> >   make 2>&1 | tee build.log
> >
> > is a very common use case, and people often miss to add  (trap "" 2;
> > ...), I think.
> Certainly.  It wasn't clear from your question what liberties you were
> allowed to take with your environment.
> I just explained what the problem was and gave a suggestion that would
> resolve it without either modifying the make source code or modifying
> your makefiles.
> As Kaz points out, if you're using tee instead of cat you can use
> tee -i (you can even make a shell alias like alias='tee -i' if you
> like; I don't really see a downside to making this the default
> behavior).
> > I was wondering if I could take care of this in Makefile somehow.
> Sure.  If you're willing to modify the makefile you have all kinds of
> options.
> Many build programs (like GCC and binutils for example) already have
> built-in support for catching SIGINT and deleting output files
> automatically, so they don't rely on make to do it for them in the
> first place.  If the programs you're running don't do that, you have
> two options:
> First is to add a trap into the recipe, as you show.  I don't see why
> it's necessary to detect whether or not you're writing to a pipe;
> there's no harm in ALWAYS performing this cleanup regardless of
> stdout/stderr.

Yes, I can always do this.
At first, I just considered the overhead caused
by doing 'trap' for every target
because the Linux kernel builds so many files.
But, this may not be a big deal.

The kernel Makefile typically looks like follows (very simplified).

I can insert 'delete-on-error' to do manual cleanups.

delete-on-error = trap 'if [ $$? != 0 ]; then rm -f $@; fi' EXIT; trap

cmd = @set -e; echo "  $(quiet_cmd_$(1))"; $(delete-on-error) $(cmd_$(1))

quiet_cmd_test.txt = GEN   $@
      cmd_test.txt = echo hello > $@; sleep 10; echo bye >> $@

        $(call cmd,test.txt)

I think 'trap' is a better fit than 'mv -f $@.tmp $@;'.

I do not tell all the story because the kernel build
is doing complicated things.

A remaining issue is a pattern rule with multiple targets
(or group target &: ).

%.x %.y: %.z
       [ build recipe to create %.x and %.y ]

When GNU Make is interrupted, it deletes
both %.x and %.y
This is the correct behavior because these two
are updated in a single recipe.

My solution above only deletes $@,
the target GNU Make is interested in.

In my understanding, there is no special
target that expands into all the targets
of the grouped target.

Anyway, I still wish the SIGPIPE problem
will be fixed by GNU Make someday.

> > manual_cleanup = trap "rm -f $@; exit 130" INT;
> >
> > build_command = echo hello > $@; sleep 10; echo bye >> $@
> >
> > test.txt:
> >         $(manual_cleanup)$(build_command)
> The other option which is often used for commands which don't have
> their own SIGINT handling is to generate the output into a temporary
> file and rename it only as the last step.  Renames (to the same
> filesystem) are typically atomic so you either get the new version or
> not, like this:
>   test.txt:
>           rm -f $@; echo hello > $@.tmp; sleep 10; echo bye >> $@; \
>           mv -f $@.tmp $@;

Best Regards
Masahiro Yamada

reply via email to

[Prev in Thread] Current Thread [Next in Thread]