c - Makefile 每次构建目标

标签 c linux makefile

我已经编写了一个 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))

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

最佳答案

您可以使用 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))

关于c - Makefile 每次构建目标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48483162/

相关文章:

linux - grep命令提取一个词

Linux:使用假鼠标指针进行 Xautomation

c++ - Linux上适用于C++的任何更智能的编译系统

c - snprintf 溢出并随机打印垃圾到文件。帮助

c - linux 查找调用的命令

linux - 有没有办法通过 LDAP 命令行执行系统命令?

makefile - `2>/dev/null` 在 Makefile 中不起作用

c - 如何在 include 预处理器指令中包含 makefile 变量

c - 如何使用 C 中的 print 进行这样的输出

c - 链表 C : add node to beginning, 意外的 '0' 值