我有一堆 shell 脚本和 Makefile,它们以各种有趣的方式相互调用。对于整个项目,需要构建一个东西,并且一些(不是全部)脚本和 Makefile 目标需要构建这个东西。任何脚本或 Makefile 目标都不会更改正在构建的内容,因此我只想每个 shell 脚本/Makefile 调用构建一次。我通过在调用子 shell 脚本/Makefile 之一之前构建事物时设置环境变量 DO_NOT_BUILD 来部分完成此操作。所以,我想在需要构建并且未设置 DO_NOT_BUILD 时构建该东西,然后让所有孩子知道不要重建,因此应该在构建后设置 DO_NOT_BUILD 。这在 shell 脚本中很容易做到,但我发现用 Makefile 很难做到。这是我的玩具 Makefile:
PARENT_DO_NOT_BUILD := $(DO_NOT_BUILD)
export DO_NOT_BUILD
.PHONY: build
build: DO_NOT_BUILD := true
build:
if [ -z "$(PARENT_DO_NOT_BUILD)" ]; then echo "Building now"; fi
.PHONY: do_thing_with_build
do_thing_with_build: build
echo "DO_NOT_BUILD=$${DO_NOT_BUILD}"
.PHONY: do_thing_without_build
do_thing_without_build:
echo "DO_NOT_BUILD=$${DO_NOT_BUILD}"
我想要的行为是(省略回显命令):
$ make do_thing_without_build
DO_NOT_BUILD=
$ make do_thing_with_build
Building now
DO_NOT_BUILD=true
$ export DO_NOT_BUILD=true && make do_thing_without_build
DO_NOT_BUILD=true
$ export DO_NOT_BUILD=true && make do_thing_with_build
DO_NOT_BUILD=true
相反,
make do_thing_with_build
有一个空的$DO_NOT_BUILD
环境变量,因为设置DO_NOT_BUILD := true
仅适用于build
目标,而不适用于do_thing_with_build
目标。
如果调用目标,如何在向子操作提供更新的环境变量时根据提供的环境变量来调节
build
目标中采取的操作?或者,当调用 build
目标时,如何更新 DO_NOT_BUILD?或者说真的,我怎样才能产生上面我想要的行为?
我有一堆 shell 脚本和 Makefile,它们以各种有趣的方式相互调用。 [...]
这听起来很可怕。
make
不要被误认为是脚本工具。人们试图以这种方式使用它,从而给自己制造了各种各样的麻烦,而其中的一个大陷阱是,如果你足够努力地破解它,那么你通常可以让它发挥作用。结果通常表现出不平凡的肮脏程度。
如果只需要构建一个工件,那么就不需要多个 makefile。此外,如果一个工件声明了适当的先决条件,那么
make
会自然地处理您的一次性构建问题。当工件已经满足其先决条件时,再次make
将不会导致其配方被执行。系统中的各种脚本可以各自make the_thing
(如果它们要求它是最新的),并确信只有在它过时时才会构建它。
我不明白为什么你的特定示例代表了你想要做的事情,但实现你指定的结果的一种方法是简单地移动特定于目标的变量的定义:
PARENT_DO_NOT_BUILD := $(DO_NOT_BUILD)
export DO_NOT_BUILD
.PHONY: build
build:
if [ -z "$(PARENT_DO_NOT_BUILD)" ]; then echo "Building now"; fi
.PHONY: do_thing_with_build
do_thing_with_build: DO_NOT_BUILD := true
do_thing_with_build: build
echo "DO_NOT_BUILD=$${DO_NOT_BUILD}"
.PHONY: do_thing_without_build
do_thing_without_build:
echo "DO_NOT_BUILD=$${DO_NOT_BUILD}"