OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 13030|回复: 14

Uboot 2014.07 makefile分析

[复制链接]

63

主题

305

帖子

1

精华

高级会员

Rank: 4

积分
853
金钱
853
注册时间
2012-8-3
在线时间
79 小时
发表于 2014-10-14 09:38:00 | 显示全部楼层 |阅读模式
uboot的官网可以通过谷歌搜索得到,显示结果第一个链接就是。
官网::
http://www.denx.de/wiki/U-Boot
ftp下载:
ftp://ftp.denx.de/pub/u-boot/


本文以uboot 2014.07为例,一般第一步总是类似这样:
make smdkc100_config
然后执行make

先看Makefile第481 行
%_config:: outputmakefile
@$(MKCONFIG) -A $(@:_config=)
当输入make smdkc100_config时,就会匹配到%_config目标,%是通配符,即输入XXX_config格式的目标就会匹配到%_config。
MKCONFIG的定义在前面:
MKCONFIG := $(srctree)/mkconfig
export MKCONFIG

srctree的定义:
srctree := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR))//if KBUILD_SRC被定义,则srctree=KBUILD_SRC,else = CURDIR,

KBUILD_SRC的定义:
ifeq ($(KBUILD_SRC),)
# OK, Make called in directory where kernel src resides
# Do we want to locate output files in a separate directory?
#O就是output目录变量,使用方法:make O= XXXDIR
ifeq ("$(origin O)", "command line")
#如果O变量来自命令行(origin返回变量的来源)
  KBUILD_OUTPUT := $(O)
endif

事实上我没用O去定义KBUILD_SRC变量,所以srctree=当前目录,也就是uboot的目录
objtree := $(CURDIR)
src := $(srctree)

以上语句可翻译为:
smdkc100_config:: outputmakefile
./mkconfig -A $(@:_config=)

这里的规则用了双冒号 :: 
1.        双冒号规则中,当依赖文件比目标更新时。规则将会被执行。对于一个没有依赖而只有命令行的双冒号规则,当引用此目标时,规则的命令将会被无条件执行。而普通规则,当规则的目标文件存在时,此规则的命令永远不会被执行(目标文件永远是最新的)。

$(@:_config=):请看Gnu Make中文手册5.3.1 变量的替换引用。
$(@)代表目标smdkc100_config,$(@:_config=):表示用等号后面的内容替代掉:和=之间的内容,=后面为空,那么_config就等于被删去了,$(@:_config=)就代表smdkc100
./mkconfig -A $(@:_config=)


现在可以看mkconfig文件了。mkconfig没有目标,从第一句开始执行:
第一个if段:

