[comp.bugs.4bsd] Bug in the make program

dimitri@cui.UUCP (KONSTANTAS Dimitri) (03/04/88)

Using the make program, I came to case where make behaves differently
when executed with the -n option and without.
That is with the -n option the actions are listed, as excected,
but without it, they are not executed (I get that the target file
is up-to-date).

Following is a shar file that recreates the case.
(the files are empty, but it is the modification dates that count)
After unpacking the shar file , just give 
	make -n test
and then
	make test

Can anybody explain what is happening?
I run the test in both VAX with 4.3 and SUN 3.4 and get the same behavior.

Dimitri Konstantas
University of Geneva

	dimitri@cgeuge51.bitnet
	mcvax!cernvac!cui!dimitri


---- cut here ---------------------------------------------

# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# makefile crf
# The files f1.a f2.o f2.c test test.c test.o will also be create

echo x - makefile
cat > "makefile" << '//E*O*F makefile//'
test:     f1.a
	@echo "compiling TEST"

f1.a: f2.o
	@echo "Recompiling f1.a"

f2.o: f2.c
	@echo "recompiling f2.c"

//E*O*F makefile//

echo x - crf
cat > "crf" << '//E*O*F crf//'
echo "Please wait a few seconds to recreate the files with correct times"
touch test.c ; sleep 1
touch f2.o ; sleep 1
touch f1.a ; sleep 1
touch test.o ; sleep 1
touch test ; sleep 1
touch f2.c
//E*O*F crf//

sh ./crf

exit 0

bww@K.GP.CS.CMU.EDU (Bradley White) (03/06/88)

In article <110@cui.UUCP>, dimitri@cui.UUCP (KONSTANTAS Dimitri) writes:
> Using the make program, I came to case where make behaves differently
> when executed with the -n option and without.

It should not be surprising that "make" and "make -n" can do different
things.  "make -n" assumes that an "a: b c" rule actually makes "a" out
of "b" and "c", and that it does it ``now'', whereas "make" can stat()
"a" after the commands are run to see if it was really made.  In
general, rules that don't make their targets (like those given), or
rules that try to be smart about making their target even though the
dependencies are out of date (for example, trying to detect benign
changes), will always confuse "make -n".
-- 
Bradley White <bww@cs.cmu.edu>         +1-412-268-3060
CMU Computer Science Department  40 26'33"N 79 56'48"W

rdh@sun.uucp (Robert Hartman) (03/07/88)

In article <1048@PT.CS.CMU.EDU> bww@K.GP.CS.CMU.EDU (Bradley White) writes:
>In article <110@cui.UUCP>, dimitri@cui.UUCP (KONSTANTAS Dimitri) writes:
>> Using the make program, I came to case where make behaves differently
>> when executed with the -n option and without.
>
>It should not be surprising that "make" and "make -n" can do different
>things.  "make -n" assumes that an "a: b c" rule actually makes "a" out
>of "b" and "c", and that it does it ``now'', whereas "make" can stat()
>"a" after the commands are run to see if it was really made.  In
>general, rules that don't make their targets (like those given), or
>rules that try to be smart about making their target even though the
>dependencies are out of date (for example, trying to detect benign
>changes), will always confuse "make -n".
>-- 
>Bradley White <bww@cs.cmu.edu>         +1-412-268-3060
>CMU Computer Science Department  40 26'33"N 79 56'48"W

Another cause for this is if the makefile contains a rule with a 'make'
command in it (e.g., a 'nested' make command):

	all:
		-cd foo ; make bar

When you run make with this makefile, you'll make the target 'bar' as defined
in the makefile in ./foo.  But if you run this with -n, the nested make isn't
performed; you don't see the rule for building bar.

In System V make, if you replace 'make' with '$(MAKE)' in the rule:

	all:
		-cd foo ; $(MAKE) bar

the nested 'make' command line runs despite -n; it runs with the same flags as
the calling make command (e.g, -n).  So if you run 'make -n' in this
case, the nested make will display the rule for bar as given in the makefile
in (directory) foo.   This allows you to run 'make -n' on an entire source
hierarchy.

A bit on terminology.  Many people call the above a 'recursive' make.  But
that seems wrong to me, since it makes nothing in the local dir.  To me
a 'recursive' make is something like this:

	foo: foo.nested foo.local

	foo.nested:
		cd subdir1 ; make foo
		cd subdir2 ; make foo
		...

	foo.local:
		touch foo


This target propagates the build of 'foo' down the hierarchy, and then builds
something in the local directory.  Thus, it makes `foo' recursively.

A make command can get flags both from the command line and the (automatic)
MAKEFLAGS macro, but note that this macro does register options that have
arguments (e.g., -f).  You can initialize MAKEFLAGS as an envar; other macros
can also be initialized in this way, but the precedence of values between
the current make, nested makes, and the environment, gets pretty convoluted.
For clarity's sake it is probably better to just to initialize macros in the
makefile, and to pass macro defs to nested makes as arguments in the nested
commands.

In an earlier posting about make I included a .DEFAULT rule to get a file out
of SCCS.  In versions of make that have tilde rules, it is not necessary to do
that.  The tilde rule for a .c file assures that it will be extracted from SCCS
as needed.

-bob.