[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
conditionally update a target
From: |
Kannan Goundan |
Subject: |
conditionally update a target |
Date: |
7 Jun 2005 16:38:23 -0700 |
User-agent: |
G2/0.2 |
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.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- conditionally update a target,
Kannan Goundan <=