Pavel P
Pavel P

Reputation: 16877

gmake rule for a header file which is created by the makefile

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

Answers (2)

slowdog
slowdog

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

perreal
perreal

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

Related Questions