pattern rules with multiple targets producing intermediate files

2023-02-07 Thread Jan Beulich
Hello,

while something has changed from 4.3 to 4.4 in the dealing with
intermediate files, the example Makefile below still doesn't work
as expected. There are two pairs of *.[ch] files generated, each by
their respective rule. Each of the *.o files to be compiled from the
*.c ones has a dependency recorded on both *.h files. If (up-to-date
or outdated) instances of all four generated files are there, all is
fine. If both *.c files are missing, all is fine as well. However,
if only one *.c file is missing and the other is up-to-date,
compilation of the other *.c file will (provided at least -j2 was
passed) be invoked in parallel to the re-generation of the other
*.[ch] pair, not taking into consideration that one of the *.h files
is in the process of being re-generated (together with its sibling
*.c file).

The difference in behavior of 4.4 compared to 4.3 is that this is
now symmetric. In 4.3 only the C file corresponding to the first
prereq of "all" was permanently affected by the bad behavior
(according to my experiments); a re-run of make would succeed
(because the intermediate file was not treated as such and hence was
not deleted).

Of course I'm not going to exclude that there's something that's
done wrongly in that (heavily stripped down) example - apologies in
advance if so, yet then I'd still appreciate if it could be pointed
out what needs doing differently.

Jan

.PHONY: all
all:tst_b.o tst_a.o

Makefile:: ;

tst_b.o tst_a.o: tst_a.h tst_b.h

#.SECONDARY: tst_a.c tst_b.c

%.o: %.c
@echo 'C: *=$* @=$@ <=$<'
@for i in $^; do test -f "$$i" || echo "Missing: $$i"; done
@for i in $^; do test -s "$$i" || echo "Empty: $$i"; done

%.c %.h: %.a
@echo 'A: *=$* @=$@ <=$<'
rm -f $*.[ch]
touch $*.c $*.h
sleep 1
echo "$*.c ($<)" >$*.c
sleep 1
echo "$*.h ($<)" >$*.h

%.c %.h: %.b
@echo 'B: *=$* @=$@ <=$<'
rm -f $*.[ch]
touch $*.c $*.h
sleep 1
echo "$*.c ($<)" >$*.c
sleep 1
echo "$*.h ($<)" >$*.h



Generating missing depfiles by an automake based makefile

2023-02-07 Thread Dmitry Goncharov
Good morning.

Here is a rule from an automake generated makefile.

$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@

This rule restores a missing depfile file by creating a file with one
line '# dummy'. (Next version of automake will create an empty one).
There must have been a reason for generating such a depfile.
However, this depfile fails dependency tracking. Once a depfile was
removed and recreated in this shape, it will no longer perform its
function.

Below is a sample bash session with gnu make which demonstrates how a
dummy shuffle.Po makefile fails to have shuffle.o rebuilt when
shuffle.h changes.


$ make -j3  CFLAGS='-Wall -Wextra -ggdb -m64 -O0 -DMAKE_MAINTAINER_MODE=1'
./config.status --header=src/mkconfig.h
Making all in lib
make[1]: Entering directory '/home/dgoncharov/src/gmake/make/l64/lib'
make  all-recursive
config.status: creating src/mkconfig.h
config.status: src/mkconfig.h is unchanged
make[2]: Entering directory '/home/dgoncharov/src/gmake/make/l64/lib'
make[3]: Entering directory '/home/dgoncharov/src/gmake/make/l64/lib'
make[3]: Nothing to be done for 'all-am'.
make[3]: Leaving directory '/home/dgoncharov/src/gmake/make/l64/lib'
make[2]: Leaving directory '/home/dgoncharov/src/gmake/make/l64/lib'
make[1]: Leaving directory '/home/dgoncharov/src/gmake/make/l64/lib'
Making all in po
make[1]: Entering directory '/home/dgoncharov/src/gmake/make/l64/po'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/home/dgoncharov/src/gmake/make/l64/po'
Making all in doc
make[1]: Entering directory '/home/dgoncharov/src/gmake/make/l64/doc'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/home/dgoncharov/src/gmake/make/l64/doc'
make[1]: Entering directory '/home/dgoncharov/src/gmake/make/l64'
make[1]: Leaving directory '/home/dgoncharov/src/gmake/make/l64'
$ ls -l src/shuffle.o
-rw-r--r-- 1 dgoncharov wireshark 13K Feb  7 21:16 src/shuffle.o
$ head src/.deps/shuffle.Po
src/shuffle.o: ../src/shuffle.c /usr/include/stdc-predef.h \
 ../src/makeint.h src/config.h ../src/../src/mkcustom.h lib/alloca.h \
 /usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/include/stddef.h \
 ../src/gnumake.h /usr/include/sys/types.h /usr/include/features.h \
 /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
 /usr/include/bits/long-double.h /usr/include/gnu/stubs.h \
 /usr/include/gnu/stubs-64.h /usr/include/bits/types.h \
 /usr/include/bits/timesize.h /usr/include/bits/typesizes.h \
 /usr/include/bits/time64.h /usr/include/bits/types/clock_t.h \
 /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \
