GNU Make每次都会生成目标,而不是在需要时生成目标

时间:2018-02-04 10:46:41

标签: makefile gnu-make gnu

我有这个Makefile:

PROJECT_DIR = $(abspath ..)

BUILDDIR = $(PROJECT_DIR)/build
OBJDIR   = $(BUILDDIR)/obj
BINDIR   = $(BUILDDIR)/bin
SRCDIR   = $(PROJECT_DIR)/src/app
SOURCES  := $(wildcard $(SRCDIR)/*.cpp)
INCLUDES := $(wildcard $(SRCDIR)/*.h)
OBJECTS  := $(SOURCES:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)

APPNAME=blink
APP=$(BINDIR)/$(APPNAME)

all: $(APP).elf

dirs:
    @echo "Project dir: " $(PROJECT_DIR)
    mkdir -p $(BUILDDIR)
    mkdir -p $(OBJDIR)
    mkdir -p $(BINDIR)

# Link
$(APP).elf: $(OBJECTS)
    $(CPP) $(CPPFLAGS) -o $@ $^
    @echo "Linked "$<" successfully!"

# Compile:
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.cpp dirs
    $(CPP) $(CPPFLAGS) -c $< -o $@
    @echo "Compiled successfully"

当我运行时:make每次都重新编译所有文件,而不是仅在源代码更改时才执行此操作。我怀疑是因为build目录时间戳与${APP}.elf目标一起更新,但不知道如何解决它。

2 个答案:

答案 0 :(得分:2)

dirs的食谱永远不会成为目标:它永远不会创建文件 叫dirs。因此这条规则:

$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.cpp dirs

总是有一个过时的预处理,dirs,所以它的配方总是运行。

将其设为order-only-prerequisite

$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.cpp | dirs

将补救无根据的重新编译和重新连接。但dirs仍然存在 从未通过其配方制作的目标,以便仍然可以运行配方。

要解决这个问题,请执行以下操作:

ODIRS := $(BUILDDIR)/$(OBJDIR) $(BUILDDIR)/$(BINDIR)
...

$(ODIRS):
    mkdir -p $@

$(APP).elf: $(OBJECTS) | $(BINDIR)
...

$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.cpp | $(OBJDIR)
...

此外,allphony target:您应该这样说:

.PHONY: all

all: $(APP).elf
...
...

提供clean目标是正常的:

.PHONY: all clean

all: $(APP).elf
...
...
clean:
    rm -fr $(BUILDDIR)

答案 1 :(得分:1)

问题是1-NeuralNetworksDeeplearning/Assignment/

您的$(OBJDIR)/%.o : $(SRCDIR)/%.cpp dirs文件取决于.o。 Makefile会将dirs解释为文件名,并搜索当前目录,然后发现没有名为dirs的文件,因此规则为:

dirs

将被执行,这意味着您的dirs: @echo "Project dir: " $(PROJECT_DIR) ... 依赖项已更新,因此本身也需要更新。这就是你

的原因
$(OBJDIR)/%.o

将一次又一次地执行。

要进行修复,请从此依赖项中删除$(OBJDIR)/%.o : $(SRCDIR)/%.cpp dirs $(CPP) $(CPPFLAGS) -c $< -o $@ 。它只需要在开始时执行。