【问题标题】:Makefile builds target every timeMakefile 每次都构建目标
【发布时间】:2018-01-28 04:29:59
【问题描述】:

我已经编写了一个 makefile 来编译不同目录中的所有源并构建一个目标。即使文件没有更改,当我运行 make 时,它​​也不会重新编译未修改的文件。但是,它总是构建目标。为什么每次运行 make 时都会单独构建目标?

CC = gcc
CFLAGS = $(INCLUDES)
TARGET = FinalBin
OUTDIR := obj

INCLUDES = -Isrc/in
S1 = src/s1
S2 = src/s2

S1_SRC = $(wildcard $(S1)/*.c)
S2_SRC = $(wildcard $(S2)/*.c)
SRCS := $(S1_SRC) \
    $(S2_SRC)

OBJS := $(patsubst %.c,$(OUTDIR)/%.o,$(SRCS))

SRCDIRS := $(S1) $(S2)

all: $(TARGET)

$(TARGET): builddir $(OBJS)
    @echo "Building..." $@
    @$(CC) $(OBJS) $(CFLAGS) -o $@
    @echo "Build Complete!"

$(OUTDIR)/%.o: %.c
    @echo "Compiling.." $(notdir $<)
    @$(CC) $(CFLAGS) -MMD -c $< -o $@

clean:
    -@rm -rf $(OUTDIR) FinalBin
    @echo "Clean complete!"

builddir :
    @$(call create-dir)

define create-dir
    for dir in $(SRCDIRS); \
    do \
        mkdir -p $(OUTDIR)/$$dir; \
    done
endef

-include $(wildcard $(OBJS:.o=.d))

$(TARGET) 每次都是从目标文件构建的。请指导我哪里出错了。

更新:

CC = gcc
CFLAGS = $(INCLUDES)
TARGET = FinalBin
OUTDIR := obj

INCLUDES = -Isrc/in
S1 = src/s1
S2 = src/s2

S1_SRC = $(wildcard $(S1)/*.c)
S2_SRC = $(wildcard $(S2)/*.c)
SRCS := $(S1_SRC) \
    $(S2_SRC)

OBJS := $(patsubst %.c,$(OUTDIR)/%.o,$(SRCS))

SRCDIRS := $(S1) $(S2)
OUTDIRS := $(addprefix $(OUTDIR)/,$(SRCDIRS))

all: $(TARGET)

$(TARGET): $(OBJS)
    @echo "Building..." $@
    @$(CC) $(OBJS) $(CFLAGS) -o $@
    @echo "Build Complete!"

$(OUTDIR)/%.o: $(OUTDIRS) %.c
    @echo "Compiling.." $(notdir $(filter %.c,$^))
    @$(CC) $(CFLAGS) -MMD -c $(filter %.c,$^) -o $@

clean:
    -@rm -rf $(OUTDIR) FinalBin
    @echo "Clean complete!"

$(OUTDIRS):
    mkdir -p $@

builddir :
    @$(call create-dir)

define create-dir
    for dir in $(SRCDIRS); \
    do \
        mkdir -p $(OUTDIR)/$$dir; \
    done
endef

-include $(wildcard $(OBJS:.o=.d))

这每次都会构建所有文件。

最终解决方案:

CC = gcc
CFLAGS = $(INCLUDES)
TARGET = FinalBin
OUTDIR := obj

INCLUDES = -Isrc/in
S1 = src/s1
S2 = src/s2

S1_SRC = $(wildcard $(S1)/*.c)
S2_SRC = $(wildcard $(S2)/*.c)
SRCS := $(S1_SRC) \
    $(S2_SRC)

OBJS := $(patsubst %.c,$(OUTDIR)/%.o,$(SRCS))

SRCDIRS := $(S1) $(S2)
OUTDIRS := $(addprefix $(OUTDIR)/,$(SRCDIRS))

all: $(TARGET)

$(TARGET): $(OUTDIRS) $(OBJS)
    @echo "Building..." $@
    @$(CC) $(OBJS) $(CFLAGS) -o $@
    @echo "Build Complete!"

$(OUTDIR)/%.o: %.c
    @echo "Compiling.." $(notdir $<)
    @$(CC) $(CFLAGS) -MMD -c $< -o $@

clean:
    -@rm -rf $(OUTDIR) FinalBin
    @echo "Clean complete!"

$(OUTDIRS):
    @mkdir -p $@

-include $(wildcard $(OBJS:.o=.d))

最终解决方案按预期工作!

【问题讨论】:

    标签: c linux makefile


    【解决方案1】:

    您可以使用 make 的调试输出来查找它认为需要重建的内容:

    make -d | grep remake
    

    您可能会看到如下内容:

    No need to remake target `Makefile'.
        Must remake target `builddir'.
          No need to remake target `src/s1/x.c'.
        No need to remake target `obj/src/s1/x.o'.
      Must remake target `FinalBin'.
    Must remake target `all'.
    

    这说明它一直认为builddir目标需要重做。由于这是$(TARGET) 的依赖项,因此它也重建了后者。

    如果您使用规则而不是函数来创建构建目录,make 将知道是否需要创建它们。例如,添加变量$(OUTDIRS),为其添加规则,并使其成为编译的依赖项:

    SRCDIRS := $(S1) $(S2)
    OUTDIRS := $(addprefix $(OUTDIR)/, $(SRCDIRS)) # <---------- Add this variable
    
    All: $(TARGET) 
    
    $(TARGET):  $(OBJS)
        @echo "Building..." $@
        @$(CC) $(OBJS) $(CFLAGS) -o $@
        @echo "Build Complete!"
    
    $(OUTDIR)/%.o: $(OUTDIRS) %.c # <--------------------------- Add dependency to $(OUTDIRS)
        @echo "Compiling.." $(notdir $<)
        @$(CC) $(CFLAGS) -MMD -c $< -o $@
    
    clean:
        -@rm -rf $(OUTDIR) FinalBin
        @echo "Clean complete!"
    
    $(OUTDIRS): # <--------------------------------------------- Add rule
        mkdir -p $@
    
    -include $(wildcard $(OBJS:.o=.d))
    

    【讨论】:

    • 感谢调试提示!我现在将其设为all: builddir $(TARGET)。它不是每次都构建 $(TARGET) 。但是,是否有可能让它打印出没有任何东西可以构建?
    • @Gomu 我不确定你到底在问什么,但我用另一种方式编辑了我的答案。
    • 我已经用建议的修改更新了这个问题。但是,现在每次都编译所有文件。如果我遗漏了什么,请告诉我。
    • 我之前的问题是,实际上随着all: builddir $(TARGET) 的初始更改,当没有要构建的东西时,make 没有打印Nothing to build 消息。它刚刚退出。这就是为什么我问是否可以手动回显该消息。
    • 如果我将$(OUTDIRS) 添加为$(TARGET) 的依赖项,那么它会按预期工作。它甚至打印Nothing to be done for all'.` 当没有要构建的东西时。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    • 1970-01-01
    • 1970-01-01
    • 2013-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多