【已解决】一个makefile中export出来的变量在另外一个makefile中无法访问

【问题背景】

一个大的系统,通过一个总的make控制整个项目编译过程。

具体make的流程是,在/make下面直接make,会先去make uboot,再去make kernel,然后去make其他的,比如drivers等等。

遇到的问题是,由于是使用交叉编译器,对应的交叉编译器的路径,是在uboot中定义的,所以uboot是可以正常交叉编译的。

但是编译完uboot,转去编译kernel的时候,却出错,说是找不到交叉编译器。

即问题的现象是,找不到交叉编译器:

/bin/sh: bfin-uclinux-gcc: command not found
【解决过程】

现象看起来很简单,就是具体的交叉编译器的路径,没有正确配置。

但是具体为何没有添加对应交叉编译器的路径,去找原因,最后却发现根本原因是,对应交叉编译器的路径,是在uboot中配置的,然后通过export CROSS_COMPILE导出该变量,供后续编译其他部分代码所使用。

刚开始,自己的理解有误,以为整个逻辑是,在make之后,由于是先make uboot,再make kernel,所以交叉编译器的变量的值,是通过在uboot中配置好,然后export出来给后续的kernel,drivers等部分编译的时候使用。

但是后来才发现,自己理解错误。

因为uboot和kernel,两者的MAKELEVEL(可以通过echo $(MAKELEVEL)查看当前makefile的level)是同一级的,MAKELEVEL都是2,对应的最开始的make的MAKELEVEL是0.

所以,经过测试,发现通过export出来的变量,在MAKELEVEL=0的make中,是可以传递给子makefile(sub-make)中的uboot的,而通过同一级的makefile,即两者的MAKELEVEL相同,是没法用export传递变量的。

即uboot和kernel,uboot中export出来的变量,是不能传递给kernel的。

而如果uboot中设置的CROSS_COMPILE的变量无法传递给kernel,那么此项目,之前的人,是如何正常编译的呢?最后通过问别人才得知,原来,就是最简单的,把交叉编译器的变量,加到.bash_profile中的$PATH中去,如此而已。这样,就可以在编译kernel的时候,找到对应的交叉编译器了。而不是通过在uboot中export出来CROSS_COMPILE来获得交叉编译器路径的。

此问题,前后花了很长时间去debug,中间,不知道什么原因,导致我测试在总的make,即MAKELEVEL=0的makefile中,传递变量到MAKELEVEL=2的uboot中,结果却发现正常传递参数,搞得很是郁闷,但是后来再次测试,却又正常了,即可以通过上层的makefile,export出来变量给sub makefile中了。真是无语了。

另外,关于在makefile中export出来的变量,可以传递给sub make中,网上很多资料介绍这方面内容的,比如:

http://www.gnu.org/s/hello/manual/make/Variables_002fRecursion.html#Variables_002fRecursion

但是对于同级makefile通过export传递变量,没有看到人讨论过,此处经过自己的测试,发现的确是无法传递的。

 

【makefile中的export和shell中的export】

对于测试,在上层makefile中,用export导出变量,传递给子makefile时,看看子makefile中是否可以访问该变量。

其中,在最上层的makefile中,这样测试的:

 carifan_TopMake=E516537_in_top_make
#export carifan_TopMake
focus_bfin
:
        echo current make MAKELEVEL=$(MAKELEVEL)
        export carifan_TopMake
        echo *****************test Value in Top Makefile=$(carifan_TopMake)
        make -f main.mak PLATFORM=Bfin PRODUCT=Focus MAKE_TARGET=focus_bfin
   

然后make focus_bfin后,发现在focus_bfin下面,export出来的carifan_TopMake,在子makefile中打印出来的是空的,即实际上该变量没有被export出来。

而后来无意间,用下面这样的方式测试:

 carifan_TopMake=E516537_in_top_make
export carifan_TopMake
focus_bfin
:
        echo current make MAKELEVEL=$(MAKELEVEL)

        #export carifan_TopMake
        echo *****************test Value in Top Makefile=$(carifan_TopMake)
        make -f main.mak PLATFORM=Bfin PRODUCT=Focus MAKE_TARGET=focus_bfin

   
结果就是,可以正常export出来变量,然后子makefile中,可以得到该变量的值。

所以,对此现象,经过后来的折腾,发现不是所谓什么makefile中变量的作用域之类的问题,

而是在makefile中的export和shell中的export作用不同:

在focus_bfin上面那行的“export carifan_TopMake”,

是makefile中的export,其作用是导出一个变量,使得子makefile,即当前makefile所派生的的makefile,即通过如下某种形式:

make XXX

make -f XXX.mak

include XXX.mak

而相关的子makefile。

focus_bfin:
        echo current make MAKELEVEL=$(MAKELEVEL)

        #export carifan_TopMake
        echo *****************test Value in Top Makefile=$(carifan_TopMake)
        make -f main.mak PLATFORM=Bfin PRODUCT=Focus MAKE_TARGET=focus_bfin

  

中的目标是“focus_bfin”,然后该目标对应的那些行的代码,都是make要去执行的动作,对于每一行,都会新启动一个shell,去执行对应的命令,因此,上面的focus_bfin中的export:

 #export carifan_TopMake
和下面的那行的make:

      make -f main.mak PLATFORM=Bfin PRODUCT=Focus MAKE_TARGET=focus_bfin
 是没有关系的,是分别属于两个shell的。

经过折腾后,对应地,这样是可以成功导出变量的:

 #export carifan_TopMake

#carifan_TopMake=E516537_in_top_make_global

