I have a program called "separator" that reads in a single file "X.both" and produces "X.h" and "X.cpp". (This program isn't really implemented yet. I'm using a dummy script to test my makefile out.)
Since changing a ".h" file can cause a lot of recompilation, I try to avoid this when possible. If the interface part of the "X.both" file doesn't change, I don't overwrite the output ".h" file. I do this by running "diff" and only writing the new ".h" file if it differs from the old one. My makefile doesn't work in the following case: 1. Modify the non-interface part of a "Helper.both" file. 2. Run "make". Everything goes as expected. 3. Run "make" again. It needlessly runs "separator". 4. goto 3. According to the timestamp, "Helper.h" *is* out of date and so Make tries to rebuild it. Since GNU Make doesn't maintain it's own persistent state file, I guess it has no way of knowing that I didn't modify it the first time. Does anybody know how to get GNU Make to do what I want? Is there a way to use some kind of extra timestamp file? If possible, I'd like to avoid having to put the smarts in a shell script. I've included the relevant files below. A tarball of everything is available at "http://cakoose.com/MaybeUpdate.tar.bz2". Any guidance would be appreciated. - Kannan ----- Makefile: # The output directory b = Build g = Generated _dummy := $(shell mkdir -p -- $(b) $(g)) # Executable rule $(b)/Executable: $(b)/Main.o $(b)/Helper.o $(b)/Regular.o # Linking @cat -- $^ > $@ # Generic rules .PRECIOUS: $(b)/%.o $(g)/%.cpp $(g)/%.h $(b)/%.o: %.cpp %.h # Compiling $< @cat -- $^ > $@ $(b)/%.o: $(g)/%.cpp $(g)/%.h # Compiling $< @cat -- $^ > $@ $(g)/%.h $(g)/%.cpp: %.both # Separating $< @./separator $< $(g)/$*.temp $(g)/$*.cpp @if diff -- $(g)/$*.temp $(g)/$*.h >/dev/null 2>&1 ; then \ rm -- $(g)/$*.temp ; \ else \ mv -- $(g)/$*.temp $(g)/$*.h ; \ fi clean: -rm -- $(b)/* $(g)/* # Dependencies $(b)/Main.o: $(g)/Helper.h Regular.h ----- separator: #! /bin/bash # Separates iface from impl. # # Any line that begins with a '#' is an interface line # and will be copied to the interface file. All other # lines will be put in the implementation file. # # Usage: COMMAND in-file iface-file impl-file function die() { for line in "$@"; do echo "$line" > /dev/stderr; done exit 2 } [ $# -eq 3 ] || die "Usage: $0 in-file iface-file impl-file" in_file="$1" iface_file="$2" impl_file="$3" [ -r "$in_file" ] || die "$0: cannot read from file '$in_file'" sed -n -e '/^ *#/p' -- "$in_file" > "$iface_file" || die "$0: sed 1" sed -e '/^ *#/d' -- "$in_file" > "$impl_file" || die "$0: sed 2" ----- Main.both # This is an interface line in Main.both This is an implementation line in Main.both ----- Helper.both # This is an interface line in Helper.both This is an implementation line in Helper.both ----- "Regular.h" are "Regular.cpp" just empty files. _______________________________________________ help-gnu-utils mailing list help-gnu-utils@gnu.org http://lists.gnu.org/mailman/listinfo/help-gnu-utils