GNU Make:Makefile无法检测目标可执行文件已构建的问题求助
解决方案
问题根源分析
- 重复链接问题:你将目标可执行文件
${PROJ}标记为.PHONY,伪目标的特性是make会忽略其实际文件的存在和时间戳,每次都会强制执行对应的构建命令,这就是即使可执行文件已存在仍重复链接的原因。 - options重复输出问题:
all目标直接依赖options(同样是伪目标),无论可执行文件是否需要重建,make都会执行options的打印逻辑。
修改后的Makefile实现(推荐方案)
通过将选项打印逻辑与可执行文件的构建条件绑定,仅在需要编译/链接时才输出选项,同时移除伪目标标记让make正常检测文件时间戳:
PROJ := comms_test CSRCS = $(PROJ).c CC := cc LD := gcc INCLUDES := \ -I. LDFLAGS = CPPFLAGS = CFLAGS := \ -O0 \ -Wpedantic OBJS += $(CSRCS:%.c=%.o) .PHONY: all clean echo test all: $(PROJ) # 仅当需要构建可执行文件时,先打印选项再执行链接 $(PROJ): $(OBJS) @# 检查可执行文件是否不存在,或者依赖的.o文件更新时间晚于可执行文件 @if [ ! -f "$@" ] || [ "$(filter-out $@,$^)" -nt "$@" ]; then \ echo "$(PROJ) build options:"; \ echo "CC = $(CC)"; \ echo "CFLAGS = $(CFLAGS)"; \ echo "CPPFLAGS = $(CPPFLAGS)"; \ echo "INCLUDES = $(INCLUDES)"; \ echo "LDFLAGS = $(LDFLAGS)"; \ fi ${LD} -o "$@" ${OBJS} ${LDFLAGS} %.o: %.c ${CC} ${CPPFLAGS} ${CFLAGS} ${INCLUDES} -c "$<" -o "$@" clean: rm -rf ${OBJS} ${PROJ} echo: @echo ${CSRCS} @echo ${OBJS}
效果说明
- 当可执行文件
comms_test已存在且所有.o依赖文件未修改时,执行make或make comms_test只会输出make: 'comms_test' is up to date.(若需隐藏此提示,可在all目标后添加@:)。 - 当
.c文件修改导致.o更新,或可执行文件被删除时,make会先打印编译选项,再执行编译和链接操作。
备选方案(使用中间标记文件)
如果偏好通过make的目标依赖而非shell逻辑实现,可使用一个临时标记文件控制选项打印:
PROJ := comms_test CSRCS = $(PROJ).c CC := cc LD := gcc INCLUDES := \ -I. LDFLAGS = CPPFLAGS = CFLAGS := \ -O0 \ -Wpedantic OBJS += $(CSRCS:%.c=%.o) .PHONY: all clean echo test all: $(PROJ) # 可执行文件依赖中间标记文件,确保选项仅在需要时打印 $(PROJ): .build-mark ${LD} -o "$@" ${OBJS} ${LDFLAGS} # 中间标记文件依赖.o文件,更新时打印选项并创建标记 .build-mark: $(OBJS) @echo "$(PROJ) build options:"; \ echo "CC = $(CC)"; \ echo "CFLAGS = $(CFLAGS)"; \ echo "CPPFLAGS = $(CPPFLAGS)"; \ echo "INCLUDES = $(INCLUDES)"; \ echo "LDFLAGS = $(LDFLAGS)"; \ touch "$@" # 编译.o文件时删除标记,触发下次构建重新打印选项 %.o: %.c ${CC} ${CPPFLAGS} ${CFLAGS} ${INCLUDES} -c "$<" -o "$@" @rm -f .build-mark clean: rm -rf ${OBJS} ${PROJ} .build-mark echo: @echo ${CSRCS} @echo ${OBJS}
内容的提问来源于stack exchange,提问作者kollie
相关产品推荐
相关产品推荐

