• (三)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
    

  • 相关阅读:
    Android开发 ViewConfiguration View的配置信息类
    Android 开发 倒计时功能 转载
    Android 开发 关于7.0 FileUriExposedException异常 详解
    Android 开发 实现文本搜索功能
    Android 开发 Activity里获取View的宽度和高度 转载
    Android 开发 存储目录的详解
    Android 开发 Fresco框架点击小图显示全屏大图实现 ZoomableDraweeView
    Android 开发 将window变暗
    Android 开发 DisplayMetrics获取Android设备的屏幕高宽与其他信息
    Android 开发 DP、PX、SP转换详解
  • 原文地址:https://www.cnblogs.com/java20130723/p/3211366.html
Copyright © 2020-2023  润新知