[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 <psmith@gnu.org> 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
: INT TERM;
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 >> $@
test.txt:
$(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