如何防止 make 将任何变量传递给子 make?

问题描述 投票:0回答:2

我无法阻止

make
将任何变量传递给子制作。我已阅读手册并遵循了他们的建议(重置
MAKEOVERRIDES
MAKEFLAGS
),但它仍然不起作用,我认为应该如此。

考虑以下原型 Makefile:

${warning $(MAKEOVERRIDES)}
${warning $(MAKEFLAGS)}
${warning $(VAR)}

none:
    $(MAKE) -f Makefile MAKEOVERRIDES= MAKEFLAGS= all

all:
    echo done!

如果我

make VAR=10 none
,我会得到以下信息:

Makefile:2: VAR=10
Makefile:3: 
Makefile:4: 10
make -f Makefile MAKEOVERRIDES= MAKEFLAGS= all
make[1]: Entering directory `/home/adriano/sandbox/makes'
Makefile:2: 
Makefile:3: 
Makefile:4: 10
echo done!
done!
make[1]: Leaving directory `/home/adriano/sandbox/makes'

意味着

make
是与子品牌的沟通
VAR
。这是正确的行为吗?

我尝试过

unexport VAR
bash -c make ...
但没有任何运气。

编辑:我已将

none
的食谱修改为:
bash -c "echo $$MAKEOVERRIDES $$MAKEFLAGS $$VAR" ; make ...

这样我发现VAR实际上是通过make为要执行的命令创建的环境传递的,而不是通过其他变量传递的(其他变量也是通过这种方式传递给make的)。

我想我现在的问题是:如何创建一个新的 shell/环境来运行我的子 make?

编辑:有人问我为什么要这样做;我会尝试在这里回答这个问题。

我有一个“模块”,它使用名为 CONFIG 的变量。为了构建这个模块,我需要构建另一个部分不相关的“模块”,它也使用 CONFIG,但具有不同的值。问题是,当我尝试构建“子模块”时,CONFIG 包含“超级模块”的值。我可以在制作“子模块”时指定 CONFIG,但是两个模块都使用许多具有相同名称的变量,并且尝试全部指定它们将使模块紧密耦合,这是我无法承受的。

这怎么这么难...

shell makefile
2个回答
5
投票

这是错误的:

none:
        $(MAKE) -f Makefile MAKEOVERRIDES= MAKEFLAGS= all

这些变量(

MAKEOVERRIDES
MAKEFLAGS
)由父 make 在 environment 中设置,并传递给子 make。在配方中设置这些值的覆盖不会有帮助,因为 make 必须在实际启动配方中的命令之前设置配方的环境(当然)。

您必须在父 makefile 中覆盖/删除这些值,以便父 make 在构建子 make 的环境之前可以看到这些更改:

MAKEOVERRIDES = none: $(MAKE) -f Makefile all

没有完美的方法可以做到这一点。不过,你可以玩一个在大多数情况下都有效的技巧:

unexport $(shell echo '$(MAKEOVERRIDES)' | sed 's/=[^ ]*//g') MAKEOVERRIDES =

第一行尝试取消导出

MAKEOVERRIDES

 中的所有变量,第二行重置 MAKEOVERRIDES。这有一些问题。一是如果 MAKEOVERRIDES 为空,它将自行使用“unexport”,从而取消导出所有内容。通过在 shell 函数之前添加一些虚假变量,可以轻松解决这个问题。另一个是,如果任何变量的值包含空格,扩展将认为它是一个未导出的变量。这可能没问题,但很奇怪。

我想不出更好的方法了。

你并没有真正说出

为什么你想这样做。您是否考虑过做一些不同的事情,例如使用 env

 运行您想要拥有“普通”环境的命令;例如,如果您想使用一组有限且特定的环境变量运行命令,您可以运行:

test: env -i PATH='$(PATH)' LANG='$(LANG)' runMyCommand --with --my arguments

不幸的是,某些版本的

env

 使用 
-
 而不是 
-i
;检查你的手册页。

或者,您可以尝试启动登录 shell,它将从头开始重新读取用户的 shell 设置环境:

test: /bin/sh -lc 'runMyCommand --with --my arguments'

编辑:这很困难,因为你要求做的事情(限制子品牌的环境)很棘手。

幸运的是,根据您的描述,这似乎没有必要。 Make 对于查找变量值具有重要性层次结构。命令行是最高级别的(好吧,有

override

,但我们会忽略它)。之后是 makefile 本身中设置的变量。最后也是最低的是从环境中导入的变量(默认变量甚至更低,但我们也会忽略它)。

因此,如果您的目标是让子品牌中的变量不受提供给上层品牌的命令行变量的影响,那么所有这些从环境中获取变量的繁琐工作都是不必要的。子 makefile 中设置的变量将优先于环境中的值。因此,您所要做的就是通过设置 MAKEOVERRIDES 来摆脱在命令行上设置的变量,我已经在上面展示了如何执行此操作。


0
投票
不知道它是否适合您的情况,但我发现了非常优雅的方法,不通过 MAKEFLAGS 将参数从 CLI 传递到子 make,而仅通过 env,使它们不会覆盖子 make 中定义的变量:

生成文件:

override MAKEFLAGS=$(MFLAGS) -- .PHONY: all all: @echo MAKEFLAGS=$(MAKEFLAGS) @echo PARAM_1=$(PARAM_1) @echo PARAM_2=$(PARAM_2) $(MAKE) -f child.mk PARAM_3=parent_cli
child.mk:

PARAM_1:=child .PHONY: all all: @echo MAKEFLAGS=$(MAKEFLAGS) @echo PARAM_1=$(PARAM_1) @echo PARAM_2=$(PARAM_2) @echo PARAM_3=$(PARAM_3)
执行:

$ make --no-print-directory -j3 PARAM_1=cli PARAM_2=cli MAKEFLAGS=-j3 --jobserver-auth=3,4 --no-print-directory -- PARAM_1=cli PARAM_2=cli make -f child.mk PARAM_3=parent_cli MAKEFLAGS= -j3 --jobserver-auth=3,4 --no-print-directory -- PARAM_3=parent_cli PARAM_1=child PARAM_2=cli PARAM_3=parent_cli
使用注释掉的覆盖执行:

MAKEFLAGS= -j3 --jobserver-auth=3,4 --no-print-directory -- PARAM_2=cli PARAM_1=cli PARAM_1=cli PARAM_2=cli make -f child.mk PARAM_3=parent_cli MAKEFLAGS= -j3 --jobserver-auth=3,4 --no-print-directory -- PARAM_3=parent_cli PARAM_1=cli PARAM_2=cli PARAM_1=cli PARAM_2=cli PARAM_3=parent_cli
这样,所有特定于 make 的选项(如 -j )仍会传递给子 make,但仅用于父 makefile 的选项不会导致与子 makefile 发生冲突。如果子 makefile 是您无法控制的第 3 方 makefile,这可能会很有用。

© www.soinside.com 2019 - 2024. All rights reserved.