You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Makefile中当目标由其他规则生成时跳过其对应规则

问题分析与修复方案

先看你遇到的情况:你的Makefile在默认执行时符合预期,但启用USE_CACHE参数后,build目标并没有被缓存规则跳过,反而还是执行了原本希望跳过的命令——这确实是个典型的Makefile依赖逻辑陷阱。

先贴出你的原始Makefile方便对照:

all: build
build:
ifdef USE_CACHE
	@printf ":sigh: failure :(\nThis should have been skipped by cache's recipe.\n"
endif
	@printf "Building ...\n"
	touch $@
ifdef USE_CACHE
build: cache
cache:
	@printf "Installing cache ...\n"
	touch $@
	@printf "Trying to skip build because cache satisfied it ... \n"
	touch build
endif

当执行rm build cache; make USE_CACHE=1时,你会看到不想看到的输出:

Installing cache ...
touch cache
Trying to skip build because cache satisfied it ... 
touch build
:sigh: failure :(
This should have been skipped by cache's recipe.
Building ...
touch build

问题根源

Make的执行逻辑是先判断目标是否需要构建,再处理依赖:

  1. 一开始build不存在,Make已经决定要执行build的命令
  2. 发现build依赖cache,于是先构建cache,在这个过程中创建了build
  3. 但Make已经进入了build的构建流程,哪怕此时build已经存在,还是会执行预先定义好的build命令

另外你在Makefile中对build目标的规则是分两段定义的,启用USE_CACHE时会合并build的命令和依赖,这让问题更隐蔽——build既有依赖cache,又有自己的执行命令,导致Make不会因为cache规则创建了build就跳过后续操作。

修复后的Makefile

我们可以用条件编译把两种场景的build规则完全分开,让启用缓存时build只依赖cache、自身无执行命令:

all: build

ifdef USE_CACHE
# 启用缓存时:build仅依赖cache,无自身命令
build: cache

cache:
	@printf "Installing cache ...\n"
	touch $@
	@printf "Trying to skip build because cache satisfied it ... \n"
	touch build
else
# 未启用缓存时:正常执行build构建逻辑
build:
	@printf "Building ...\n"
	touch $@
endif

测试验证

  • 首次启用缓存执行:
    rm build cache; make USE_CACHE=1
    
    输出符合预期,没有执行build的命令:
    Installing cache ...
    touch cache
    Trying to skip build because cache satisfied it ... 
    touch build
    
  • 缓存已存在时执行make USE_CACHE=1,输出为空(所有目标已是最新状态)
  • 未启用缓存时执行,和原来的正常输出一致

内容的提问来源于stack exchange,提问作者Trevor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:33:21