编写makefile以编译所有子目录中的所有cpp文件

3

我的代码库看起来像这样:

./src/ModuleA/ModuleA.cpp
./src/ModuleA/ModuleA.h
./src/foo/ModuleB.cpp
./src/foo/ModuleB.h
./src/bar/ModuleC.cpp
./src/bar/ModuleC.h
<A few more modules>

./obj
./dep
./makefile

我想创建一个makefile,使其能够为./dep中的每个.cpp文件创建一个依赖关系文件(.d),然后将这些.cpp文件编译成./obj中的一个目标文件。
我不想明确指定模块的名称和路径 - 只需获取./src中所有目录,并在每个目录中查找cpp文件并创建目标规则即可。
编辑:我正在使用Windows。

依赖关系.d文件通常是使用c ++编译器的适当编译器选项生成的。例如,对于g ++,它是--MM--MD选项组。还可以参见此问答此处(可能还有更多)。 - πάντα ῥεῖ
顺便说一句,我发现将.d文件与编译好的.o文件放在一起比放在单独的目录中更容易。这样可以使得clean:目标更加“干净”。 - πάντα ῥεῖ
2个回答

6
在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)

子目录会被创建到objdep,以避免如果两个文件共享相同的文件名但位于不同的子目录中而发生冲突。这样还可以避免在调用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

在“.\obj”中是否有可能不创建子目录? - user972014

0

你可以做的最简单的makefile之一如下所示:

OBJDIR   = .srcobjs

SRCS    := $(shell find . -name '*.cpp')
SRCDIRS := $(shell find . -name '*.cpp' -exec dirname {} \; | uniq)
OBJS    := $(patsubst %.cpp,$(OBJDIR)/%.o,$(SRCS))
DEPS    := $(patsubst %.cpp,$(OBJDIR)/%.d,$(SRCS))

DEBUG    = -g
INCLUDES = -I./Include
CXXFLAGS = $(DEBUG) -Wall -pedantic $(INCLUDES) -c

DEPENDS  = -MT $@ -MD -MP -MF $(subst .o,.d,$@)

它将查找所有的 .cpp 文件并编译它们。


没有必要两次使用 find。你已经在 $(SRCS) 中拥有了 *.cpp 文件列表。(如果你使用一些 make 的技巧,完全可以避免使用 shell 来处理 SRCDIRS)。 - Etan Reisner
1
我忘了提到我使用的是Windows操作系统,所以“find”命令不可用。 - user972014
有没有办法为 Windows 制作一些 find 的 polyfill? - Tomáš Zato

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接