focus_bfin:

        echo current make MAKELEVEL=$(MAKELEVEL)

        echo "*****************test Value in Top Makefile=$(carifan_TopMake)"; \

        carifan_TopMake=E516537_in_top_make_local;export carifan_TopMake; make -f main.mak PLATFORM=Bfin PRODUCT=Focus MAKE_TARGET=focus_bfin

 

【疑问】

不过,虽然理解了上面的makefile中的export和shell中的export是不同的,但是对于下面的这样的例子:

 carifan_TopMake=E516537_in_top_make_global

focus_bfin:

        echo current make MAKELEVEL=$(MAKELEVEL)

        echo "*****************test Value in Top Makefile=$(carifan_TopMake)"; \

        export carifan_TopMake=E516537_in_top_make_local; echo "in same shell line,carifan_TopMake=$(carifan_TopMake)"; make -f main.mak PLATFORM=Bfin PRODUCT=Focus MAKE_TARGET=focus_bfin

 其echo输出的内容,却是   
 echo "in same shell line,carifan_TopMake=E516537_in_top_make_global"
   而不是我所期望的:

 echo "in same shell line,carifan_TopMake=E516537_in_top_make_local"
   而看到别人有关于makefile中的$XXX的解释,说makefile会去自动将$XXX替换为相应的内容,所以对于上面的内容:

 echo "in same shell line,carifan_TopMake=$(carifan_TopMake)";

其自动会替换成:

 echo "in same shell line,carifan_TopMake=E516537_in_top_make_global";

   所以就相当于在shell中执行:

 export carifan_TopMake=E516537_in_top_make_local; echo "in same shell line,carifan_TopMake=E516537_in_top_make_global";

但是,我去尝试:

 echo "in same shell line,carifan_TopMake=$carifan_TopMake";

或者 

 echo "in same shell line,carifan_TopMake=$$carifan_TopMake";

 输出的结果,都无法实现想要的:

 echo "in same shell line,carifan_TopMake=E516537_in_top_make_local";

 而相对的,在shell中执行类似的动作,是可以echo出来对应的变量的:

 export carifan_TopMake=E516537_in_top_make_local ; echo "$carifan_TopMake"

-->
E516537_in_top_make_local

   而此处却始终无法实现像shell中一样的结果,显示我的E516537_in_top_make_ local 的值。

截止目前,还是没搞懂这点。。。

 

【总结】

1.在(parent,上层的)makefile中export出来变量,子makefile(sub make)中,是可以访问的。

2. 而同一级别的makefile(可通过makefile中内置变量MAKELEVEL查看得知当前makefile的levlel),是无法通过export来传递变量的,即一个makefile中export出来一个变量,同一级的另外一个makefile中,是无法访问/得到的。

3.makefile中的export是导出变量到子makfile,而目标对应执行的动作中的export,是属于shell中的export,其作用是导出变量到当前shell。此两个export的作用是不同的。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本程序的Makefile分为3类: 1. 顶层目录的Makefile 2. 顶层目录的Makefile.build 3. 各级子目录的Makefile 一、各级子目录的Makefile: 它最简单,形式如下: EXTRA_CFLAGS := CFLAGS_file.o := obj-y += file.o obj-y += subdir/ "obj-y += file.o" 表示把当前目录下的file.c编进程序里, "obj-y += subdir/" 表示要进入subdir这个子目录下去寻找文件来编进程序里,是哪些文件由subdir目录下的Makefile决定。 "EXTRA_CFLAGS", 它给当前目录下的所有文件(不含其下的子目录)设置额外的编译选项, 可以不设置 "CFLAGS_xxx.o", 它给当前目录下的xxx.c设置它自己的编译选项, 可以不设置 注意: 1. "subdir/"的斜杠"/"不可省略 2. 顶层Makefile的CFLAGS在编译任意一个.c文件时都会使用 3. CFLAGS EXTRA_CFLAGS CFLAGS_xxx.o 三者组成xxx.c的编译选项 二、顶层目录的Makefile: 它除了定义obj-y来指定根目录下要编进程序去的文件、子目录外, 主要是定义工具链前缀CROSS_COMPILE, 定义编译参数CFLAGS, 定义链接参数LDFLAGS, 这些参数就是文件export导出的各变量。 三、顶层目录的Makefile.build: 这是最复杂的部分,它的功能就是把某个目录及它的所有子目录、需要编进程序去的文件都编译出来,打包为built-in.o 详细的讲解请看视频。 四、怎么使用这套Makefile: 1.把顶层Makefile, Makefile.build放入程序的顶层目录 在各自子目录创建一个空白的Makefile 2.确定编译哪些源文件 修改顶层目录和各自子目录Makefile的obj-y : obj-y += xxx.o obj-y += yyy/ 这表示要编译当前目录下的xxx.c, 要编译当前目录下的yyy子目录 3. 确定编译选项、链接选项 修改顶层目录Makefile的CFLAGS,这是编译所有.c文件时都要用的编译选项; 修改顶层目录Makefile的LDFLAGS,这是链接最后的应用程序时的链接选项; 修改各自子目录下的Makefile: "EXTRA_CFLAGS", 它给当前目录下的所有文件(不含其下的子目录)设置额外的编译选项, 可以不设置 "CFLAGS_xxx.o", 它给当前目录下的xxx.c设置它自己的编译选项, 可以不设置 4. 使用哪个编译器? 修改顶层目录Makefile的CROSS_COMPILE, 用来指定工具链的前缀(比如arm-linux-) 5. 确定应用程序的名字: 修改顶层目录Makefile的TARGET, 这是用来指定编译出来的程序的名字 6. 执行"make"来编译,执行"make clean"来清除,执行"make distclean"来彻底清除

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值