【问题背景】
一个大的系统,通过一个总的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_globalfocus_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的作用是不同的。