zoukankan      html  css  js  c++  java
  • (三)u-boot2013.01.01 for TQ210:《mkconfig分析》

    /* 和分析makefile一样,分析mkconfig同样注重句法分析 */
    #####################################################################
    #!/bin/sh -e
    # 上面这句指定执行该脚本所使用的解释器, -e相当于使用/bin/bash
    # Script to create header files and links to configure
    # U-Boot for a specific board.
    # Parameters:  Target  Architecture  CPU  Board [VENDOR] [SOC]
    # (C) 2002-2010 DENX Software Engineering, Wolfgang Denk <wd@denx.de>
    #
    #####################################################################
    # mkconfig脚本文件存在的理由:因为uboot是一个多CPU多架构的统一bootloader,为了完成针
    # 对特定目标单板,目标架构的编译,需要给Makefile指明,哪些文件需要编译,相当与从整体上控制
    # 需要编译的cpu,单板等。
    # 当执行make xxx_config U-boot时就会调用这个mkconfig文件。mkconfig会处理单板信息
    # (在boards.cfg文件中定义有各种单板信息,smdkc100_config只是其中一个)并生成单板信息到
    # U-boot源码顶层目录/include/config.mk这个文件中(会自动创建)。
    # 以make smdkc100_config为例,执行成功后,mkconfig会产生5个变量分别为:
    #   ARCH   CPU    BOARD    VENDOR   SOC
    #   arm   armv7  smdkc100  samsung s5pc1xx
    # (ARCH=目标板的CPU架构   CPU=具体使用的CPU型号   BOARD = 目标板名称  SOC = 芯片名称)
    
    APPEND=no		# 默认创建一个新的配置文件
    BOARD_NAME=""	# make 执行xxx_config的时候打印输出单板名
    TARGETS=""
    
    arch=""
    cpu=""
    board=""
    vendor=""
    soc=""
    options=""
    #####################################################################
    # SHELL常用内部参数:  
    # $# ----传递给程序的总的参数数目
    # $? ----上一个代码或者shell程序在shell中退出的情况,如果正常退出则返回0,反之为非0值。
    # $* ----传递给程序的所有参数组成的字符串。
    # $n ----表示第几个参数,$1 表示第一个参数,$2 表示第二个参数 ... 
    # $0 ----当前程序的名称
    # $@ ----以"参数1" "参数2" ... 形式保存所有参数
    # $$ ----本程序的(进程ID号)PID
    # $! ----上一个命令的PID 
    # 下面对$?多做些说明,当补充shell知识吧
    # 切记:$?永远表示shell命令最后一次执行后的退出状态,当函数执行完毕后,如果又执行了其它命
    # 令,则$?不再表示函数执行后的状态,而表示其它命令的退出状态.
    #-a  表示(and)两个条件同时成立
    # -eq 表示两数值相等
    # -gt 表示n1大于n2,即前面大于后面
    # -lt 表示n1小于n2,即前面小于后面
    # "("  ")"是对圆括号的转义,转成普通圆括号"()"来包裹条件表达式
    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    # !!!!注意!!!:从下面开始我们做个约定$0,$1,$2,...我们称$0为第0个变量,$1为第1个变量!!!!
    # !!!!!这样排号从描述上比较便!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    # if[...]中的表达式意思为:如果传递给mkconfig的参数个数($#)等于2个并且第1个变量为
    # "-A"($1),则执行出错提示.那么$0,$1,$2,...是什么呢?我们看Makefile中是怎么执行make 
    # xxx_config这个伪目标的.
    # Makefile中是这么写的:
    # %_config::	unconfig
    # @$(MKCONFIG) -A $(@:_config=)
    # MKCONFIG的值为mkconfig(这是在Makefile里有定义的,自己搜索一下就可以到),$(MKCONFIG)
    # 就是执行mkconfig脚本,则传入的参数 $0=U-boot源码顶层目录/mkconfig  $1 = -A   $2 = 
    # $(@:_config),当我们输入的是make smdkc100_config时$(@:_config) = smdkc100,所以# 这个表达式意思是把输入的参数中的字符串"_config"去掉然后返回剩下的部分,
    # smdkc100_config去掉"_config"后当然就剩下"smdkc100",所以$(@:_config) = smdkc100,
    # 进而$2 = $(@:_config) = smdkc100。所以很明显,执行@$(MKCONFIG) -A $(@:_config=)
    # 后,传入给mkconfig的参数的确是有两个并且第1个变量$1=-A,所以if表达式为真然后会执行then
    # 后面的脚本语句!!
    if [ ( $# -eq 2 ) -a ( "$1" = "-A" ) ] ; then
    	########################################################################
    	# egrep是grep的扩展,egrep支持扩展型的正则表达式。-i参数表示不区分大小写。
    	# "^[[:space:]]*${2}[[:space:]]"。'^'表示反向选择,'*'是通配符,代表任意(0个或
    # 多个)字符*${2}则表示1个以上的任意多个${2}。所以这个表达式的意思是:从boards.cfg文
    # 件中搜索符合条件:非空格开头但以空格结尾的包含至少1个"smdkc100"字符串的行.如果搜索
    # 不到,则说明不存在对应的单板信息,则会报错说找不到创建目标的规则并退出不再执行脚本。
    # !!!说了这么多,总结起来这个if判断表达式所做的工作就是从boards.cfg文件中找到执行
    # xxx_config的单板信息,找不到就无法完成单板配置,U-boot编译自然也无法完成!!!!
    	line=`egrep -i "^[[:space:]]*${2}[[:space:]]" boards.cfg` || {
    		echo "make: *** No rule to make target \`$2_config'.  Stop." >&2
    		exit 1
    	}
        
    
        ########################################################################
        # 了解这句的意思前先做些功课吧,看完不用我解释相信你也清楚是干嘛用的了
        # 扩展阅读:set,env和export这三个命令都可以用来显示shell变量,其区别是什么?
        # set 用来显示本地变量
        # env 用来显示环境变量
        # export 用来显示和设置环境变量
        # set 显示当前shell的变量,包括当前用户的变量
        # env 显示当前用户的变量
    # export 显示当前导出成用户变量的shell变量
    # 每个shell有自己特有的变量(set)显示的变量,这个和用户变量是不同的,当前用户变量和你
    # 用什么shell无关,不管你用什么shell都在,比如HOME,SHELL等这些变量,但shell自己的 
    # 变量不同,shell是不同的,比如BASH_ARGC, BASH等,这些变量只有set才会显示,是bash
    # 特有的,export不加参数的时候,显示哪些变量被导出成了用户变量,因为一个shell自己的变
    # 量可以通export “导出”变成一个用户变量。set ${line}意思是设置line中的变量为本地环
    # 境变量,变量的集合为line,你可以在这句的下面加上显示本地环境变量的语句echo `set`,
    # 终端会打印出所有本地变量,找一下就可以发现其中有一句内容是:line = 'smdkc100 arm # 
    # armv7 smdkc100 sansung s5pc1xx'。要是缺少了set ${line}就等着出错吧!(上述结果
    # 是基于make smdkc100_config而言的)
        
    	set ${line}
    #echo `set`     # 删掉echo前面的'#',该语句将会被执行。2012-12-25圣诞节^_^
    	#######################################################################
    	# 如果boards.cfg搜索到的单板信息行的变量只有3个,如果有需要的话则把变量${1}作为默认
    # 单板名称
    	[ $# = 3 ] && set ${line} ${1}
    	
    ###########################################################################
    # 接上面的if表达式的分支,即如果make smdkc100_config时,即执行
    # %_config::	unconfig
    # @$(MKCONFIG) -A $(@:_config=)
    # 后传入的参数不是2个或者第1个变量不是-A则执行elif下面的判断
    # 如果${MAKEFLAGS+set}${MAKELEVEL+set} = setset则向终端打印警告信息并使用sleep 5
    # 来做延时提示,延时一下信息会停留在终端一段时间然后继续往下执行,这样做只是为了让程序猿更
    # 容易注意到这个这个警告条目吧,我的想法是这样的,有更好解释的可以告知我,谢谢!"cat << -EOF 
    # 信息  EOF"  是用来显示文本内容的,EOF就是"end of file"的意思实际上正常情况下
    # "${MAKEFLAGS+set}${MAKELEVEL+set}" = "setset"是成立的,只是执行if了。所以轮不到
    # elif执行!
    elif [ "${MAKEFLAGS+set}${MAKELEVEL+set}" = "setset" ] ; then
    	# only warn when using a config target in the Makefile
    	cat <<-EOF
    
    	warning: Please migrate to boards.cfg.  Failure to do so will
    	         mean removal of your board in the next release.
    
    	EOF
    	sleep 5
    fi
    
    ###########################################################################
    # 如果上面一切正常的话,执行了make smdkc100_config后就会有6个变量传进来,分别是:
    # smdkc100 arm armv7 smdkc100 sansung s5pc1xx
    # 此时$# = 6,while [ $# -gt 0 ]的意思就是当S#不为0时循环执行do ... done之间的语句
    # shift的作用是使$1=$2,$2=$3,$3=$4….,而原来的$1将丢失。因此while循环的作用是,依次# 处理传递给mkconfig脚本的选项(--,-a,-n,-t,*)。由于我们并没有传递给mkconfig任何的选
    # 项,因此while循环中的代码不起作用。具体的处理是比较简单了,既然没用到也就不多废话了。
    while [ $# -gt 0 ] ; do
    	case "$1" in
    	--) shift ; break ;;
    	-a) shift ; APPEND=yes ;;
    	-n) shift ; BOARD_NAME="${1%_config}" ; shift ;;
    	-t) shift ; TARGETS="`echo $1 | sed 's:_: :g'` ${TARGETS}" ; shift ;;
    	*)  break ;;
    	esac
    done
    
    ###########################################################################
    # 检查如果传进来的变量个数,如果小于4个则退出,若大于7个也要退出
    [ $# -lt 4 ] && exit 1
    [ $# -gt 7 ] && exit 1	
    
    ###########################################################################
    # 变量赋值,CONFIG_NAME = smdkc100,${1%_config}意思是将$1的字符串右边拿掉"_config"(如果有的话)
    CONFIG_NAME="${1%_config}"
    
    ###########################################################################
    # 如果BOARD_NAME(单板名称)不为空则什么都不做,如果为空则BOARD_NAME="${1%_config}
    # ${1%_config}意思是将$1的字符串右边拿掉"_config"(如果有的话)
    # 脚本文件开头BOARD_NAME = "",所以执行下句后BOARD_NAME = smdkc100
    [ "${BOARD_NAME}" ] || BOARD_NAME="${1%_config}"
    
    ###########################################################################
    # arch = arm  
    # 处理cpu赋值时,先用echo $3读入要处理的信息行,即armv7,armv7会被赋值到$1中,即$1=armv7
    # 而$2 = 空,然后awk 'BEGIN {FS = ":"}; {print $1}'意思是以冒号为分隔符,提取出输入
    # 行的第一个变量,结果是cpu = armv7。同理spl_cpu = $2,而$2为空,所以spl_cpu为空
    arch="$2"
    cpu=`echo $3 | awk 'BEGIN {FS = ":"} ; {print $1}'`
    spl_cpu=`echo $3 | awk 'BEGIN {FS = ":"} ; {print $2}'`
    
    ###########################################################################
    # 如果$4的值为'-',则board = ${BOARD_NAME} = "smdkc100"(正常情况下),
    # 否则board="$4"="smdkc100",为什么这么做呢,其实是为了防止boards.cfg中单板信息不足的
    # 情况下还能从ARCH信息中把单板名字提取出来然后复制给board变量。(PS:开发者想得真周到)
    if [ "$4" = "-" ] ; then
    	board=${BOARD_NAME}
    else
    	board="$4"
    fi
    
    ###########################################################################
    # 当传进来的变量数目大于4的时候而且第5个变量不等于"-"时vendor="$5"="samsung"
    # 当传进来的变量数目大于5的时候而且第6个变量不等于"-"时soc="$6"="s5pc1xx"
    # 当传进来的变量数目大于6的时候而且第7个变量不等于"-"时执行{..}中的处理
    [ $# -gt 4 ] && [ "$5" != "-" ] && vendor="$5"
    [ $# -gt 5 ] && [ "$6" != "-" ] && soc="$6"
    [ $# -gt 6 ] && [ "$7" != "-" ] && {
    	# check if we have a board config name in the options field
    	# the options field mave have a board config name and a list
    	# of options, both separated by a colon (':'); the options are
    	# separated by commas (',').
    	#
    	# Check for board name
    	
    	#############################################################
    	  # 检查在选项区域(Options)中是否存在一个单板配置选项,该选项区域可能含有单板名称和选项
    # 表。单板名称和选项之间使用':'做分隔符,选项表成员之间则用','做分隔符
    	# 举例:对于mx51_efikamx单板来说,它的Options为:
    	   # mx51_efikamx:MACH_TYPE=MACH_TYPE_MX51_EFIKAMX,IMX_CONFIG=board/genesi/m
    # x51_efikamx/imximage_mx.cfg即
    #"$7"="mx51_efikamx:MACH_TYPE=MACH_TYPE_MX51_EFIKAMX,IMX_CONFIG=board/g
    # enesi/mx51_efikamx/imximage_mx.cfg"
    	# ${7%:*}:从字符串"$7"右边开始删掉字符,直到遇到(从右部数起的)第一个':'
    	# temp = mx51_efikamx
    	tmp="${7%:*}"
    	# 如果tmp不是空的则配置名称CONFIG_NAME = "$tmp" = "mx51_efikamx"
    	if [ "$tmp" ] ; then
    		CONFIG_NAME="$tmp"
    	fi
    	
    	#  注意!确保Options域中的内容中只有一个':'号
    	#  "${tmp}" != "$7"用这句来做比较,确认上一步处理是否成功
    	#  ${7#*:},这个表达式意思是从字符串"$7"左边开始删掉直到遇到第一个':'为止
    	   # options=${7#*:}=MACH_TYPE=MACH_TYPE_MX51_EFIKAMX,IMX_CONFIG=board/genes
    # i/mx51_efikamx/imximage_mx.cfg
    	#  echo ${options}这句是将options作为sed的处理源
    	#  sed 's:,: :g',开头的's'代表搜索,搜索','然后把搜索到的','替换成空格' '
    	#  TARGETS = MACH_TYPE=MACH_TYPE_MX51_EFIKAMX
    #  IMX_CONFIG=board/genesi/mx51_efikamx/imximage_mx.cfg
    	if [ "${tmp}" != "$7" ] ; then
    		options=${7#*:}
    		TARGETS="`echo ${options} | sed 's:,: :g'` ${TARGETS}"
    	fi
    }
    
    ###########################################################################
    # 如果变量ARCH的值存在而且变量ARCH的值与变量arch的值不相等的话则配置失败,打印错误信息
    # ARCH和arch必须相等!
    if [ "${ARCH}" -a "${ARCH}" != "${arch}" ]; then
    	echo "Failed: $ARCH=${ARCH}, should be '${arch}' for ${BOARD_NAME}" 1>&2
    	exit 1
    fi
    ###########################################################################
    # 如果options存在则把options信息一并打印出来,否则的话就没必要打印!
    # 这里就是我们执行make xxx_config后会打印到终端上的信息!
    if [ "$options" ] ; then
    	echo "Configuring for ${BOARD_NAME} - Board: ${CONFIG_NAME}, Options: ${options}"
    else
    	echo "Configuring for ${BOARD_NAME} board..."
    fi
    
    ###########################################################################
    # 如果源码顶层目录(SRCTREE)和存放编译生成文件的目录(OBJTREE)不一致的话就在
    # 存放编译生成文件的目录(OBJTREE)建立两个文件include和include2
    # 然后进入include2目录中,删除asm文件夹,建立一个 软链接asm,链接指向目录
    # ${SRCTREE}/arch/${arch}/include/asm
    # LNPREFIX多加了一个'/'作为路径,然后退到上层目录进入include文件夹,创建一个名为asm的文# 件夹
    if [ "$SRCTREE" != "$OBJTREE" ] ; then
    	mkdir -p ${OBJTREE}/include
    	mkdir -p ${OBJTREE}/include2
    	cd ${OBJTREE}/include2
    	rm -f asm
    	ln -s ${SRCTREE}/arch/${arch}/include/asm asm
    	LNPREFIX=${SRCTREE}/arch/${arch}/include/asm/
    	cd ../include
    	mkdir -p asm
    else
    	########################################################################
    	# 如果二者目录相同的话就直接进入当前目录(此时当前目录就是U-boot源码的顶层目录)的
    # include文件夹中删除 asm文件夹,直接建立一个软链接asm,链接指向目
    # 录../arch/${arch}/include/asm
    # 一般我们采用这个分支的方法来编译U-boot,OBJTREE目录就是U-boot源码顶层目录相当于 
    # ln -s ../arch/arm/include/asm asm
    	cd ./include
    	rm -f asm
    	ln -s ../arch/${arch}/include/asm asm
    fi
    
    ###########################################################################
    # 删除 asm/arch,这个时候的asm是个软连接,实际上是对链接的目标进行操作,建立软件接的目的就# 是方便程序的编写和编译,提高效率,你写程序的时候总不想常常打一长串的路径吧
    rm -f asm/arch
    
    ###########################################################################
    # 如果soc不为空则建立软连接asm/arch,指向${LNPREFIX}arch-${cpu},由于OBJTREE目录就是
    # U-boot源码顶层目录,LNPREFIX为空
    # 一般soc也不为空,则相当于执行: ln -s arch-armv7 asm/arch
    if [ -z "${soc}" ] ; then
    	ln -s ${LNPREFIX}arch-${cpu} asm/arch
    else
    	ln -s ${LNPREFIX}arch-${soc} asm/arch
    fi
    
    ###########################################################################
    # 如果架构是arm架构,则删除当前目录(此时当前目录是U-boot源码顶层目录/include)下的
    # asm/proc目录建立软链接ln -s proc-armv asm/proc
    if [ "${arch}" = "arm" ] ; then
    	rm -f asm/proc
    	ln -s ${LNPREFIX}proc-armv asm/proc
    fi
    
    ###########################################################################
    # 生成make的头文件config.mk
    # ARCH=arm  CPU=armv7 BOARD=smdkc100 VENDOR=samsung  SOC=s5pc1xx 
    # 加一个exit0(返回成功值),然后这些统统写入config.mk文件中, > config.mk是强行覆盖创建# config.mk然后把数据导入config.mk中
    ( 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
    
    ###########################################################################
    # 如果厂商名不为空则BOARDDIR = ${vendor}/${board},vendor=samsung,所以
    # BOARDDIR = samsung/smdkc100
    if [ -z "${vendor}" ] ; then
        BOARDDIR=${board}
    else
        BOARDDIR=${vendor}/${board}
    fi
    
    ###########################################################################
    # 创建指定的配置的头文件,默认APPEND=no(本文件开头有赋值),所以执行else分支,创建
    # config.h文件
    if [ "$APPEND" = "yes" ]	# Append to existing config file
    then
    	echo >> config.h
    else
    	> config.h		# Create new config file
    fi
    ###########################################################################
    # 向config.h中写入信息
    echo "/* Automatically generated - do not edit */" >>config.h
    
    ###########################################################################
    # 如果没有Options选项的话,TARGETS为空,for不执行,如果有Options选项,则i=TARGETS中变# 量的个数变量之前已经被处理成以空格符' '分隔,例如:TARGETS = 
    # MACH_TYPE=MACH_TYPE_MX51_EFIKAMX 
    # IMX_CONFIG=board/genesi/mx51_efikamx/imximage_mx.cfg,然后用echo ${i}逐条导入
    # sed进行处理,sed '/=/ {s/=/	/;q; } ; { s/$/	1/; }'的作用是搜索等号'=',然后把
    # 等号替换成TAB符'	',接着参数q意思是退出当前动作执行下一个动作,下一个动作用分号';'分隔,
    # 最后加上#define CONFIG_${i}后写入config.h中。
    # "MACH_TYPE=MACH_TYPE_MX51_EFIKAMX"处理成:
    # "#define CONFIG_MACH_TYPE  MACH_TYPE_MX51_EFIKAMX"
    # "IMX_CONFIG=board/genesi/mx51_efikamx/imximage_mx.cfg"处理成:
    # "#define CONFIG_IMX_CONFIG  board/genesi/mx51_efikamx/imximage_mx.cfg"
    for i in ${TARGETS} ; do
    	i="`echo ${i} | sed '/=/ {s/=/	/;q; } ; { s/$/ 1/; }'`"
    	echo "#define CONFIG_${i}" >>config.h ;
    done
    
    ###########################################################################
    # 如果是smdkc100,config.h中会多出以下头文件
    # #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"  
          
    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
    
    ###########################################################################
    # 添加别的头文件,利用cat << EOF >> config.h  ...内容...   EOF把信息写入config.h中
    cat << EOF >> config.h
    #define CONFIG_BOARDDIR board/$BOARDDIR
    #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
    

  • 相关阅读:
    C#操作Word (2)-- 打开&关闭Word文档
    JS input 银行卡号格式转换
    解决H5在微信浏览器或QQ浏览器修改title的问题
    CSS
    Atom 编辑器使用和学习
    php的一个小坑,输出不了json_encode
    js 组合键监听ctrl + enter
    webpack3.0 环境搭建
    css 使表格随着内容自动适应宽度
    获取input光标的x和y轴
  • 原文地址:https://www.cnblogs.com/java20130723/p/3211366.html
Copyright © 2011-2022 走看看