从Bash脚本中读取Makefile变量

5

我有一个makefile,在其中我试图设置一些变量,这些变量已经存在于我编写的bash脚本set-vars.sh中(它只包含变量名和值)。

我在其他几个bash脚本中使用这些变量。我还需要能够在我的makefile中使用它们。

经过大量研究和尝试,我找到了一种可行的方法,可以从bash脚本中设置makefile中的变量,具体如下:

set-vars.sh

# set vars
foo=FOO1
bar=BAR1
baz=BAZ1

# if a command line arg is given (e.g. foo) 
# echo value command line arg (e.g. echo $foo)

if ! [ -z ${1+x} ]; then echo ${!1}; fi

这里的奥妙在于最后一行,它通过输出一个命令行参数给定的变量名的值(如果有命令行参数的话)。我会在makefile中调用这个脚本,提供变量名并使用输出的值来设置makefile变量。
.PHONY:  target1 target2 target3

export foo = $(shell sh set-vars.sh foo)

target1:
    @echo $(foo)

# ... other targets which reference $(foo) ...

这样做可以实现,但可能是一种比较“hacky”的方式。我想知道是否有更简单、优雅的方法来实现我的需求。

我在StackOverflow上遇到了几个类似的问题和答案,但没有找到与我的示例相匹配的内容。如果已经有我错过的答案,请指引我。

非常感谢!


你不能在调用make的shell中设置变量,也不能将它们放在make命令行上吗? - Barmar
其他脚本需要那个 if ! [ -z... 行吗? - Beta
@Barmar,我不能在make命令行上放置它们,因为其他人可能不熟悉这个makefile的内部工作方式,而这个makefile将被其他人使用。我希望调用makefile尽可能简单...但你所说的在调用make的shell中设置变量是什么意思?对不起,我不太精通shell脚本。 - tamjd1
@Beta,这行代码是专门为了makefile添加的,以便我可以在makefile中设置变量,使用从bash脚本中echo出的值。 - tamjd1
3个回答

8
你可以在一个文件中定义变量,该文件可以从你的shell脚本中引用,并从你的Makefile中包含:

您可以在文件中定义变量,该文件可从您的shell脚本中源代码,并从您的Makefile中包含:

$ cat vardef.txt
foo=FOO1
bar=BAR1
baz=BAZ1
$ cat set-vars.sh
source ./vardef.txt
echo "$foo $bar $baz"
$ sh ./set-vars.sh
FOO1 BAR1 BAZ1
$ cat Makefile
include vardef.txt
all:
    @echo "$(foo) $(bar) $(baz)"
$ make
FOO1 BAR1 BAZ1

当两种语言部分使用相同的语法时,这不是很棒吗?

这段话涉及到IT技术相关内容。

这看起来很有前途... 我会试一试。谢谢! - tamjd1
尝试了一下。在Makefile中工作得很好,但是在Shell脚本中并不完美。出现了这个问题:subtest.sh: line 3: source: vars.txt: file not found - tamjd1
你尝试过 source ./vars.txt 或者 source vars.txt 吗? - Renaud Pacalet

1

不确定是否更加简便,但您可以“创建”一个文件,并将其包含到Makefile中。在运行时完成。像这样:

$(shell grep '=' vars.sh > /tmp/vars.tmp)
include /tmp/vars.tmp
$(shell rm /tmp/vars.tmp)

将第一行替换为更合理的内容。

1
通常认为,构建系统依赖于环境变量是不好的实践,因为如果这样做,输出不仅取决于命令行,还取决于环境变量的状态,这样就会出现可重复性问题。
在提醒您之后,所有环境变量都可以在make中访问,例如:
user := ${USER} # ${USER} comes from the environment.
all :
    @echo ${user}

换句话说,编写一个脚本来设置环境变量并调用make:
#!/bin/bash
export foo=FOO1
export bar=BAR1
export baz=BAZ1
exec make "$@"

另外,您可以使用只包含export foo=FOO1语句的shell脚本。这实际上是有效的makefile语法,因此您可以在Makefile中执行include set-vars.sh


这个方法可以行得通,但我需要能够从命令行运行make,而不是从脚本中运行。我需要让make在幕后获取所有正确的变量和值。从而创建一个抽象层,用户除了运行make install或者其他他们想要运行的目标之外,无需知道Makefile内部的内容。 - tamjd1
@tamjd1 为您提供了一种备选解决方案。 - Maxim Egorushkin
刚注意到@RenaudPacalet最初提出了这个建议。 - Maxim Egorushkin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接