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

qhhrdooz  于 2023-10-23  发布在  Shell
关注(0)|答案(2)|浏览(134)

我无法阻止make将任何变量传递给submake。我已经阅读了手册,并遵循了他们的建议(重置MAKEOVERRIDESMAKEFLAGS),但它仍然没有工作,我认为它应该。
考虑以下原型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'

这意味着makeVAR到子品牌的通信。这是正确的行为吗?
我试过unexport VARbash -c make ...没有任何运气。
编辑:我修改了none的配方:bash -c "echo $$MAKEOVERRIDES $$MAKEFLAGS $$VAR" ; make ...
通过这种方式,我发现VAR实际上是通过make为要执行的命令创建的环境传递的,而不是通过其他变量(其他变量也以这种方式传递给make)。
我想我现在的问题是:我如何创建一个新shell/环境来运行我的sub make?
编辑:有人问我为什么要这样做;我会在这里尝试回答这个问题。
我有一个“模块”,它使用一个名为CONFIG的变量。为了构建这个模块,我需要构建另一个部分不相关的“模块”,它也使用CONFIG,但具有不同的值。问题是,当我试图构建“子模块”时,CONFIG包含“超级模块”的值。我可以在创建“子模块”时指定CONFIG,但两个模块使用许多同名变量,试图指定它们将使模块紧密耦合,这是我无法承受的。
怎么会这么难...

d8tt03nd

d8tt03nd1#

这是错误的:

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

这些变量(MAKEOVERRIDESMAKEFLAGS)由父make在 environment 中设置,并传递给子make。在recipe中设置这些值的覆盖没有帮助,因为make必须在实际启动recipe中的命令之前设置recipe的环境(当然)。
你必须覆盖/删除父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本身中设置的变量。最后也是最低的是从环境中导入的变量(默认变量甚至更低,但我们也忽略它)。
因此,如果您的目标是允许子make中的变量不受提供给上层make的命令行变量的影响,那么所有这些从环境中获取变量的繁琐程序都是不必要的。子makefile中设置的变量将优先于环境中的值。因此,您所要做的就是通过设置MAKEOVERRIDES来删除命令行上设置的变量,我已经在上面展示了如何做到这一点。

t98cgbkg

t98cgbkg2#

不知道它是否适合你的情况,但我发现了一种非常优雅的方法,不通过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)仍然传递给sub-make,但仅用于父makefile的选项不会导致与子makefile冲突。如果子生成文件是你无法控制的第三方生成文件,这可能很有用。

相关问题