在Makefile中,deploy配方需要设置一个环境变量ENV来正确执行自身,而其他人则不关心,例如:
ENV =
.PHONY: deploy hello
deploy:
rsync . $(ENV).example.com:/var/www/myapp/
hello:
echo "I don't care about ENV, just saying hello!"
Run Code Online (Sandbox Code Playgroud)
如何确保设置此变量,例如:是否有办法将此makefile变量声明为部署配方的先决条件,例如:
deploy: make-sure-ENV-variable-is-set
Run Code Online (Sandbox Code Playgroud)
?
谢谢.
Bet*_*eta 155
如果ENV未定义且需要某些东西,这将导致致命错误(无论如何,在GNUMake中).
.PHONY: deploy check-env deploy: check-env ... other-thing-that-needs-env: check-env ... check-env: ifndef ENV $(error ENV is undefined) endif
(注意,ifndef和endif没有缩进 - 它们控制着什么使"看到",在Makefile运行之前生效."$(错误"用缩进键缩进,以便它只在规则的上下文中运行.)
Cla*_*ley 90
您可以创建一个隐式守护目标,用于检查词干中的变量是否已定义,如下所示:
guard-%:
@ if [ "${${*}}" = "" ]; then \
echo "Environment variable $* not set"; \
exit 1; \
fi
Run Code Online (Sandbox Code Playgroud)
然后,您可以在任何要声明已定义变量的位置添加guard-ENVVAR目标,如下所示:
change-hostname: guard-HOSTNAME
./changeHostname.sh ${HOSTNAME}
Run Code Online (Sandbox Code Playgroud)
如果您调用'make change-hostname',而不在调用中添加HOSTNAME = somehostname,那么您将收到错误,并且构建将失败.
Dan*_*der 40
内联变体
在我的makefile中,我通常使用如下表达式:
deploy:
test -n "$(ENV)" # $$ENV
rsync . $(ENV).example.com:/var/www/myapp/
Run Code Online (Sandbox Code Playgroud)
原因:
不要忘记对调试很重要的注释:
test -n ""
Makefile:3: recipe for target 'deploy' failed
make: *** [deploy] Error 1
Run Code Online (Sandbox Code Playgroud)
...强制您查找Makefile,而...
test -n "" # $ENV
Makefile:3: recipe for target 'deploy' failed
make: *** [deploy] Error 1
Run Code Online (Sandbox Code Playgroud)
......直接解释了什么是错的
全局变体(完整性,但没有问)
在Makefile之上,您还可以编写:
ifeq ($(ENV),)
$(error ENV is not set)
endif
Run Code Online (Sandbox Code Playgroud)
警告:
clean如果未设置ENV,即使目标也会失败.否则看Hudon的答案更复杂我知道这很旧,但我想我会为未来的访客提供我自己的体验,因为恕我直言,它更整洁一些。
通常,make将sh用作其默认 shell(通过特殊SHELL变量设置)。在sh及其衍生物中,如果通过执行以下操作检索环境变量未设置或为空,则退出并显示错误消息是微不足道的:${VAR?Variable VAR was not set or null}。
扩展这一点,我们可以编写一个可重用的 make 目标,如果未设置环境变量,它可用于使其他目标失败:
.check-env-vars:
@test $${ENV?Please set environment variable ENV}
deploy: .check-env-vars
rsync . $(ENV).example.com:/var/www/myapp/
hello:
echo "I don't care about ENV, just saying hello!"
Run Code Online (Sandbox Code Playgroud)
注意事项:
$$) 将扩展推迟到 shell 而不是内部maketest只是为了防止 shell 尝试执行其中的内容VAR(它没有其他重要目的).check-env-vars可以简单地扩展以检查更多环境变量,每个环境变量只添加一行(例如@test $${NEWENV?Please set environment variable NEWENV})您可以使用ifdef不同的目标来代替。
.PHONY: deploy
deploy:
ifdef ENV
rsync . $(ENV).example.com:/var/www/myapp/
else
@echo 1>&2 "ENV must be set"
false # Cause deploy to fail
endif
Run Code Online (Sandbox Code Playgroud)
我看到命令本身需要ENV变量,所以你可以在命令本身中检查它:
.PHONY: deploy check-env
deploy: check-env
rsync . $(ENV).example.com:/var/www/myapp/
check-env:
if test "$(ENV)" = "" ; then \
echo "ENV not set"; \
exit 1; \
fi
Run Code Online (Sandbox Code Playgroud)
到目前为止,给定答案的一个可能问题是未定义make中的依赖顺序。例如,运行:
make -j target
Run Code Online (Sandbox Code Playgroud)
什么时候target有一些依赖关系并不能保证它们将以任何给定的顺序运行。
解决此问题的方法(以确保在选择配方之前将对ENV进行检查)是在任何配方之外的make首次通过期间检查ENV:
## Are any of the user's goals dependent on ENV?
ifneq ($(filter deploy other-thing-that-needs-ENV,$(MAKECMDGOALS)),$())
ifndef ENV
$(error ENV not defined)
endif
endif
.PHONY: deploy
deploy: foo bar
...
other-thing-that-needs-ENV: bar baz bono
...
Run Code Online (Sandbox Code Playgroud)
您可以了解此处使用的不同函数/变量,$()这只是一种明确声明我们要与“无”进行比较的方法。
小智 5
我发现最好的答案不能用作要求,除了其他PHONY目标。如果用作实际文件目标的依赖项,则使用check-env将强制重建该文件目标。
其他答案是全局的(例如,对于Makefile中的所有目标都是必需的变量)或使用外壳程序,例如,如果缺少ENV,make将终止于目标。
我发现这两个问题的解决方案是
ndef = $(if $(value $(1)),,$(error $(1) not set))
.PHONY: deploy
deploy:
$(call ndef,ENV)
echo "deploying $(ENV)"
.PHONY: build
build:
echo "building"
Run Code Online (Sandbox Code Playgroud)
输出看起来像
$ make build
echo "building"
building
$ make deploy
Makefile:5: *** ENV not set. Stop.
$ make deploy ENV="env"
echo "deploying env"
deploying env
$
Run Code Online (Sandbox Code Playgroud)
value 有一些可怕的警告,但是对于这种简单的用法,我相信它是最佳选择。
| 归档时间: |
|
| 查看次数: |
65986 次 |
| 最近记录: |