Reputation: 583
I have a compiler that produces .c files from .ec files as an intermediate step. The compiler does not remove the .c file. The compiler cannot be asked to skip invocation of $CC to produce the .o file. I am trying to have GNU make (3.81) treat the .c files produced as intermediate files and clean them up. The following is an isolated example that reproduces the bad behavior with a file extension that has no implied rules.
.INTERMEDIATE: %.delme
%.o: %.ec
cp $< $(<:.ec=.delme)
cp $(<:.ec=.delme) $@
all: test.o
To execute the test case:
rm -f test.*
touch test.ec
make
if [[ -e test.delme ]]; then echo "Failure"; else echo "Success"; fi
Upvotes: 0
Views: 1268
Reputation: 4692
Try using a pattern rule to tell make their your compiler produces both .o and .c files from the .ec source. And then declare all the c files as INTERMEDIATE. Pattern rules with multiple outputs work differently than non-pattern rules. Make will run pattern rules only once to produce all output files from the rule, while static rules will be run for each output file. Make also understand that a pattern rule will produce all output files, even if it only wanted one of them as a target.
The result is something like this:
SRC := foo.ec bar.ec
OBJS := $(SRC:.ec=.o)
all: program
program: $(OBJS)
cat $^ > $@
%.o %.c: %.ec
cp $< $(<:.ec=.c) ; cp $< $(<:.ec=.o)
.INTERMEDIATE: $(SRC:.ec=.c)
The command to make the .c and .o from the .ec will be run once to produce both those files. Since make knows it made the .c (even though it only wanted the .o), it will know enough to delete it. The .INTERMEDIATE target will only work if the files are listed explicitly, not using a pattern, so we haven't used %.c
. Which seems like a bad idea anyway, what if you had C source that wasn't produce from an .ec file and make deleted it for you? Example output:
$ make
cp foo.ec foo.c ; cp foo.ec foo.o
cp bar.ec bar.c ; cp bar.ec bar.o
cat foo.o bar.o > program
rm bar.c foo.c
$ touch foo.ec ; make
cp foo.ec foo.c ; cp foo.ec foo.o
cat foo.o bar.o > program
rm foo.c
Notice how in the second invocation it only deleted foo.c since bar.o/c wasn't rebuilt.
Upvotes: 1
Reputation: 100856
Make can only consider make targets to be intermediate. You can't just declare a random file on the filesystem as intermediate and have make delete it for you.
Here the .delme
file is created as a side effect of the recipe that builds the .o
file; make doesn't know anything about it, so make will not delete it because there are no targets in the makefile that are intermediate.
In your example you could split the two cp
commands into separate rules and that would allow the intermediate setting to work:
%.delme : %.ec
cp $< $@
%.o : %.delme
cp $< $@
I'm assuming that in your real environment you can't do that because it's all one command that generates the intermediate file and the real file. In that case you'll have to deal with the delete yourself inside the recipe:
%.o : %.ec
cp $< $(<:.ec=.delme)
cp $(<:.ec=.delme) $@ && rm -f $(<:.ec=.delme)
Note this leaves the .delme
file existing if the cp
command fails; if you want to remove it no matter what you can do that too.
EDIT
To delete the intermediate file even if the command fails you have to preserve the exit code so you can tell make
what it was. Something like:
%.o : %.ec
cp $< $(<:.ec=.delme)
cp $(<:.ec=.delme) $@; e=$$?; rm -f $(<:.ec=.delme); exit $$e
Upvotes: 1