shell 如何从目标更新make变量?

wvyml7n5  于 2023-10-23  发布在  Shell
关注(0)|答案(1)|浏览(138)

我有一堆shell脚本和Makefile,它们以各种有趣的方式相互调用。对于整个项目,有一件事要构建,一些(不是全部)脚本和Makefile目标需要构建这件事。脚本或Makefile目标都不会改变正在构建的东西的任何内容,所以我希望每个shell脚本/Makefile调用只构建一次。在调用子shell脚本/Makefiles之前,我通过在构建东西时设置环境变量DO_NOT_BUILD来部分实现这一点。所以,我想在需要构建的时候构建这个东西,而DO_NOT_BUILD没有设置,然后让所有的孩子都知道不要重建,所以在构建之后应该设置DO_NOT_BUILD。这在shell脚本中很容易做到,但我发现用Makefiles很难做到。这是我的玩具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?或者说,我如何才能产生我想要的行为?

k4emjkb1

k4emjkb11#

我有一堆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}"

我在此重申我对这个问题的看法:

  • 没有进程可以操纵其父进程(或更远的祖先进程)的环境。特别是,在makefile中放入的任何内容都不会改变运行make的shell中DO_NOT_BUILD的值。
  • 特定于目标的变量的作用域为定义它们的目标及其先决条件。它们在其他目标的背景下是不可见的。

相关问题