Make: a pattern rule matching multiple extensions

I have duplicate template rules for several extensions (ex: cpp and cc ):

 $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp @$(CXX) $(CPPFLAGS) -I. -o $@ -c $? $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cc @$(CXX) $(CPPFLAGS) -I. -o $@ -c $? 

Is there a way to have one template rule that matches both extensions, instead of having two rules?

+5
source share
2 answers

You can use .SECONDEXPANSION for this. Here is an example:

 OBJ_DIR:=obj SRC_DIR:=src TARGETS:=obj/foo.o obj/bar.o all: $(TARGETS) .SECONDEXPANSION: $(OBJ_DIR)/%.o: $$(wildcard $(SRC_DIR)/%.cpp) $$(wildcard $(SRC_DIR)/%.cc) @$(CXX) $(CPPFLAGS) -I. -o $@ -c $< 

Create src/foo.cc and src/bar.cpp and issue make -n and you will get:

 g++ -I. -o obj/foo.o -c src/foo.cc g++ -I. -o obj/bar.o -c src/bar.cpp 

If you have foo.cc and foo.cpp , this will behave exactly like the version in the question foo.cpp here ( foo.cpp will take precedence over foo.cc , which will be ignored).

The $ signs are doubled for $$(wildcard... to prevent evaluation during the first extension. You can have $$(SRC_DIR) just like $(SRC_DIR) , since that doesn't matter (in the code above), when this variable expands.

+3
source

No, you cannot combine the two rules. Necessary conditions must match.

But you can avoid the need to specify the recipe twice.

Or using the definition for the recipe:

 define COMPILE @$(CXX) $(CPPFLAGS) -I. -o $@ -c $? endef $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp $(COMPILE) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cc $(COMPILE) 

Or, using a loop and eval to define recipes (untested, I might have gotten some of the screens, but I prefer the definition approach anyway):

 $(foreach prereq,cc cpp,$(eval $(OBJ_DIR)/%.o: $(SRC_DIR)/%.$(prereq) ; @$(CXX) $(CPPFLAGS) -I. -o $@ -c $?)) 
+5
source

Source: https://habr.com/ru/post/1211111/


All Articles