Makefilevariables作为先决条件
在Makefile中, deploy
配方需要设置一个环境variablesENV
来正确执行自己,而另一些则不关心,例如:
ENV = .PHONY: deploy hello deploy: rsync . $(ENV).example.com:/var/www/myapp/ hello: echo "I don't care about ENV, just saying hello!"
我怎样才能确保这个variables设置,例如:是否有一种方法来声明这个makefilevariables作为部署配方的先决条件,如:
deploy: make-sure-ENV-variable-is-set
?
谢谢。
这会导致一个致命的错误,如果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之前生效 。)
你可以创build一个隐式的守护目标,检查这个目录中的variables是否被定义,如下所示:
guard-%: @ if [ "${${*}}" = "" ]; then \ echo "Environment variable $* not set"; \ exit 1; \ fi
然后,您可以在任何想要声明variables已定义的位置添加guard-ENVVAR目标,如下所示:
change-hostname: guard-HOSTNAME ./changeHostname.sh ${HOSTNAME}
如果您调用“make change-hostname”,而不是在调用中添加HOSTNAME = somehostname,那么您将得到一个错误,构build将失败。
内联变体
在我的makefile中,我通常使用如下的expression式:
deploy: test -n "$(ENV)" # $$ENV rsync . $(ENV).example.com:/var/www/myapp/
原因:
- 这是一个简单的一行
- 它紧凑
- 它靠近使用variables的命令
不要忘记对debugging非常重要的注释:
test -n "" Makefile:3: recipe for target 'deploy' failed make: *** [deploy] Error 1
…迫使你查找Makefile,而…
test -n "" # $ENV Makefile:3: recipe for target 'deploy' failed make: *** [deploy] Error 1
…直接解释了什么是错的
全球变体 (完整性,但没有问)
在你的Makefile的顶部,你也可以写:
ifeq ($(ENV),) $(error ENV is not set) endif
警告:
- 不要使用该块中的选项卡
- 小心使用:即使没有设置ENV,
clean
目标也会失败。 否则,请参阅Hudon的更复杂的答案
正如我看到的命令本身需要ENVvariables,所以你可以检查它在命令本身:
.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
到目前为止给出的答案的一个可能的问题是make中的依赖顺序没有被定义。 例如,运行:
make -j target
当target
有一些依赖不能保证这些将以任何给定的顺序运行。
这个解决scheme(保证在select食谱之前检查ENV)是在制作第一遍的时候检查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 ...
你可以阅读这里使用的不同的函数/variables,而$()
只是明确指出我们正在比较“无”的一种方式。
你可以使用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