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

如何设置Makefile中仅执行一次的分组触发规则?

问题描述

假设我有一个包含一组前置条件的Makefile规则:

prereqs=a b c

$(prereqs):
  bash configure.sh

我希望a、b、c中的任意一个触发bash configure.sh执行,但该脚本仅运行一次。我了解其他解决方法,也知晓可通过装饰器改变规则行为,请问是否有办法让make仅评估该规则一次?

答案

Make的多目标规则(如你编写的$(prereqs):结构)本质上会为每个目标生成独立的规则实例,默认情况下每个目标触发时都会执行规则体,无法直接让该规则仅被评估一次。但可以通过以下两种方式实现脚本仅执行一次的效果,同时贴合你对规则评估控制的需求:

方法1:哨兵文件触发(最常用且可靠)

通过引入一个哨兵文件作为统一触发点,让所有目标依赖这个文件,确保脚本仅在哨兵文件不存在或过期时执行一次:

prereqs=a b c

# 哨兵文件,用于记录脚本是否已执行
.configure_done:
	bash configure.sh
	touch $@  # 创建哨兵文件标记执行完成

# 让a、b、c都依赖哨兵文件,同时生成自身目标文件
$(prereqs): %: .configure_done
	touch $@

这种方式利用Make的依赖追踪机制,只有当.configure_done需要更新时才会执行脚本,所有目标共享这个触发源,自然只会执行一次。

方法2:会话变量控制(基于Make内部状态)

如果要保留原多目标规则的结构,可以利用Make的会话变量标记脚本是否已执行,通过$(eval)动态修改变量状态:

prereqs=a b c
# 初始化标记变量,0表示未执行
CONFIGURE_RUN ?= 0

# 定义规则模板,仅当标记为0时执行脚本
define CONFIGURE_TEMPLATE
$(1):
	@if [ $(CONFIGURE_RUN) -eq 0 ]; then \
		bash configure.sh; \
		$(eval CONFIGURE_RUN=1); \
	fi
	touch $(1)
endef

# 为每个前置目标生成规则
$(foreach p,$(prereqs),$(eval $(call CONFIGURE_TEMPLATE,$(p))))

第一次触发任意目标时,脚本会执行并将CONFIGURE_RUN设为1,后续目标触发时会跳过脚本执行。注意这种方式仅在同一个Make进程会话中有效,若分多次调用Make则不生效。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 05:21:01