源shell脚本进入makefile

时间:2014-08-07 06:25:44

标签: bash shell makefile environment-variables

我有一个bash shell脚本,我通常会将其输入shell,并定义了许多环境变量,这些变量是导出的。我不想:

  1. 导出变量,因为这会导致可导出的环境太大,最终导致整个系统变慢(必须在从shell运行每个命令时导出)
  2. 在makefile(DRY)中重新定义这些变量
  3. 我想将相同的shell脚本源于makefile的环境,以便我可以访问这些变量。这可能吗?我怎样才能做到这一点?理想情况下,我会在makefile中执行:

    source setup-env.sh
    

    makefile没有source命令,但也许等同于什么?我可以使用任何特殊的黑客来模拟相同的效果吗?

1 个答案:

答案 0 :(得分:6)

根据additional question in the comment,这是一种有效地将整个环境标记为已导出的方法:

for var in $(compgen -v); do export $var; done
根据{{​​3}},

compgen -v只输出所有变量名称。然后我们简单地遍历此列表并export每个列表。

归功于bash manual, section 8.7 Programmable Completion Builtins - compgen对我而言是新的。


我可以通过两种方式将其整合到您的制作工作流程中:

- Shell脚本包装器

只需编写一个shell脚本来源您的setup-env.sh,导出所有变量,然后调用make本身。类似的东西:

#!/bin/bash

./source setup-env.sh
for var in $(compgen -v); do export $var; done
make $@

- 递归制作

可能您不想要shell脚本包装器,并且想要出于任何原因直接调用make。您可以在一个Makefile中执行此操作,该文件以递归方式调用自身:

$(info MAKELEVEL=$(MAKELEVEL) myvar=$(myvar))
ifeq ($(MAKELEVEL), 0)
all:
    bash -c "source ./setup-env.sh; \
    for var in \$$(compgen -v); do export \$$var; done; \
    $(MAKE) $@"
else
all: myprog

myprog:
    echo "Recipe for myprog.  myvar=$(myvar)"
endif

此Makefile的输出为:

$ make
MAKELEVEL=0 myvar=
bash -c "source ./setup-env.sh; \
    for var in \$(compgen -v); do export \$var; done; \
    make all"
MAKELEVEL=1 myvar=Hello World
make[1]: Entering directory `/home/ubuntu/makesource'
echo "Recipe for myprog.  myvar=Hello World"
Recipe for myprog.  myvar=Hello World
make[1]: Leaving directory `/home/ubuntu/makesource'
$ 

我们检查GNU Make内置变量MAKELEVEL以查看我们所处的递归级别。如果级别为0,那么我们递归调用所有目标的make,但首先源./setup-env.sh并导出所有变量。如果递归级别是其他任何东西,我们只是做普通的makefile,但是你看到你需要的变量现在可用了。这由Makefile顶部的$(info )行突出显示,该行显示递归级别和myvar的值(或不是)。

注意:

  • 我们必须使用bash -c,因为compgen严格来说是内置的bash,并且在Posix模式下不可用 - 即默认情况下make调用shell为sh -c。 / p>

  • 第一个$食谱中的all:需要非常谨慎地转义。 $$使$无法通过make进行展开,而\$$使$无法通过隐式sh

    扩展{{1}}
  • 有很多文献认为"递归制作被认为是有害的"。例如。 https://stackoverflow.com/a/16337687/2113226