$ grep shuffle.h src/.deps/*.Po
src/.deps/file.Po: ../src/variable.h ../src/debug.h ../src/shuffle.h
src/.deps/file.Po:../src/shuffle.h:
src/.deps/implicit.Po: ../src/output.h ../src/commands.h
../src/shuffle.h /usr/include/assert.h
src/.deps/implicit.Po:../src/shuffle.h:
src/.deps/job.Po: ../src/variable.h ../src/os.h ../src/dep.h ../src/shuffle.h \
src/.deps/job.Po:../src/shuffle.h:
src/.deps/main.Po: ../src/shuffle.h /usr/include/assert.h /usr/include/fcntl.h \
src/.deps/main.Po:../src/shuffle.h:
src/.deps/shuffle.Po: /usr/include/glob.h ../src/shuffle.h
../src/filedef.h ../src/hash.h \
src/.deps/shuffle.Po:../src/shuffle.h:
$ rm src/.deps/shuffle.Po
$ make -j3  CFLAGS='-Wall -Wextra -ggdb -m64 -O0 -DMAKE_MAINTAINER_MODE=1'
./config.status --header=src/mkconfig.h
Making all in lib
make[1]: Entering directory '/home/dgoncharov/src/gmake/make/l64/lib'
make  all-recursive
make[2]: Entering directory '/home/dgoncharov/src/gmake/make/l64/lib'
config.status: creating src/mkconfig.h
config.status: src/mkconfig.h is unchanged
make[3]: Entering directory '/home/dgoncharov/src/gmake/make/l64/lib'
make[3]: Nothing to be done for 'all-am'.
make[3]: Leaving directory '/home/dgoncharov/src/gmake/make/l64/lib'
make[2]: Leaving directory '/home/dgoncharov/src/gmake/make/l64/lib'
make[1]: Leaving directory '/home/dgoncharov/src/gmake/make/l64/lib'
Making all in po
make[1]: Entering directory '/home/dgoncharov/src/gmake/make/l64/po'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/home/dgoncharov/src/gmake/make/l64/po'
Making all in doc
make[1]: Entering directory '/home/dgoncharov/src/gmake/make/l64/doc'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/home/dgoncharov/src/gmake/make/l64/doc'
make[1]: Entering directory '/home/dgoncharov/src/gmake/make/l64'
make[1]: Leaving directory '/home/dgoncharov/src/gmake/make/l64'
$ head src/.deps/shuffle.Po
# dummy
$ touch ../src/shuffle.h
$ make -j3  CFLAGS='-Wall -Wextra -ggdb -m64 -O0 -DMAKE_MAINTAINER_MODE=1'
./config.status --header=src/mkconfig.h
Making all in lib
make[1]: Entering directory '/home/dgoncharov/src/gmake/make/l64/lib'
make  all-recursive
config.status: creating src/mkconfig.h
config.status: src/mkconfig.h is unchanged
make[2]: Entering directory '/home/dgoncharov/src/gmake/make/l64/lib'
make[3]: Entering directory '/home/dgoncharov/src/gmake/make/l6