1

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 running 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 $@
asked Jun 6, 2011 at 13:59
3
  • It's rather unclear what you want, or why the include line doesn't do whatever it is that you want. For automatically-generated dependency information, that include line does exactly what I would want... perhaps that is because I am using -MMD -MP (inline generation) instead of -MM (extra pass for dependencies). Commented Jun 6, 2011 at 14:01
  • I want to -include $(DEPS_debug) only when making target all and not when making target clean or target release for instance. Currently, putting it in there has make trying to run include from the shell rather than its built-in include function. Commented Jun 6, 2011 at 14:03
  • See my answer below. Your first error is TAB-ing the include, your second is trying to make it conditional in the first place. You simply don't have to. It doesn't even speed up things - make has to check the directory contents anyway... Commented Jun 6, 2011 at 14:17

3 Answers 3

3

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 $@
answered Jun 6, 2011 at 14:22
Sign up to request clarification or add additional context in comments.

8 Comments

It is my fault that I didn't include the format of my makefile more comprehensively, as I am already doing exactly what you speak of in your last paragraph, I generate my .d files at the same time that I build my .o's.
@Steven Liu: really? And you find that just including unneeded .d files significantly slows down make clean? How many files are we talking about, and how many seconds of delay?
About 2-3 seconds on an Atom netbook. I kept wondering why make clean took so long.
@Steven Lu: Apologizes from me, too, for adamantly claiming that you don't need to make the inclusion conditionally. +1 to Beta's answer.
recursive make looks really clean and nice. Two thumbs up!
|
1

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.)

answered Jun 6, 2011 at 14:13

Comments

1

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.

answered Jun 6, 2011 at 14:11

2 Comments

I did some testing and it seems like ifeq ($(.DEFAULT_GOAL),) results in true even when I run make clean.
I think that this approach will work, but .DEFAULT_GOAL is not the best choice. Take a look at MAKECMDGOALS instead.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.