Hi Paul,
On Sun, Jun 6, 2021 at 12:40 AM Paul Smith <psm...@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