GNU Make 4.2.1 中意外跳过先决条件

Unexpected prerequisite skip in GNU Make 4.2.1

我正在尝试创建一个通用 Makefile 以用于我的大部分项目。它应该按如下方式工作:只重建和 link 那些 .o 文件 .c.h 依赖已经改变。 .o.d 文件存储在名为 'build'.

的单独目录中

在官方 GNU Make 手册和一些谷歌搜索的帮助下,我已经设法实现了所需的行为,除了一件事:当我 运行 make re 我得到错误: Assembler messages: Fatal error: can't create build/ft_build_buffer.o: No such file or directory — 原因是 'build' 目录仅在生成 .d 文件时创建,但由于某种原因 re rule 直接跳过这一步直接编译 .o 文件!注意:如果我 运行 make clean && make fclean && make all (这应该是完全一样的东西)一切正常。

其他一些事情:我尝试使用 -MMD 选项动态生成依赖项,但在我的机器上导致 .d 文件仅包含 .c 依赖项。当然,我可以让所有 .c 文件都依赖于所有 .h 文件,但这似乎是一个非常草率的解决方案。

欢迎分享任何其他 advice/improvements 将使此文件更清晰和可读的内容,谢谢! :)

# Define the C compiler to use.
CC := gcc

# Define any compile-time flags.
CFLAGS := -I./include -Wall -Wextra -Werror -g
#CFLAGS := -I./include -march=native -O2 -pipe

# Define the executable file.
BIN := ft_hexdump

# Define build directory.
BUILD_DIR := build

# Define source files directory.
SRC_DIR := src

# Define the C source files.
SRCS := $(wildcard $(SRC_DIR)/*.c)

# Define the C object files.
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)

# Define the prerequisite files.
DEPS := $(OBJS:%.o=%.d)

.PHONY: all clean fclean re

.DELETE_ON_ERROR:

all: $(BIN)

-include $(DEPS)

$(BIN): $(OBJS)
    $(CC) $(CFLAGS) $^ -o $@

$(BUILD_DIR)/%.o: $(BUILD_DIR)/%.d
    $(CC) $(CFLAGS) -c $(SRC_DIR)/$*.c -o $@

$(BUILD_DIR)/%.d: $(SRC_DIR)/%.c
    @mkdir -p $(@D)
    @set -e; rm -f $@; \
    $(CC) $(CFLAGS) $(INCLUDE) -MM  $< > $@.$$$$; \
    sed 's,\($*\)\.o[ :]*,.o $@ : ,g' < $@.$$$$ > $@; \
    rm -f $@.$$$$

clean:
    -rm -rf $(BUILD_DIR)

fclean: clean
    -rm -f $(BIN)

re: fclean all

这是@M.M

建议的修改后的工作版本
# Define the C compiler to use.
CC := gcc

# Define any compile-time flags.
CFLAGS := -I./include -Wall -Wextra -Werror -g
#CFLAGS := -I./include -march=native -O2 -pipe

# Define the executable file.
BIN := ft_hexdump

# Define build directory.
BUILD_DIR := build

# Define source files directory.
SRC_DIR := src

# Define the C source files.
SRCS := $(wildcard $(SRC_DIR)/*.c)

# Define the C object files.
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)

# Define the prerequisite files.
DEPS := $(OBJS:%.o=%.d)

.PHONY: all clean fclean re

.DELETE_ON_ERROR:

all: $(BIN)

-include $(DEPS)

$(BIN): $(OBJS)
    $(CC) $(CFLAGS) $^ -o $@

$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
    @mkdir -p $(@D)
    $(CC) $(CFLAGS) -MMD -c $(SRC_DIR)/$*.c -o $@

clean:
    -rm -rf $(BUILD_DIR)

fclean: clean
    -rm -f $(BIN)

re: 
    $(MAKE) fclean 
    $(MAKE) all