makefile中SHELL变量的设置

原创 2016年08月31日 14:52:45

备注:如果只关心shell问题和解决的办法,请直接阅读第2节和第5节。

1. 问题的由来

这是以前遇到的一个问题,最近调试makefile想起来了,总结一下。
当时编译一个公司早期发布的linux代码,但在我Ubuntu 14.04上编译的时候却出现了一个错误:

cp -f defconfigs/defconfig-brcm-uclinux-rootfs-7400d0_be .config
rm -f linux-2.6.x/.config
(. .config; \
        echo "cp -f vendors///config.linux-2.6.x /.config;"; \
                cp -f vendors///config.linux-2.6.x /.config; \
        )
/bin/sh: line 0: .: .config: file not found
make[2]: *** [vmlinuz-initrd-7400d0_be] Error 1

可以肯定的是这个代码包在正式发布的时候一定是可以编译的,所以我相信这是一个环境相关的问题,从错误信息看,实际上是用“.”去执行一个shell脚本时报错。

2. 问题的复现

经简化,可以用一个简单的make工程来复现这个问题:

.PHONY: all clean

all: hello.sh
    . hello.sh

clean:
    rm -rf hello.sh

hello.sh:
    @echo "#!/bin/bash" > hello.sh
    @echo "" >> hello.sh
    @echo "echo 'hello'" >> hello.sh

在这个makefile中先生成一个hello.sh的脚本(脚本只是简单回显一个“hello”字符串),然后再运行命令“. hello.sh”命令执行脚本,错误信息如下:

ygu@fs-ygu:/opt/work/make-example$ make
. hello.sh
/bin/sh: line 0: .: hello.sh: file not found
make: *** [all] Error 1

3. 几个关于错误的实验

在Ubuntu命令行用“. hello.sh”单独执行是可以的:

ygu@fs-ygu:/opt/work/make-example$ . hello.sh
hello

a. 用“source”命令执行shell脚本

如果将“. hello.sh”修改为“source hello.sh”:

.PHONY: all clean

all: hello.sh
    source hello.sh

clean:
    rm -rf hello.sh

hello.sh:
    @echo "#!/bin/bash" > hello.sh
    @echo "" >> hello.sh
    @echo "echo 'hello'" >> hello.sh

make时会报错:

ygu@fs-ygu:/opt/work/make-example$ make
source hello.sh
make: source: Command not found
make: *** [all] Error 127

b. 直接执行shell脚本

i. 直接执行脚本

如果将“. hello.sh”修改为“./hello.sh”:

.PHONY: all clean

all: hello.sh
    ./hello.sh

clean:
    rm -rf hello.sh

hello.sh:
    @echo "#!/bin/bash" > hello.sh
    @echo "" >> hello.sh
    @echo "echo 'hello'" >> hello.sh

则make时报另外一个错误:

gu@fs-ygu:/opt/work/make-example$ make
./hello.sh
make: execvp: ./hello.sh: Permission denied
make: *** [all] Error 127

ii. 给脚本增加可执行权限

进一步修改,让hello.sh具有可执行权限:

.PHONY: all clean

all: hello.sh
    chmod a+x hello.sh
    ./hello.sh

clean:
    rm -rf hello.sh

hello.sh:
    @echo "#!/bin/bash" > hello.sh
    @echo "" >> hello.sh
    @echo "echo 'hello'" >> hello.sh

则可以正确运行:

ygu@fs-ygu:/opt/work/make-example$ make
chmod a+x hello.sh
./hello.sh
hello

c. makefile中SHELL的检查

当前我的Ubuntu上默认执行的shell是/bin/bash,但makefile执行提示的是/bin/sh,可以在makefile中检查SHELL的环境变量和当前makefile中的设定:

.PHONY: all clean

all: hello.sh
    @echo 'Linux SHELL='$$SHELL
    @echo ' Make SHELL='$(SHELL)
    . hello.sh

clean:
    rm -rf hello.sh

hello.sh:
    @echo "#!/bin/bash" > hello.sh
    @echo "" >> hello.sh
    @echo "echo 'hello'" >> hello.sh

执行结果:

ygu@fs-ygu:/opt/work/make-example$ make
Linux SHELL=/bin/bash
 Make SHELL=/bin/sh
. hello.sh
/bin/sh: line 0: .: hello.sh: file not found
make: *** [all] Error 1

从打印输出的信息看,系统环境变量SHELL为/bin/bash,而makefile的变量SHELL确实为/bin/sh

d. 实验结论

以上实验说明脚本本身是没有问题的,问题就在命令“. hello.sh”上。

4. make手册的说明

查阅make手册:https://www.gnu.org/software/make/manual/make.html
其中关于shell的设置,其中5.3.2节有如下描述:

5.3.2 Choosing the Shell

The program used as the shell is taken from the variable SHELL. If this variable is not set in your makefile, the program /bin/sh is used as the shell. The argument(s) passed to the shell are taken from the variable .SHELLFLAGS. The default value of .SHELLFLAGS is -c normally, or -ec in POSIX-conforming mode.

Unlike most variables, the variable SHELL is never set from the environment. This is because the SHELL environment variable is used to specify your personal choice of shell program for interactive use. It would be very bad for personal choices like this to affect the functioning of makefiles.

大意是说make使用SHELL变量来指定执行shell命令的程序,如果makefile中没有设置SHELL变量,则默认使用/bin/sh。但是跟其他大多数变量不一样的是SHELL变量并不从系统环境变量中继承,这是因为系统环境变量“SHELL”用于指定哪个程序被用来作为用户和系统交互的接口程序,他对于不存在交互过程的makefile是不合适的。

