【问题标题】:makefile to compile all cpp files in all subdirsmakefile 编译所有子目录中的所有 cpp 文件
【发布时间】:2015-01-16 02:02:57
【问题描述】:

我的存储库如下所示:

./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,它将为每个 .cpp 文件创建一个依赖文件 (.d) 到 ./dep 中,然后将这些 .cpp 文件中的每一个编译到 ./obj 中的一个 obj 中

我不想明确说明模块的名称和路径 - 只是获取 ./src 中的所有目录并在每个目录中找到 cpp 文件并为其创建目标规则。

编辑:我正在使用 Windows。

【问题讨论】:

  • 依赖.d 文件通常使用 c++ 编译器的适当编译器选项生成。例如。对于g++,它是--MM--MD 选项系列。另请参阅 Q&Athis(可能更多)。
  • 顺便说一句,我发现将 .d 文件与已编译的 .o 文件一起保存比将它们放在单独的目录中更容易。使clean: 目标更加干净

标签: c++ makefile subdirectory


【解决方案1】:

在 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 外壳

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' 中创建子目录?
【解决方案2】:

您可以执行的最简单的 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 魔法,你可以完全避免使用 SRCDIRS 的 shell。)
  • 我没有提到我使用 Windows。所以“查找”不可用
  • 有什么方法可以在 windows 上做一些 polyfill?
猜你喜欢
  • 1970-01-01
  • 2018-02-02
  • 1970-01-01
  • 2012-10-18
  • 1970-01-01
  • 1970-01-01
  • 2012-02-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多