rfg@paris.ics.uci.edu (Ronald Guilmette) (02/24/90)
A question on GNU Make (3.57): In the following GNU Makefile, I am trying to solve a very old problem which affects C programmers but which is much worse for C++ programmers. Basically, when I write C++ classes, I generally try to put only one class definition into each .H file. (I use the .H suffix for C++ header files and I use the .C suffix for C++ "base" files.) Anyway, for each class declaration which appears in a .H file, I like to put the corresponding class member function definitions into the corresponding .C file. The problem is that this makes editing harder than it has to be. It would be nicer if the class declarations and the corresponding member function definitions could be kept in the same single file. That way, the class declaration is easily visible while you are working on editing the class member functions. I figured out a tricky way to make this possible (using GNU Make) and it mostly works except that there is one little problem. Each time I run the following Makefile, the final link step gets done again (whether it needs to be done again or not). I can't figure out why this is happening. My guess is that the general rule for updating .H files makes GNU make think that the .H files have actually changed (even though they may not have). I believe that this in turn makes GNU make think that the .o files that depend on those .H file have been updated (even though they do not get updated) and then that in turn makes GNU make think that it is necessary to do the final link step again. Anyway, this is all just guesswork on my part. I would appreciate it if someone could look at this and tell me what I am doing wrong. The fundamental symptom is that if you do a complete make (with the following Makefile) and then immediately do a make again, the link step gets repeated (unnecessarily). A few comments on the procedure involved here. First, I am generating .H files from .C files by having `sed' slice out just those lines in the .C files which come before my special delimiter string `####'. Second, in order to avoid unnecessary recompilations, I create a time-stamp file (with a .t suffix) each time the contents of a .H file is checked against (and possibly updated from) the corresponding .C file. This checking and/or updating of .H files is setup to only occur when a corresponding .C file has changed since the last check/update. This technique is similar to the method used in the GCC Makefile (where stamp-* files are used and where there is a script called move-if-changed.) The (short) example files I have been working with are also provided below. P.S. This Makefile is using the "rule chaining" feature of GNU Make. This is a nice feature. It is impossible for me to play these games with System V make. // rfg Makefile: ------------------------------------------------------------------------------ SHELL = /bin/sh #CPLUSPLUS= g++ CPLUSPLUS= CC CPLUSPLUS_FLAGS = -g # -O SOURCES= \ one.C \ two.C \ three.C OBJECTS= \ one.o \ two.o \ three.o .PRECIOUS: %.t all: $(OBJECTS) $(CPLUSPLUS) $(LDFLAGS) -o ao $(OBJECTS) %.o: %.C $(CPLUSPLUS) $(CPLUSPLUS_FLAGS) -c $< %.t: %.C sed '/####/,$$d' $< > $*.H+ if cmp -s $*.H+ $*.H; then \ rm -f $*.H+; \ else \ rm -f $*.H; \ mv $*.H+ $*.H; \ fi touch $@@ %.H: %.t @true three.o: two.H one.H two.o: one.H ------------------------------------------------------------------------------ one.C: ------------------------------------------------------------------------------ class one { public: one (); }; //#### one::one () { } ------------------------------------------------------------------------------ two.C: ------------------------------------------------------------------------------ #include "one.H" class two : public one { public: two (); }; //#### two::two () { } ------------------------------------------------------------------------------ three.C: ------------------------------------------------------------------------------ #include "two.H" class three : public two { public: three (); }; //#### three::three () { } main () { return 0; } ------------------------------------------------------------------------------