if [ \( $# -eq 2 \) -a \( "$1" = "-A" \) ] ; then
# Automatic mode
line=`awk '($0 !~ /^#/ && $7 ~ /^'"$2"'$/) { print $1, $2, $3, $4, $5, $6, $7, $8 }' $srctree/boards.cfg`
if [ -z "$line" ] ; then
echo "make: *** No rule to make target \`$2_config'.  Stop." >&2
exit 1
fi

set ${line}
# add default board name if needed
[ $# = 3 ] && set ${line} ${1}
fi

######    $#表示传入参数个数,由上可知$# = 2,符合条件。 -a表示逻辑与。$1表示第一个参数,等于-A,符合条件,所以then后面的语句被执行。
这段代码符号比较多,看起来比较复杂,请百度shell 符号,你会有所收获。

line=`awk**************`
用倒引号``把命令的输出作为字串,如果是"",则里面的内容不被当做命令执行,而是当做纯粹的字符串,但可引用变量
'  '单引号内的内容作为字串,但变量$符号不会起作用(忽略任何引用),
单括号()内可以的内容可以执行命令,也就是说,()内先执行,再用''把()的输出当做纯字串,大括号同理。
//斜杠表示里面的内容是正则表达式。
($0 !~ /^#/ && $7 ~ /^'"$2"'$/)
在awk命令里,$不是shell变量符号,而是域标记。但是也有例外:双引号""中的$可以引用变量(参见《LINUX与UNIX SHELL编程指南》67页,9.2.2节,“域和记录”和第15章,引号),所以这里的$7 为boards.cfg里的域7,而$2则表示mkconfig的第二个参数,没错,就是smdkc100,/^'"$2"'$/表示只包含变量$2的行,依然是smdkc100。
$0表示所有域,$0 !~ /^#/ 意思是,awk排除以#开头的行,这句话用来排除那些以#开头的注释内容。$7 ~ /^'"$2"'$/表示记录的域7必须为smdkc100
boards.cfg只有下面这行符合条件:
Active  arm         armv7          s5pc1xx     samsung         smdkc100            smdkc100
然后执行{ print $1, $2, $3, $4, $5, $6, $7, $8 }
这样line就等于Active  arm         armv7          s5pc1xx     samsung         smdkc100            smdkc100

接下来:
set ${line}
# add default board name if needed
[ $# = 3 ] && set ${line} ${1}

set命令
参见《高级bash脚本编程指南》202页
set 命令用来修改内部脚本变量的值.一个作用就是触发选项标志位来帮助决定脚本的行
为.另一个应用就是以一个命令的结果(set `command`)来重新设置脚本的位置参数.脚本
将会从命令的输出中重新分析出位置参数。

所以mkconfig 的位置参数被重新定义为$(line)的内容,即:
$1=Active  $2=arm         $3=armv7          $4=s5pc1xx     $5=samsung         $6=smdkc100            $7=smdkc100  $8=-(注意是短破折号,不是空格)
补充一下,以上排列为:

# Status, Arch, CPU:SPLCPU, SoC, Vendor, Board name, Target, Options
 
对于[ $# = 3 ] && set ${line} ${1}
&&的说明参见《LINUX与UNIX SHELL编程指南》6.1 使用&&
这里先判断$# 是否等于 3(明显不等),相等则执行&&右边的命令。那么,直接跳过吧。

[mw_shl_code=c,true]while [ $# -gt 0 ] ; do case "$1" in --) shift ; break ;; -a) shift ; APPEND=yes ;; -n) shift ; BOARD_NAME="${7%_config}" ; shift ;; -t) shift ; TARGETS="`echo $1 | sed 's:_: :g'` ${TARGETS}" ; shift ;; *) break ;; esac done[/mw_shl_code]
其实上面的参数都不会匹配到。(没有指定-a -n -t选项)
这里只说一下${7%_config},结果等于smdkc100 ,请百度shell 截取 变量。
%号截取,删除右边字符,保留左边字符
echo ${var%/*}
%/* 表示从右边开始,删除第一个 / 号及右边的字符


实际上$7本身等于smdkc100了,那么${7%_config}依然是smdkc100。
后面的代码比较简单了,实现如下功能:

变量arch="arm"
建立软连接:
arch\arm\include\asm\arch-s5pc1xx 生成链接符号 arch\arm\include\asm\arch


进入include目录
[mw_shl_code=c,true]# Create include file for Make # ( echo "ARCH = ${arch}" if [ ! -z "$spl_cpu" ] ; then echo 'ifeq ($(CONFIG_SPL_BUILD),y)' echo "CPU = ${spl_cpu}" echo "else" echo "CPU = ${cpu}" echo "endif" else echo "CPU = ${cpu}" fi echo "BOARD = ${board}" [ "${vendor}" ] && echo "VENDOR = ${vendor}" [ "${soc}" ] && echo "SOC = ${soc}" exit 0 ) > config.mk[/mw_shl_code]
include目录下生成config.mk,内容为:
ARCH   = arm
CPU    = armv7
BOARD  = smdkc100
VENDOR = samsung
SOC    = s5pc1xx

include目录下创建config.h

for i in ${TARGETS} ; do
i="`echo ${i} | sed '/=/ {s/=/ /;q; } ; { s/$/ 1/; }'`"
echo "#define CONFIG_${i}" >>config.h ;
done
 ${TARGETS} 为空,所以以上for循环不会被执行。

[mw_shl_code=c,true]echo "#define CONFIG_SYS_ARCH \"${arch}\"" >> config.h echo "#define CONFIG_SYS_CPU \"${cpu}\"" >> config.h echo "#define CONFIG_SYS_BOARD \"${board}\"" >> config.h [ "${vendor}" ] && echo "#define CONFIG_SYS_VENDOR \"${vendor}\"" >> config.h [ "${soc}" ] && echo "#define CONFIG_SYS_SOC \"${soc}\"" >> config.h [ "${board}" ] && echo "#define CONFIG_BOARDDIR board/$BOARDDIR" >> config.h cat << EOF >> config.h #include <config_cmd_defaults.h> #include <config_defaults.h> #include <configs/${CONFIG_NAME}.h> #include <asm/config.h> #include <config_fallbacks.h> #include <config_uncmd_spl.h> EOF exit 0[/mw_shl_code]
[mw_shl_code=c,true]cat << EOF >> config.h表示以下内容追加到config.h中,直到出现EOF标记为止。[/mw_shl_code] 最终config.h内容为:

[mw_shl_code=c,true]/* Automatically generated - do not edit */ #define CONFIG_SYS_ARCH "arm" #define CONFIG_SYS_CPU "armv7" #define CONFIG_SYS_BOARD "smdkc100" #define CONFIG_SYS_VENDOR "samsung" #define CONFIG_SYS_SOC "s5pc1xx" #define CONFIG_BOARDDIR board/samsung/smdkc100 #include <config_cmd_defaults.h> #include <config_defaults.h> #include <configs/smdkc100.h> #include <asm/config.h> #include <config_fallbacks.h> #include <config_uncmd_spl.h>[/mw_shl_code]




u-boot-smdkc100.tar.bz2

7.38 MB, 下载次数: 352

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-10-14 23:33:56 | 显示全部楼层
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

1

主题

8

帖子

0

精华

初级会员

Rank: 2

积分
58
金钱
58
注册时间
2013-7-19
在线时间
7 小时
发表于 2015-5-7 12:47:03 | 显示全部楼层
谢谢楼主~
正在开始看u-boot
回复 支持 反对

使用道具 举报

1

主题

9

帖子

0

精华

新手上路

积分
34
金钱
34
注册时间
2015-6-3
在线时间
0 小时
发表于 2015-6-3 11:13:07 | 显示全部楼层
楼主,我在移植的时候选用了你的这个版本的uboot,但是生成的uboot.bin文件却没有c代码,不知道是什么原因,能帮忙分析下吗
回复 支持 反对

使用道具 举报

63

主题

305

帖子

1

精华

高级会员

Rank: 4

积分
853
金钱
853
注册时间
2012-8-3
在线时间
79 小时
 楼主| 发表于 2015-6-3 17:29:53 | 显示全部楼层
回复【4楼】sunpat:
---------------------------------
生成的uboot.bin没有c代码?我不太理解这句话的意思。麻烦说中文^_^
回复 支持 反对

使用道具 举报

1

主题

9

帖子

0

精华

新手上路

积分
34
金钱
34
注册时间
2015-6-3
在线时间
0 小时
发表于 2015-6-3 19:15:44 | 显示全部楼层
回复【5楼】EDA3rd:
---------------------------------
事情是这样的,编译后在板子上跑发现总是死在board_init_f这块儿,后来我用gdb反汇编查看这个函数发现这块全是空的,没有指令,然后我将u-boot.bin文件也反汇编,发现所有c 代码都没有编进bin文件中,是不是链接的时候出问题了?下面是我反汇编的结果,有汇编指令的是start.S的代码,没有的是 c 的,纠结中 ,其实我就是想把能在老版本uboot上跑起来的板级支持移植到这个版本上,一路波折,现在遇到这个问题没思路了

    10a4:   14ff0010    b   0xcf8
    10a8:   21186900    addu    v1,v1,t1
    10ac:   00000000    nop
    10b0:   ffffffff    sd  ra,-1(ra)
    10b4:   ffffffff    sd  ra,-1(ra)
    10b8:   ffffffff    sd  ra,-1(ra)
    10bc:   ffffffff    sd  ra,-1(ra)
    .....
回复 支持 反对

使用道具 举报

1

主题

9

帖子

0

精华

新手上路

积分
34
金钱
34
注册时间
2015-6-3
在线时间
0 小时
发表于 2015-6-3 19:24:26 | 显示全部楼层
回复【6楼】sunpat:
---------------------------------
其实我就是想把能在老版本uboot上跑起来的板级支持移植到这个版本上,一路波折,现在遇到这个问题没思路了
回复 支持 反对

使用道具 举报

头像被屏蔽

65

主题

277

帖子

0

精华

高级会员

Rank: 4

积分
674
金钱
674
注册时间
2013-8-11
在线时间
29 小时
发表于 2015-6-3 20:00:49 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

1

主题

9

帖子

0

精华

新手上路

积分
34
金钱
34
注册时间
2015-6-3
在线时间
0 小时
发表于 2015-6-4 09:39:39 | 显示全部楼层
回复【5楼】EDA3rd:
---------------------------------
我发现编译阶段每次链接的时候都是链接的built-in.o这个文件,它取代了原先的libxx.a吗
回复 支持 反对

使用道具 举报

63

主题

305

帖子

1

精华

高级会员

Rank: 4

积分
853
金钱
853
注册时间
2012-8-3
在线时间
79 小时
 楼主| 发表于 2015-6-4 09:51:26 | 显示全部楼层
回复【9楼】sunpat:
---------------------------------
built-in.o是将所在目录的所有生成的目标文件(*.o)打包,包括.a库文件,makefile最终将所有目录下的built-in.o打包成u-boot.bin,这是kbuild的机制。
要移植的话你看看移植教程。最好参考别人移植过的版本,在你不熟悉uboot的情况下,建议不要自己尝试去移植新版本的uboot,我之前也是看zjh移植了2014.04,发现原来uboot这么简单,然后才尝试自己移植2014.07的
回复 支持 反对

使用道具 举报

1

主题

9

帖子

0

精华

新手上路

积分
34
金钱
34
注册时间
2015-6-3
在线时间
0 小时
发表于 2015-6-4 12:45:35 | 显示全部楼层
回复【10楼】EDA3rd:
---------------------------------
原来如此,昨天我就觉得是链接的问题,今天上午手动加载了built-in.o到链接脚本里,调试就能跑到c了,bin文件也有代码了,现在不明白的是为什么make的时候ld会失败,还没报错,编译的时候还显示了 LD xxx/built-in.o的字样,奇怪了
回复 支持 反对

使用道具 举报

63

主题

305

帖子

1

精华

高级会员

Rank: 4

积分
853
金钱
853
注册时间
2012-8-3
在线时间
79 小时
 楼主| 发表于 2015-6-4 15:55:14 | 显示全部楼层
built-in.o从来都不是手动加载的
回复 支持 反对

使用道具 举报

1

主题

9

帖子

0

精华

新手上路

积分
34
金钱
34
注册时间
2015-6-3
在线时间
0 小时
发表于 2015-6-5 11:35:53 | 显示全部楼层
回复【12楼】EDA3rd:
---------------------------------
可能说手动加载有点不合适,只是指定了链接顺序 :-) 虽然没弄懂为什么好使。。。。

今天上午弄puts("DRAM   ") ,发现只要一进入serial_printf(const char *fmt, ...) fmt的值就不对了(gdb看的),好奇怪,中间就是一个宏定义转换,没经过什么啊。
PS:把define puts serial_printf 去掉,直接调用serial_printf也会变


Breakpoint 1, init_func_ram () at arch/mips/lib/board.c:167
167 puts ("DRAM:  ");
(gdb) s
serial_printf (fmt=0xbfc24f90 '\377' <repeats 200 times>...)
    at arch/mips/lib/board.c:153
153 i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
回复 支持 反对

使用道具 举报

1

主题

9

帖子

0

精华

新手上路

积分
34
金钱
34
注册时间
2015-6-3
在线时间
0 小时
发表于 2015-6-5 14:50:55 | 显示全部楼层
回复【12楼】EDA3rd:
---------------------------------
我怀疑是因为我虽然吧text段强行链接到了一起,但是数据段却没有,导致夸文件的函数传参过程出错,又回到原来问题了, 为啥链接会失败,失败了为啥没报错,继续纠结。。。
回复 支持 反对

使用道具 举报

63

主题

305

帖子

1

精华

高级会员

Rank: 4

积分
853
金钱
853
注册时间
2012-8-3
在线时间
79 小时
 楼主| 发表于 2015-6-6 09:31:21 | 显示全部楼层
回复【14楼】sunpat:
---------------------------------
瞎折腾,看看别人的移植教程,没看到有你这么折腾的
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-21 14:50

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表