NetBSD-Bugs archive

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

bin/59962: make(1): grouped target rules for batch recipes



>Number:         59962
>Category:       bin
>Synopsis:       make(1): grouped target rules for batch recipes
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Feb 05 02:45:00 +0000 2026
>Originator:     Taylor R Campbell
>Release:        current, 11, 10, 9, ...
>Organization:
netbsd.c netbsd.h: foundation.y
>Environment:
>Description:

	Tools like lex(1) and yacc(1) produce multiple output files
	foo.c and foo.h from a single input file foo.l/.y.  (Other
	examples abound, like TeX, Heimdal compile_et, and so on.)

	For _sequentiail_ make(1), this can be expressed with a rule
	having multiple targets:

foo.tab.c foo.tab.h: foo.y
	yacc -b foo foo.y

	However, this doesn't work for _parallel_ make(1): it may
	execute the same recipe twice for foo.tab.c and foo.tab.h
	independently.

	GNU make(1) has sprouted an alternative syntax `&:' to mean
	that foo.tab.c and foo.tab.h are both produced simultaneously
	by a single execution of the recipe (which, of course, can't
	vary according to the target by using $@ or $* or similar), and
	in parallel builds, it only executes the rule once for either
	target:

foo.tab.c foo.tab.h &: foo.y
	yacc -b foo foo.y

	We should adopt this.

	(I'm not entirely clear on why the traditional parallel
	behaviour of multi-target `:' rules is useful, really, except
	when it's actually a different recipe for each target because
	it varies by ${.TARGET}.)

>How-To-Repeat:

$ cat Makefile
all: .PHONY
all: c

.if !make(clean)
.BEGIN:
	echo 0 >counter
.END:
	@case $$(cat counter) in \
	0|1)	echo ok;; \
	*)	echo -n clobbered: ''; cat counter; exit 1;; \
	esac
.endif

clean: .PHONY
	@-rm -f a b c

a b:
	@exec 3>counter; flock 3; c=$$(cat counter); echo $$((c + 1)) >&3
	echo hello >a
	echo world >b

c: a b
	echo done >c
$ make clean && make
echo 0 >counter
echo hello >a
echo world >b
echo done >c
ok
$ make clean && make -j4
echo 0 >counter
--- a ---
--- b ---
echo hello >a
echo world >b
--- a ---
echo hello >a
echo world >b
--- c ---
echo done >c
clobbered: 2
*** Error code 1

Stop.
make: stopped in /tmp/riastradh/20260204/test
$ 


>Fix:

	Yes, please!



Home | Main Index | Thread Index | Old Index