开发者

makefile conditionals

开发者 https://www.devze.com 2023-03-10 12:53 出处:网络
Note: using MinGW\'s make (should be GNU make) i have a couple of -include statements in my makefile to import dependencies which were generated using g++ -MM. However I would like to only do this wh

Note: using MinGW's make (should be GNU make)

i have a couple of -include statements in my makefile to import dependencies which were generated using g++ -MM. However I would like to only do this when necessary. I have several different build targets and I don't want all of their respective dependency files to be included since this takes a while (suppose I'm r开发者_开发技巧unning make clean: no need to include them in this case)

Here's the format of my makefile.

DEPS_debug = $(patsubst %.cpp,build_debug/%.d,$(SRC))
OBJ_debug = $(patsubst %.cpp,build_debug/%.o,$(SRC))
all: program_debug
    -include $(DEPS_debug) #make: include: Command not found
program_debug: $(OBJ_debug)
    $(CC) $(CFLAGS) $(OBJ_debug) -o $@


If you really don't want to include those files needlessly, you have a couple of options:

You can put in a conditional as Diego Sevilla suggests (but I would recommend using MAKECMDGOALS so that you can write a more flexible version, specific to targets, e.g. you'll include foo.d if and only if you're making foo.o).

You can use make recursively (heresy!), invoking $(MAKE) for each target object, using a makefile that includes that target's dependencies.

But actually including the file takes negligible time, it's the rebuilding of the file (automatic for any included file that's out of date) that takes time. If needless rebuilding is what you want to avoid, you can use a very clever trick. When must foo.d be rebuilt? Only when something about foo has changed. But in that case foo.o must also be rebuilt. So don't have a seperate rule for foo.d, just rebuild it as a side effect of making foo.o. That way you can include all dependency files and not waste time rebuilding them if they aren't needed.

EDIT:
I'm astounded that merely including these files can add 2-3 seconds to make clean. My last paragraph is off the mark, so let me expand on the first two options.

If all is the only target for which these files should be included, and you make all from the command line (and not e.g. make all tests tarball install kitchenSink), then this will do it:

ifeq ($(MAKECMDGOALS),all)
-include $(DEPS_debug)
endif

Note that this will not include foo.d if you make foo.o. You can write a more sophisticated conditional, something like

$(foreach targ,$(MAKECMDGOALS),$(eval $(call include_deps $(targ)))...

but that's pretty advanced, so let's get a simple version working first.

If you'd rather avoid the conditional and use recursive Make, the simplest way is to split the makefile in two:

makefile:

all:
    $(MAKE) -f makefile.all

clean:
    rm whatever

...other rules

makefile.all:

DEPS_debug = $(patsubst %.cpp,build_debug/%.d,$(SRC))
OBJ_debug = $(patsubst %.cpp,build_debug/%.o,$(SRC))
-include $(DEPS_debug)

all: program_debug
program_debug: $(OBJ_debug)
    $(CC) $(CFLAGS) $(OBJ_debug) -o $@


Indenting a line by a TAB makes make think it's a command to be passed to the shell (as you found out). It doesn't work that way.

The - in front of include suppresses errors that might result from DEPS_debug not existing (e.g. when running clean or release without having had a dependency-file-generating call first). Since DEPS_debug is not a dependency of those rules (clean / release), your dependency files do not get generated when you call them, and everything is fine. I don't really see the problem you're having - you don't have to make the include conditional.

Perhaps you'd like to change your approach, though. Instead of having a seperate *.d target, with a seperate -M preprocessor pass, you might want to try something like -MMD -MP which generates the dependency files inline during code generation, in your standard *.c -> *.o pass.

(I know this sounds completely wrong at first, but when you think about it, it makes sense. Makefile logic is a bit backwards that way, unless you're familiar with functional programming.)


includes are independent of the rules, as they are makefile indications, not compilation indications. You can, however, use makefile conditionals based on special makefile variables such as MAKECMDGOALS, that is set to the default goal:

ifeq ($(MAKECMDGOALS),all)
    -include whatever
endif

This is included when no default goal is specified. You can change the condition to specify the exact goal you want to check to include other sub-makefiles.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号