如何基于git describe输出触发Make目标的条件重建?
解决方法
核心思路是引入强制执行的空依赖,同时保留仅当内容变化时才更新version.c的逻辑,既保证Git版本变化时能触发更新,又避免无意义的重复构建。
具体修改步骤
- 删除原Makefile中的
.PHONY: version.c声明,新增一个FORCE伪目标 - 将
FORCE设为version.c的依赖项,保证每次构建都会执行version.c的生成逻辑 - 原有
cmp对比逻辑已经可以保证仅当版本号变化时才覆盖version.c,因此version.c的修改时间只会在版本实际变化时更新,不会触发不必要的后续编译。
修改后的完整Makefile
SOURCEFILES = $(wildcard *.c) version.c PROGRAMS = $(addprefix build/,$(SOURCEFILES:.c=.out)) # 新增FORCE伪目标,没有依赖和生成规则,每次都会被认为已更新 .PHONY: all clean FORCE all: $(PROGRAMS) clean: rm -fR build build/%.out: build/%.o Makefile mkdir -p build gcc -g $< -o $@ build/%.o: %.c Makefile mkdir -p build gcc -Wall -Werror -g -c $< -o $@ # 增加FORCE作为依赖,保证每次都会执行生成规则 version.c: version.c.in Makefile FORCE cp $< $@_temp sed -i "s/@BUILDVERSION@/$$(git describe --always --dirty=-dirty)/g" $@_temp @cmp -s $@_temp $@ || mv $@_temp $@ rm -f $@_temp
原理解释
FORCE作为伪目标,没有对应的生成文件,每次构建都会被make判定为"已更新",因此version.c的生成规则每次都会执行- 生成规则中只有新生成的
version.c_temp和原有version.c内容不一致时,才会覆盖原有version.c,此时version.c的修改时间才会更新,触发依赖它的.o、.out文件重新构建 - 如果版本号没有变化,
version.c的修改时间不会变化,后续的编译、链接步骤都不会执行,避免了无意义的重复构建
也有方案尝试把
.git/index、.git/refs下的相关文件作为version.c的依赖来实现自动触发,但这种方案覆盖场景不全(比如新增标签、修改Git配置等操作不会修改这些文件),且实现复杂,FORCE方案是更通用稳定的选择。
内容的提问来源于stack exchange,提问作者Benedikt Schmidt
相关产品推荐
相关产品推荐

