在Windows下工作的极简Makefile:
SRC := $(patsubst $(shell CHDIR )\\%.cpp,%.cpp,$(shell DIR *.cpp /S /B))
OBJ := $(addprefix obj\, $(SRC:.cpp=.o))
DEP := $(addprefix dep\, $(SRC:.cpp=.d))
CPPFLAGS = -MMD -MP -MF dep\$(<:.cpp=.d)
all: $(OBJ)
obj\\%.o: %.cpp
@IF NOT EXIST obj\$(<D) MKDIR obj\$(<D)
@IF NOT EXIST dep\$(<D) MKDIR dep\$(<D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<
-include $(DEP)
子目录会被创建到
obj
和
dep
,以避免如果两个文件共享相同的文件名但位于不同的子目录中而发生冲突。这样还可以避免在调用
make
时每次重新编译子目录中的源文件。
更新: 更强大的版本
Windows Shell (Vista及更高版本,因为使用了FORFILE
命令)
SRCDIR := .
OBJDIR := obj
DEPDIR := dep
SRCS := $(shell FORFILES /P $(SRCDIR) /S /M *.cpp /C "CMD /C ECHO @relpath")
SRCS := $(patsubst ".\\%",$(SRCDIR)\\%,$(SRCS))
OBJS := $(SRCS:$(SRCDIR)\\%.cpp=$(OBJDIR)\\%.o)
DEPS := $(SRCS:$(SRCDIR)\\%.cpp=$(DEPDIR)\\%.d)
TREE := $(patsubst %\,%,$(dir $(OBJS)))
CPPFLAGS = -MMD -MP -MF $(<:$(SRCDIR)\\%.cpp=$(DEPDIR)\\%.d)
.PHONY: all clean
all: $(OBJS)
.SECONDEXPANSION:
$(OBJDIR)\\%.o: $(SRCDIR)\%.cpp | $$(@D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<
$(TREE): %:
MKDIR $@
MKDIR $(@:$(OBJDIR)%=$(DEPDIR)%)
clean:
IF EXIST $(OBJDIR) RMDIR /S /Q $(OBJDIR)
IF EXIST $(DEPDIR) RMDIR /S /Q $(DEPDIR)
ifeq "$(MAKECMDGOALS)" ""
-include $(DEPS)
endif
UNIX SHELL
SRCDIR := .
OBJDIR := obj
DEPDIR := dep
SRCS := $(shell find $(SRCDIR) -name "*.cpp")
OBJS := $(SRCS:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
DEPS := $(SRCS:$(SRCDIR)/%.cpp=$(DEPDIR)/%.d)
TREE := $(patsubst %/,%,$(dir $(OBJS)))
CPPFLAGS = -MMD -MP -MF $(@:$(OBJDIR)/%.o=$(DEPDIR)/%.d)
.PHONY: all clean
all: $(OBJS)
.SECONDEXPANSION:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp | $$(@D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<
$(TREE): %:
mkdir -p $@
mkdir -p $(@:$(OBJDIR)%=$(DEPDIR)%)
clean:
$(RM) -r $(OBJDIR) $(DEPDIR)
ifeq "$(MAKECMDGOALS)" ""
-include $(DEPS)
endif
.d
文件通常是使用c ++编译器的适当编译器选项生成的。例如,对于g ++
,它是--MM
,--MD
选项组。还可以参见此问答和此处(可能还有更多)。 - πάντα ῥεῖ.d
文件与编译好的.o
文件放在一起比放在单独的目录中更容易。这样可以使得clean:
目标更加“干净”。 - πάντα ῥεῖ