views:

318

answers:

3

Is there a way to direct make/gmake to act upon conditional dependencies?

I have this rule in place:

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
  $(CPPC) -c $(FLAGS_DEV) $< -o $@

In the general case, every .cpp file has a corresponding .h file; however there are a few exceptions. Is there a way to achieve "depend on this if it exists" with gmake? Failing that, is there a best practice for this type of setup?

Thanks in advance; Cheers!

Update: I'm using GCC

A: 

You can achieve this through judicious use of pattern rules in your makefile, thanks to two features of gmake pattern rule matching. First, gmake attempts to match patterns in the order they are declared; second, a pattern matches if and only if all of the prereqs in the pattern can be satisfied (either they already exist as files, or there is a rule to make them). So, if you write your makefile like this:

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp $(SRC_DIR)/%.h
        $(CPPC) -c $(FLAGS_DEV) $< -o $@

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
        $(CPPC) -c $(FLAGS_DEV) $< -o $@

gmake will match the first pattern for those files that have a corresponding .h file, and the second for those that do not. Of course the up-to-date checks will behave as expected as well (eg, "foo.o" will be considered out-of-date if "foo.h" exists and is newer).

You may want to use another variable to eliminate the redundancy between these two rules; eg:

COMPILE=$(CPPC) -c $(FLAGS_DEV) $< -o $@
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp $(SRC_DIR)/%.h
        $(COMPILE)

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
        $(COMPILE)
Eric Melski
+2  A: 

A better way to do this, is to actually determine the dependencies of the cpp files with gcc -MM and include them in the makefile.

SRCS = main.cpp other.cpp
DEPS = $(SRCS:%.cpp=$(DEP_DIR)/%.P)

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
  $(CPPC) -c $(FLAGS_DEV) $< -o $@

$(DEP_DIR)/%.P: $(SRC_DIR)/%.cpp
  $(CPPC) -MM $(FLAGS_DEV) -MT $(OBJ_DIR)/$*.o -MP -MF $@ $<

-include $(DEPS)
wich
A: 

A much more robust solution would be to let gcc generate the dependencies for you. If you make a rule to generate (e.g.) .d files which contain generated dependencies then you don't have to worry about whether a .h file exists for any given .cpp file and you automatically get the correct dependencies for each .cpp file for any .h files that it depends on.

E.g.

DEPFILES=$(patsubst $(SRC_DIR)/%.cpp,$(OBJ_DIR)/%.d,$(wildcard $(SRC_DIR)/*.cpp))

$(OBJ_DIR)/%.d: $(SRC_DIR)/%.cpp
    g++ -MF $@ -MM -MT $@ -MT $(basename $@).o %<

include $(DEPFILES)

Note that I make both the .d and the .o targets of the make rule using the -MT option so that the dependencies are correctly remade following any changes to any of the current dependencies.

Charles Bailey