Makefile 和 Bash script 在使用的过程中有很多奇奇怪怪的坑,本文做一下纪录。
首先,有两个文件,一个叫 envs,里面定义了一个环境变量,比如
$ cat envs
export GOPROXY="test.local"
第二个文件就是 Makefile ,假如我这样写
test:
source ./envs
echo ${GOPROXY}
所以,总的目标是,我希望在 Makefile 中导入另一个文件中事先定义好的环境变量。 然而这样的写法有很多问题。
source 命令找不到
加入直接运行 make, 很有可能你会看到这样的错误
$ make
source ./envs
make: source: Command not found
可是在 terminal 里面明明可以用 source 命令啊? 于是,第一个坑出现:
source is a (non-POSIX) shell builtin, not an executable program on any conventional UNIX-like system. If source is changed to ., make changes its strategy; instead of trying to find and execute a program, it just passes the rule body to the system shell.
更加具体的原因在这篇文章中已经说了。
通过这个错可以学到什么呢?
- 保险的做法是在 Makefile 中指定
SHELL := /bin/bash
- 学习了用 strace 命令查看系统调用
$ strace -f -s65535 -- make | grep source
[pid 104517] execve("/usr/local/go/bin/source", ["source", "./envs"], 0x559253194a40 /* 31 vars */) = -1 ENOENT (No such file or directory)
[pid 104517] execve("/usr/local/sbin/source", ["source", "./envs"], 0x559253194a40 /* 31 vars */) = -1 ENOENT (No such file or directory)
[pid 104517] execve("/usr/local/bin/source", ["source", "./envs"], 0x559253194a40 /* 31 vars */) = -1 ENOENT (No such file or directory)
变量没有赋值
接下来把 Makefile 改成这样
SHELL := /bin/bash
test:
source ./envs
echo ${GOPROXY}
可是结果依然不对,GOPROXY 的值并没有被 echo 出来
$ make
source ./envs
echo
查了一番资料以后,发现了参考资料 2 中的解释
Each line of a make recipe is executed by a separate shell, so even if you source the file, the shell that sources it exits before the next line is evaluated.
也就是说,我的 Makefile 把 source 和 echo 写成了两行,就相当于
bash -c 'source .envs'
bash -c 'echo ${GOPROXY}'
Makefile 变量 和 Shell 变量
经过上面的错误,我把 Madefile 改成了下面这样,这下总对了吧?
SHELL := /bin/bash
test:
source ./envs && echo ${GOPROXY}
结果还是不对
$ make
source ./envs && echo
为什么呢? 又经过一番搜索,发现了参考资料 3 的解释:
在 Makefile 中使用变量的值得时候,分为 makefile 的变量和 shell 变量
- makefile variable, use a single dollar sign
- shell variable, use two dollar signs
所以,最后写成这样才对
SHELL := /bin/bash
test:
source ./envs && echo $${GOPROXY}
总结
搞得这么复杂,罪魁祸首就是把环境变量放在了单独的文件中,其实直接在 Makefile 开头 export 环境变量就没有这么多麻烦了。