I’ve been using qmake and CMake in the past without any problem to generate my makefiles. However, recently I figured on some of the clusters I run my codes these tools are harder to find/install so I’ve decided writing bare Makefiles. Besides I could also learn a thing or two about Makefiles 😉
My project involves several directories with source/header files inside and most often cross dependencies between them. I’ve learned, through SO, to use -MM flag to automatically generate dependency information. My Makefiles look like this
include $(HEAD_DIR)/common.mk
OBJS_DIR = objs
LIBS_DIR = libs
SRCS = Matrix.cpp MatrixFull.cpp
OBJS = $(patsubst %,$(OBJS_DIR)/%,$(SRCS:.cpp=.o))
LIB_0 = $(patsubst %, $(LIBS_DIR)/%,libalgebra.a)
DEPS := $(patsubst %,$(OBJS_DIR)/%,$(SRCS:.cpp=.d))
-include $(DEPS)
.PHONY: all
all:
@echo " ===== Building dependencies in lib/algebra ===== "
@$(MKDIR) $(OBJS_DIR)
@$(MAKE) $(OBJS)
@$(MKDIR) $(LIBS_DIR)
@$(MAKE) $(LIB_0)
@echo " ===================== done ===================== "
$(OBJS_DIR)/%.o: %.cpp
@echo " compiling source file: $< ..."
$(CXX) -c $(CXXFLAGS) -I$(INCLUDE_PATH) -MM $< -o $@
$(LIB_0): $($(OBJS_DIR)/%.o)
@echo " generating library file: $(@F) ..."
@$(AR) $(AR_FLAGS) $@ $^
.PHONY: clean
clean:
@$(RM) $(OBJS_DIR) $(LIBS_DIR)
This generally works fine but I’d like to improve on couple of things:
1) When I change a header file and I issue make, somehow the compiler does not pick all and seems to default to DEPS. Is this supposed to happen in this makefile? How can I make all the default rule?
2) How can I make depenency files invisible? I tried DEPS := $(patsubst %,$(OBJS_DIR)/.%,$(SRCS:.cpp=.d)) but that did not help
3) Is there any specific suggestion you could give me if you think this Makefile could be improved in any other way?
EDIT: To be honest, I’m not even sure how make invokes the compiler to generate dependencies :p … I do not see any explicit rule for this. Is it somehow hidden in DEPS := $(patsubst %,$(OBJS_DIR)/%,$(SRCS:.cpp=.d)) ?
1) Move the
-include $(DEPS)down below theallrule. The first rule is the default rule (unless you deliberately set some special variable), so ifincludepulls in a rule aboveall:, that will be the default.2) I presume that by “make them invisible” you mean you want
.foo.dinstead offoo.d. You have to modify the rule that makes them:and then the variable that finds them:
3) I’d get rid of the recursive calls (
$(MAKE) ...), but you should make sure everything else is working right first. And I’m surprised the$(OBJS_DIR)/%.orule doesn’t go incommon.mk. Other than that it looks pretty good.4(?)) The compiler command in the
$(OBJS_DIR)/%.orule uses the-MMflag, so the compiler generates the dependency files as a side-effect.