5. makefile中设置SHELL

通过在makefile中设置SHELL=/bin/bash,问题得到了解决:

SHELL=/bin/bash

.PHONY: all clean

all: hello.sh
    . hello.sh

clean:
    rm -rf hello.sh

hello.sh:
    @echo "#!/bin/bash" > hello.sh
    @echo "" >> hello.sh
    @echo "echo 'hello'" >> hello.sh

makefile的执行:

ygu@fs-ygu:/opt/work/make-example$ make
. hello.sh
hello

执行的结果跟预期一致,问题得到了解决。

6. 关于/bin/sh和/bin/bash的疑问

现在还有一个问题是,在我当前Ubuntu 14.04的机器上,/bin/sh是软链接到/bin/bash的,如下:

ygu@fs-ygu:/opt/work/make-example$ ls -l /bin
-rwxr-xr-x 1 root root 1021112 Oct  8  2014 bash
lrwxrwxrwx 1 root root       4 Aug 14  2014 sh -> bash

为什么/bin/bash可以正确执行而/bin/sh却不能呢?

这就涉及到/bin/sh和/bin/bash的区别了,这里有一篇文章谈到了这个问题:
《/bin/bash和/bin/sh的区别》: http://www.cnblogs.com/baizhantang/archive/2012/09/11/2680453.html

大体而言,现在的linux中sh一般设置为bash的软链接,使用sh调用执行脚本相当于打开了bash的POSIX标准模式,也就是说 /bin/sh 相当于 /bin/bash –posix
我们可以修改makefile来验证一下:

SHELL=/bin/bash --posix
#SHELL=/bin/bash

.PHONY: all clean

all: hello.sh
        . hello.sh

clean:
        rm -rf hello.sh

hello.sh:
        @echo "#!/bin/bash" > hello.sh
        @echo "" >> hello.sh
        @echo "echo 'hello'" >> hello.sh

make时会报错:

ygu@fs-ygu:/opt/work/make-example$ make
. hello.sh
/bin/bash: line 0: .: hello.sh: file not found
make: *** [all] Error 1

这个错误跟默认SHELL为/bin/sh的错误一样。

7. 结语

  • 以前在很多makefile中也看到过对SHELL的设置,但是没看到哪里有引用,不清楚为什么要设置SHELL;
  • 以前在很多make工程中没有设置SHELL执行起来也好像没有问题,所以一直也没有发现SHELL问题;
    建议:当执行makefile中的shell命令不成功时,先检查下SHELL变量的设置。
版权声明:本文为guyongqiangx原创,欢迎评论留言和转载收藏,转载请注明出处:http://blog.csdn.net/guyongqiangx

Linux下srand随机函数关于时间种子的精度提升

最近工作的时候遇见了一个问题,是关于随机函数的问题。网上有很多关于随机函数的例子,这点就不做说明。 说一下我今天遇见的问题,我在服务器端写了一个随机函数,使用的是time(0)作为随机种子。在我自己...

跟我一起写Makefile(9)--- 书写命令(显示命令+命令执行+命令出错+嵌套执行make+定义命令包)

书写命令 ———— 每条规则中的命令和操作系统Shell的命令行是一致的。make会一按顺序一条一条的执行命令,每条命令的开头必须以[Tab]键开头,除非,命令是紧跟在依赖规则后面的分号后的。...

shell特定变量和Makefile中自动化变量的对比记忆

经常在shell命令行见到$*,$#,$@...这些特定变量,还有在Makefile中看到一些以$开头的自动化变量,为了方便记忆,不产生混淆,特总结出来,希望可以给大家带来一些帮助。1.     sh...

GCC 编译动态链接库和静态链接库 + 大型工程Makefile编写 + Linux环境变量的设置和查看方法

GCC 编译使用动态链接库和静态链接库  1 库的分类 根据链接时期的不同,库又有静态库和动态库之分。 静态库是在链接阶段被链接的,所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然...

bash shell自动生成Makefile

  • 2013年05月07日 22:50
  • 2KB
  • 下载

shell设置系统环境变量的问题

业务场景: 我在一个bash脚本中修改了PATH变量的内容,并将其保存到/etc/profile文件中,同时执行了 source /etc/profile 但是当脚本退出时,我发现PATH变量还...
  • tao_627
  • tao_627
  • 2015年11月07日 15:34
  • 2592

十一. shell的变量功能之变量的显示与设置,取消:echo,unset

1.  变量的显示:#echo  ${name}   或则   #echo  $name  2. 变量的设置:系统变量通常大写,自定义变量小写。   (1)变量与变量内容以等号 = 来连...

shell脚本——变量的设置及使用

变量的设置及使用#!/bin/bash# 定义变量## 常量变量 myAge=30 echo $myAge## 字符串变量 # 单引号,单号定义时不能使用转义符号,且不能出现其他变量) myBook...

第1章 BashShell命令------------(默认的shell环境变量与path变量的设置)

1.6.2 默认的shell环境变量与path变量的设置          1.默认的shell环境变量          bashshell默认将使用一些特定的环境变量来定义系统环境。随时都可以...

ARM:Makefile编写、链接脚本编写、裸板shell框架

《Makefile编写、链接脚本编写、裸板shell框架》 ' 工具:UtraEdit 代码编辑工具 // 此工具里面 Ctrl + h 查看ASCII码 vi中命令模式下: ' :e mai...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:makefile中SHELL变量的设置
举报原因:
原因补充:

(最多只允许输入30个字)