views:

61

answers:

3

A long time ago, I remember using some Solaris make, and they had an ingenious option that would automatically detect when the compiler options had changed, and rebuild all rules appropriately. For example, suppose I switch from:

g++ -O3

to

g++ -g

Then all files should be recompiled. I'm using gnu make, and haven't found any feature like this, and was wondering whether anyone has a way of making it work.

+3  A: 

A simple way to achieve this with gmake is to write the gcc options into a file. Then, in the Makefile, read these options to a variable, use this variable in the gcc command line, plus add the dependency for all object files to this option file (can be done in the pattern rule).

Didier Trosset
Or better, use the contents of that file to set the `CFLAGS` variable (or `CXXFLAGS` for C++).
Bart van Ingen Schenau
Setting the `CFLAGS` variable has the problem that you override the shell environment variable of same name.
Didier Trosset
This solution is simple and elegant. I don't understand the CFLAGS comment. However, it's not enough to just write out the file, you need to compare whether the new args are different, and only write out the file if it's changed. Otherwise, the file always changes, and the rules will always fire. How do you in make compare the contents of the file with the variable, and if it's different, write out to the file? Something like:COMPILE:=g++ $(DEBUG) $(OPT)LASTCOMPILE:=`cat <.compile.txt`<br>if $(COMPILE) != $(LASTCOMPILE)<br> echo $(COMPILE) >.compile.txtis this close?
Dov
@Didier: My UNIX is a bit rusty, but, if you don't export the CFLAGS, it won't change the setting for the whole shell, just for the execution of the current script, right?
Bruno Brant
There's an exmple of such a solution here: http://stackoverflow.com/questions/3236145/force-gnu-make-to-rebuild-objects-affected-by-compiler-definition/3237349#3237349
slowdog
@Bruno: You're correct. What I mean is that if you want to use this `CFLAGS` variable to set some option from the command line into your Makefile. Then you can't, because the Makefile overrides it.
Didier Trosset
+1  A: 

Just make your target depend on the makefile itself:

all: a.out

a.out: boo.c Makefile
        cc -O3 -g boo.c
Nikolai N Fetissov
This is very brute force. Change anything in the makefile, even a space, and everything recompiles. That isn't very good.
Dov
Hmm, you don't recompile when you change your makefiles? Why do you change them then?
Nikolai N Fetissov
Well, adding a single source file should really only trigger a compile of that file and a link of that into some library or binary. It doesn't have to rebuild _everything_ to be correct.
Jack Kelly
Yes - that's what I have in the answer - the *link* line (never mind that its the compile like too :)
Nikolai N Fetissov
+1  A: 

Here's a basic way to do this (although I'm convinced it's a terrible idea, see below):

-include CFLAGS.save

CFLAGS := -O2 -g

all: foo

CFLAGS.save:
    echo 'CFLAGS_SAVE := $(CFLAGS)' > $@
ifeq ($(CFLAGS),$(CFLAGS_SAVE))
%.o: %.c CFLAGS.save
    gcc $(CFLAGS_SAVE) -c -o $@ $<
else
.PHONY: CFLAGS.save
%.o: %.c CFLAGS.save
    $(MAKE) $@
endif

foo: foo.o
    gcc -o $@ $^

Here's what happens: Before any compilation is done, the current CFLAGS are written out to CFLAGS.save. If CFLAGS isn't equal to CFLAGS_SAVE, then the user must've changed them. If so, we declare CFLAGS.save to be phony so make will rebuild it. Note also that if CFLAGS has changed, we'll update it but we'll still have the old value in memory. Therefore, we have to recursively invoke make for every source file. Not cool on a big project.

The other problem is that if you neglect to specify CFLAGS on the command line, it will go back and rebuild everything with the default. You could work around this by testing the $(origin) of CFLAGS, but seriously, no. My professional ethics won't allow me to stand for this.

make is meant to be simple. Distributors already have enough trouble understanding packagers' abuses of build tools (sadly, most of the blame levelled at automake is due to this). Please, just say no to Cthulhoid build systems.

Besides, make clean all CFLAGS='-Whatever -foo' will work just as well.

Jack Kelly
Thank you for the phrase "Cthulhoid build systems", I love it :-) Here's a variation on your solution that avoids the recursive make invocation: http://stackoverflow.com/questions/3236145/force-gnu-make-to-rebuild-objects-affected-by-compiler-definition/3237349#3237349
slowdog