Reputation: 16877
How can I properly write gmake rule for a header file which is generated by the make itself?
Suppose, that I can pass do make BUILDTYPE=1
and buildtype.h will be created and populated with
#define BUILDTYPE 1
Makefile will simply do something like this:
buildtype.h:
echo #define BUILDTYPE 1 > TMPFILE
//pseudo code:
if(TMPFILE != buildtype.h)
cat TMPFILE > buildtype.h
I need to ensure that this process won't be repeated 1000 times for each cpp file and I want to ensure that this process will be done at least once
What I want to ensure is that this rule runs always and only once. That is, even if buidtype.h exist it still has to be run. I have automatic dependency tracking and it should trigger this rule only once when make runs.
That is, if I run make BUILDTYPE=2 and there is nothing to do, it still has to run that rule for buildtype.h and if buildtype.h will updated by the rule it should recompile all files.
Is something like that possible with gmake?
Upvotes: 2
Views: 173
Reputation: 6216
I need to ensure that this process won't be repeated 1000 times for each cpp file
You shouldn't need to do anything special to ensure that. Make will keep track of the targets it has updated. It will not rerun the rule multiple times just because multiple other targets depend on its output.
and I want to ensure that this process will be done at least once
The canonical way to do that is:
.PHONY: force
buildtype.h: force
You didn't ask for it, but a simple way to implement
//pseudo code: if(TMPFILE != buildtype.h) cat TMPFILE > buildtype.h
is
cmp -s TMPFILE buildtype.h || cp TMPFILE buildtype.h
Update: A related "interesting problem" is how to ensure that buildtype.h
is up to date before any compilation tries to use it. Automatic dependency tracking systems can fail here for "clean" builds, because their output is only based on what header files they can see on disk; If buildtype.h
hasn't yet been created, makedepend
or gcc -M
cannot know about it, so cannot generate correct dependencies.
One solution for that is to carefully hand-code the right dependencies into the makefile, like
foo.o: buildtype.h # because foo.c includes buildtype.h
A more foolproof but hacky alternative is to write
Makefile: buildtype.h
which ensures that make
will update buildtype.h
before it does anything else (see the manual). So now buildtype.h
will never be missing or out of date.
One disadvantage of that method is that even typing something like make clean
will cause buildtype.h
to be updated, even though it's not needed at all in that case. That can be mitigated for specific cases by really ugly hackery like
ifneq (clean,$(MAKECMDGOALS))
Makefile: buildtype.h
endif
Upvotes: 1
Reputation: 98088
Here is one way using sed:
deps =
ifdef BUILDTYPE
old = $(shell sed -n 's/\#define *BUILDTYPE *\([0-9]*\)/\1/p' buildtype.h)
ifneq ($(BUILDTYPE),$(old))
deps := buildtype.h
endif
endif
all: $(deps)
@echo $(deps)
Upvotes: 0