如何在不同被包含Makefile中导出不同COMPOSE_PROFILES值?
我想为每个docker compose profile创建独立的Makefile,由根Makefile统一导入,目录结构如下:
Makefile # 导入其他Makefile docker_compose_profile_makefiles/ profile_a.Makefile profile_b.Makefile ...
需求是:每个子Makefile里的所有目标在调用docker compose时,自动使用对应文件的COMPOSE_PROFILES导出值,不需要在每个目标里重复指定。比如profile_a.Makefile的目标都用COMPOSE_PROFILES=profile_a,profile_b.Makefile的目标都用COMPOSE_PROFILES=profile_b。
之前试过顶层export指令和.EXPORT_ALL_VARIABLES,但最后一次设置的值会覆盖之前的所有设置,达不到预期效果。
示例代码
Makefile
.PHONY: all include docker_compose_profile_makefiles/*.Makefile export COMPOSE_PROFILES := default all: echo env_var: $$COMPOSE_PROFILES
docker_compose_profile_makefiles/profile_a.Makefile
# profile_a.Makefile export COMPOSE_PROFILES := profile_a profile_a: @echo "profile_a: COMPOSE_PROFILES is set to $(COMPOSE_PROFILES)"
docker_compose_profile_makefiles/profile_b.Makefile
# profile_b.Makefile export COMPOSE_PROFILES := profile_b profile_b: @echo "profile_b: COMPOSE_PROFILES is set to $(COMPOSE_PROFILES)"
实际执行结果
$> make all echo env_var: $COMPOSE_PROFILES env_var: default $> make profile_a profile_a: COMPOSE_PROFILES is set to default $> make profile_b profile_b: COMPOSE_PROFILES is set to default
期望执行结果
$> make all echo env_var: $COMPOSE_PROFILES env_var: default $> make profile_a profile_a: COMPOSE_PROFILES is set to profile_a $> make profile_b profile_b: COMPOSE_PROFILES is set to profile_b
解决方案
Make的变量是全局作用域,直接在子Makefile中覆盖export COMPOSE_PROFILES会导致全局变量被最后一次设置的值覆盖。以下是两种可靠的解决方法:
方法1:递归调用Make(推荐,适合多目标场景)
每个子Makefile的目标启动一个新的Make进程,在该进程中设置专属的COMPOSE_PROFILES变量,确保变量只在当前目标的执行环境中生效,且所有子目标无需重复配置。
修改profile_a.Makefile如下:
# profile_a.Makefile .PHONY: profile_a profile_a_up profile_a_logs # 主目标:调用递归Make并传递专属变量 profile_a profile_a_up profile_a_logs: @$(MAKE) -f $(lastword $(MAKEFILE_LIST)) $@_internal COMPOSE_PROFILES=profile_a # 实际执行逻辑的内部目标 profile_a_internal: @echo "profile_a: COMPOSE_PROFILES is set to $(COMPOSE_PROFILES)" profile_a_up_internal: docker compose up -d profile_a_logs_internal: docker compose logs -f
profile_b.Makefile只需将所有profile_a替换为profile_b即可。
方法2:目标特定变量(适合少量目标场景)
如果子Makefile中的目标数量不多,可以给每个目标单独绑定目标特定变量,并通过.EXPORT_ALL_VARIABLES确保变量传递到子进程:
修改profile_a.Makefile如下:
# profile_a.Makefile .EXPORT_ALL_VARIABLES: # 给每个目标绑定专属变量 profile_a: COMPOSE_PROFILES=profile_a profile_a: @echo "profile_a: COMPOSE_PROFILES is set to $(COMPOSE_PROFILES)" # 多目标场景下逐个绑定 profile_a_up: COMPOSE_PROFILES=profile_a profile_a_up: docker compose up -d
验证效果
执行命令后即可得到期望结果:
$> make profile_a profile_a: COMPOSE_PROFILES is set to profile_a $> make profile_b profile_b: COMPOSE_PROFILES is set to profile_b
内容的提问来源于stack exchange,提问作者codekiln

