[lug] OT: Makefile oddity

Tom Tromey tromey at redhat.com
Sat Apr 20 11:53:58 MDT 2002


>>>>> ">" == D Stimits <stimits at idcomm.com> writes:

>> SRC_GLOBAL_SERVER	=	$(SRCDIR_GLOBAL_SERVER)/x.cpp	\
>> 				$(SRCDIR_GLOBAL_SERVER)/y.cpp	\
>> 				$(SRCDIR_GLOBAL_SERVER)/z.cpp

>> OBJ_GLOBAL_SERVER	=	$(OBJDIR_GLOBAL)/x.o	\
>> 				$(OBJDIR_GLOBAL)/y.o	\
>> 				$(OBJDIR_GLOBAL)/z.o

>> ${OBJ_GLOBAL_SERVER}: ${SRC_GLOBAL_SERVER}
>> 	@cd ../global ; ${MAKE} ${@}


>> But ${OBJ_SERVER} is not one file, it is three, and it might be
>> considering all of ${OBJ_SERVER} out of date if any one of the
>> files in ${SRC_SERVER} is out of date

Exactly.

What you've written above is that each of the objects depends on all
the inputs.  So if you touch, say, y.cpp, make will consider that each
of x.o, y.o, and z.o needs to be remade.  It will do each of these
separately via a new make invocation in ../global.

That's just how make works.  You can easily convince yourself of it
with this Makefile:

    all: x y

    x y: a b
	    @echo $@

Do:

    touch b; touch x y; touch a; make

Writing "x y : a b" is just like writing:

    x: a b
    y: a b


A few comments that might help:

First of all, if you can assume GNU make (something I recommend if
possible; experience with automake has shown that writing a portable
Makefile is painful), then use `$(MAKE) -C DIR' instead of `cd DIR; $(MAKE)'.
Also, as another nit, I recommend using `&&' instead of `;' in make rules.
That way you get to find out if anything fails.


One way to fix your larger problem would be to use a GNU make pattern
rule for the .o files.  I don't use GNU make features too much, so I'm
not certain this will work:

    $(OBJDIR_GLOBAL)/%.o: $(SRCDIR_GLOBAL_SERVER)/%.cpp
	    $(MAKE) -C ../global $@

However, there's a bug here.  It is the classic recursive make bug:
you only have a dependency on the .cpp file.  So if you `touch
config.h', nothing will be rebuilt -- which is wrong.

Putting full dependencies into every Makefile is hard, because the
maintenance costs are high.  The paper goes into this problem in
depth.

Automake's solution is taken from pre-existing GNU practice (as of
1993 or so).  Namely, always recurse into every directory for the
exported targets.  So:

    all:
	    for d in $(SUBDIRS); do $(MAKE) -C $$d; done

Now, if you go read an automake-generated Makefile.in, you'll see all
kinds of other stuff surrounding that little piece of code.  For
instance we correctly deal with `make -k' (or lack of -k).  (Note for
the record that you can't just copy automake's rules; they have a
license attached.  See the docs.)


Another solution would be to have one big Makefile that keeps track of
everything.  You've already indicated you can't do this though.

>> It still works, it still ends up with the right thing, but it tries
>> to do all targets twice, even the ones that were not touched.

Offhand I don't see why it does them all twice.  That's interesting.
Perhaps there is also a problem in the Makefile in ../global?

Tom



More information about the LUG mailing list