zoukankan      html  css  js  c++  java
  • uboot主Makefile解析第二篇

    这篇主要分析Makefile文件开头部分对与一些编译环境以及编译路径等变量的初始化

    VERSION = 2010

    PATCHLEVEL = 12

    SUBLEVEL =

    EXTRAVERSION =

    ifneq "$(SUBLEVEL)"""

    U_BOOT_VERSION =$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)

    else

    U_BOOT_VERSION =$(VERSION).$(PATCHLEVEL)$(EXTRAVERSION)

    Endif

    U_BOOT_VERSION = 2010.12

    TIMESTAMP_FILE =$(obj)include/timestamp_autogenerated.h

    VERSION_FILE = $(obj)include/version_autogenerated.h

    HOSTARCH := $(shell uname -m |

             sed-e s/i.86/i386/

                 -e s/sun4u/sparc64/

                 -e s/arm.*/arm/

                 -e s/sa110/arm/

                 -e s/ppc64/powerpc/

                 -e s/ppc/powerpc/

                 -e s/macppc/powerpc/

                 -e s/sh.*/sh/)

    $(shell uname -m)表示执行uname –m的shell命令,他执行的结果是取出机器硬件名(这台机器是64位的,所以其得到的结果就是x86-84)。sed –e s/abc/def 的意思是寻找结果里面是否有’abc’字样,如果有,就用‘def’字样将其代替。

    所以整条语句的意思就是,取出uname –m的结果,并在其中寻找是否有i.86字样,如果有就用i386代替,是否有arm.*(*是通配符),如果有,就用arm代替……,本台机的结果是x86-64所以还保持原样,没有用其他字符替换,所以HOSTARCH=x86-64

    HOSTOS := $(shell uname -s | tr'[:upper:]' '[:lower:]' |

                sed -e 's/cygwin.*/(cygwin/')

      

    uname –s 表示取出本机操作系统内核名称,(这台机器是Linux),tr ‘[:upper:]’’[:lower:]’表示将结果里面的大写字符全部换成小写字符,sed –e‘s/Cygwin.*/Cygwin/’表示寻找结果里面是否有cygwin.*字符,如果有就用cygwin替换

    所以整句话的结果就是HOSTOS = linux(注意第一个字母L被换成了小写l)

    SHELL := $(shell if [ -x "

    BASH"];thenecho

    BASH;

          else if [-x /bin/bash];then echo /bin/bash;

         else echosh;fi;fi

           

    SHELL if[-x filename]   表示如果这个filename文件是可执行的,则为真,显然BASH变量是空的,则SHELL= /bin/bash  就是说shell命令的路径位于/bin/bash目录下

    export       HOSTARCH HOSTOS SHELL 

    表示将这些变量导出,供别的文件使用

    ifeq (,$(findstring s,$(MAKEFLAGS)))

    XECHO = echo

    else

    XECHO = :

    Endif

    If$( findstring string,text )表示从text中寻找string字样,如果找到了则返回text,如果没找到就返回空,显然MAKEFLAGS为空,所以 $(findstring s,$(MAKEFLAGS)) 返回为空,if语句为真,XECHO =echo,执行非静默编译,否则,执行静默编译(静默编译的意思就是在编译时控制台不打印任何信息)

    ifdef O

    ifeq ("$(origin O)", "commandline")

    BUILD_DIR := $(O)

    endif

    endif

    这句话表示如果在编译的命令里面加入参数O(如 make O=/tmp).,就把O后面所指定的值赋给变量BUILD_DIR,(BUILD_DIR表示uboot的编译路径)

    ifneq ($(BUILD_DIR),)

    saved-output := $(BUILD_DIR)

    如果BUILD_DIR不为空,则将BUILD_DIR的值赋给saved-output

    $(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})

    如果BUILD_DIR是一个目录名称,就把该目录创建出来

    BUILD_DIR := $(shell cd $(BUILD_DIR) &&/bin/pwd)

    $(if $(BUILD_DIR),,$(error output directory"$(saved-output)" does not exist))

    Endif

    shell命令的意思是先进入到BUILD_DIR目录,然后调用PWD命令显示当前路径名,并把当前路径名赋给BUILD_DIR变量,If语句判断BUILD_DIR是否存在,如果还为空就显示错误(命令里面两个逗号之间表示空)

    OBJTREE            :=$(if $(BUILD_DIR),$(BUILD_DIR),$(CURIDR)) //输出目录

    SRCTREE             :=$(CURDIR) //源码目录

    TOPDIR                :=$(SRCTREE)  //顶层目录

    LNDIR                  :=$(OBJTREE) //连接目录

    export        TOPDIR SRCTREE OBJTREE

    先看CURIDR变量,这是一个MAKEFILE的内嵌变量,代表当前路径,为了验证,可以如下做个测试:

         在/tmp/test目录下新建一个Makefile文件,在里面添加如下内容:

        all::

                   @echo $(CURDIR)

         

             然后在/tmp/test路径下执行Make命令,显示的就是/tmp/test

    如果定义了BUILD_DIR,就将BUILD_DIR赋给OBJTREE,如果没有定义,就将CURIDR赋给OBJTREE

    ……

    所以如果编译时没有定义编译路径,及没有定义BUILD_DIR,则以上所有变量都是CURDIR,即当前目录,也就是uboot的顶层目录

    MKCONFIG        :=$(SRCTREE)/mkconfig) 

    export MKCONFIG

    ifneq ($(OBJTREE),$(SRCTREE))

    REMOTE_BUILD  := 1 

    export REMOTE_BUILD

    endif

    如果源码目录与输出目录不想等,则置位REMOTE_BUILD变量

    ifneq ($(OBJTREE),$(SRCTREE))

    obj := $(OBJTREE)/

    src := $(SRCTREE)/

    else

    obj :=

    src :=

    endif

    export obj src

    如果源码目录和输出目录不想等,则变量obj和src被赋予相应的值,否则,两变量都为空

    SUBDIRS   =tools

              examples/standalone

             examples/api

              

    .PHONY : $(SUBDIRS)

    SUBIDRS被赋予了三个路径名称,并申明SUBIDRS是一个伪目标

    这篇主要分析跟编译和连接库文件相关的变量

    ifeq ($(obj)include/config.mk,$(wildcard $(obj)include/config.mk))

    ……

    else   # !config.mk

    all $(obj)u-boot.hex $(obj)u-boot.srec $(obj)u-boot.bin

    $(obj)u-boot.img $(obj)u-boot.dis $(obj)u-boot

    $(filter-out tools,$(SUBDIRS)) $(TIMESTAMP_FILE) $(VERSION_FILE)

    updater depend dep tags ctags etags cscope $(obj)System.map:

             @echo "System not configured - see README" >&2

             @ exit 1

    tools:

             $(MAKE) -C $@ all

    endif # config.mk

    ifeq语句判断include目录下是否存在config.mk文件(通过《uboot系列之-----uboot配置过程详细分析》一文可知,只有执行了make xxx_config之后,才存在该文件)。

    我们暂时不分析config.mk存在时的情况,因为太长了,先分析config.mk不存在的情况,即else后的语句,该语句把所有的目标都指向了一个依赖,就是打印出错信息“System not configured – see README”,然后退出。

    接下来看config.mk存在的情况:

    all:

    sinclude $(obj)include/autoconf.mk.dep

    sinclude $(obj)include/autoconf.mk

    先看目标all: 从makefile开始到现在,发现这个all是第一个目标,也就是说当我们执行make命令时,它是默认目标,但是该目标既没有依赖也没有规则,那它起到什么作用呢?接着往下看,sinclude $(obj)include/autoconf.mk.dep,他的意思是包含autoconf.mk.dep文件,进入到该文件,发现第一句是:

    include/autoconf.mk: include/common.h ,它也是一个目标,并且有很多的依赖

    再回到all的作用上来,如果没有这个all,那么当我们执行make 时,根据make法则,(它将第一个目标作为他的默认目标),也就是将autoconf.mk作为默认目标,显然这不是我们想要的结果,(我们执行make是想编译整个文件,也就是执行第365行的all: $(ALL)这个规则,而在这里加上一个看起来“毫无意义”的all,就能达到我们想要的目的,即执行第一个空的all目标后,会跳过autoconf.mk目标,执行下一个all目标)

    再来看sinclude ,sinclude也是包含文件的关键词,他与include的区别就是使用sinclude时,即使所需要包含的文件不存在,也不影响makefile的往下执行。

    而autoconf.mk.dep和autoconf.mk这两个文件是怎么来的呢,在makefile中有如下一段语句,说明了这两个文件的来源:

    $(obj)include/autoconf.mk.dep: $(obj)include/config.h include/common.h

             @$(XECHO) Generating $@ ;

             set -e ;

             : Generate the dependancies ;

             $(CC) -x c -DDO_DEPS_ONLY -M $(HOSTCFLAGS) $(CPPFLAGS)

                       -MQ $(obj)include/autoconf.mk include/common.h > $@

    $(obj)include/autoconf.mk: $(obj)include/config.h

             @$(XECHO) Generating $@ ;

             set -e ;

             : Extract the config macros ;

             $(CPP) $(CFLAGS) -DDO_DEPS_ONLY -dM include/common.h |

                       sed -n -f tools/scripts/define2mk.sed > $@.tmp &&

             mv $@.tmp $@

    这段规则没有完全看明白,望大侠们帮我分析一下

    include $(obj)include/config.mk

    export        ARCH CPU BOARD VENDOR SOC

    包含配置过程中生成的config.mk文件,并把该文件中的变量导出来

    ifeq ($(ARCH),arm)

    CROSS_COMPILE =/usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-

    Endif

    如果ARCH=arm,即体系架构为ARM ,就给变量CROSS_COMPILE赋值,改变量的值代表了交叉编译器的路径

    include $(TOPDIR)/config.mk

    包含顶层目录下的config.mk文件

    下面开始定义了目标文件变量(跟ARM无关的这里就省略没有列出来)

    OBJS  = $(CPUDIR)/start.o

    这里的CPUDIR目录在顶层目录的config.mk文件里面定义 CPUDIR=arch/$(ARCH)/cpu/$(CPU),对于smdk4412来说CPUDIR= arch/arm/cpu/armv7

    ……

    OBJS := $(addprefix $(obj),$(OBJS))

    在原有OBJS值前面加上一个路径$(obj)前缀,指明绝对路径,如果$(obj)为空,则OBJS相当于没变化

    下面开始定义了库文件变量(跟硬件平台无关的这里就省略没有列出来)

    …….

    LIBS += $(shell if [ -f board/$(VENDOR)/common/Makefile ]; then echo

             "board/$(VENDOR)/common/lib$(VENDOR).o"; fi)

    LIBS += $(CPUDIR)/lib$(CPU).o

    ifdef SOC

    LIBS += $(CPUDIR)/$(SOC)/lib$(SOC).o

    Endif

    对于smdk4412来说,board/Samsung/common/Makefile文件并不存在,所以第一个赋值无效,接下来的两个分别为

    LIBS+= arch/arm/cpu/armv7/libarmv7.o

    LIBS+= arch/arm/cpu/armv7/exynos/libexynos.o

    …..

    LIBS += arch/$(ARCH)/lib/lib$(ARCH).o

    LIBS+= arch/arm/lib/libarm.o

    ifeq ($(SOC),exynos)

    LIBS += $(CPUDIR)/s5p-common/libs5p-common.o

    Endif

    LIBS+= arch/arm/cpu/armv7/s5p-common/libs5p-common.o

    LIBBOARD = board/$(BOARDDIR)/lib$(BOARD).o

    LIBBOARD := $(addprefix $(obj),$(LIBBOARD))

    BOARDDIR定义在顶层目录的config.mk文件中  BOARDDIR = $(VENDOR)/$(BOARD) 对于smdk4412来说

    BOARDDIR = Samsung/smdk4212

    LIBBOARD = board/samsung/smdk4212/libsmdk4212.o

    PLATFORM_LIBGCC = -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) –lgcc

    PLATFORM_LIBS += $(PLATFORM_LIBGCC)

    export PLATFORM_LIBS

    dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`取得交叉编译器的libgcc.a的绝对路径

    $(CC) = $(CROSS_COMPILE)gcc

    $(CFLAGS)定义在config.mk

    -L表示编译时将其后所跟的目录作为第一个寻找库文件的目录

    LDPPFLAGS +=

             -include $(TOPDIR)/include/u-boot/u-boot.lds.h

             $(shell $(LD) --version |

               sed -ne 's/GNU ld version [09][09].[09][09].*/-DLD_MAJOR=1 -DLD_MINOR=2/p')

    $(LD)定义在顶层目录的config.mk文件

    LD= $(CROSS_COMPILE)ld,表示交叉编译器里面的连接工具

    shell $(LD) –version表示取得连接工具的版本,我这里的版本号是”GNU ld (GNU Binutils for Ubuntu) 2.22”

    ifeq ($(CONFIG_NAND_U_BOOT),y)

    NAND_SPL = nand_spl

    U_BOOT_NAND = $(obj)u-boot-nand.bin

    endif

    ifeq ($(CONFIG_ONENAND_U_BOOT),y)

    ONENAND_IPL = onenand_ipl

    U_BOOT_ONENAND = $(obj)u-boot-onenand.bin

    ONENAND_BIN ?= $(obj)onenand_ipl/onenand-ipl-2k.bin

    endif

    __OBJS := $(subst $(obj),,$(OBJS))

    __LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))

    $subst(<from>,<to>,<text>)的功能是将<text>中的<from>字符串换成<to>字符串

    __OBJS相当于截取OBJS的相对路径,__LIBS类似

    本篇主要分析目标文件以及相关的依赖文件

    ALL += $(obj)u-boot.srec $(obj)u-boot.bin$(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND)

    all:              $(ALL)

    当用make命令编译时,执行的就是这个all变量

    $(obj)u-boot.hex:         $(obj)u-boot

                       $(OBJCOPY)${OBJCFLAGS} -O ihex $< $@

    Vuboot.hex是hex格式的文件。它的依赖u-boot属于ELF文件,OBJCOPY和OBJCFLAGS定义在顶层config.mk文件,

    OBJCOPY = $(CROSS_COMPILE)objcopy ;objcopy命令的作用是将一种格式的文件拷贝成另外一种格式的文件。

    OBJCFLAGS += --gap-fill=0xff;   --gap-fill = 0xff是objcopy的参数,表示在拷贝过程中,用0xff来填充段与段之间的空隙。

    $<表示所有的依赖,即u-boot文件,$@表示所有的目标,即u-boot.hex

    整句话的意思就是将u-boot拷贝成u-boot.hex 

    $(obj)u-boot.srec:        $(obj)u-boot

                       $(OBJCOPY)-O srec $< $@

    类似的,将u-boot拷贝成u-boot.srec文件

    $(obj)u-boot.bin: $(obj)u-boot

                       $(OBJCOPY)${OBJCFLAGS} -O binary $< $@

                       $(BOARD_SIZE_CHECK)

    ifeq ($(CONFIG_S5PC210),y)

                       ./mkbl2u-boot.bin bl2.bin 14336

    Endif

    将u-boot拷贝成u-boot.bin文件,同时执行$(BOARD_SIZE_CHECK),在Makefile前面部分,有如下语句定义了BOARD_SIZE_CHECK:

    ifneq($(CONFIG_BOARD_SIZE_LIMIT),)

    BOARD_SIZE_CHECK=

             @actual='wc -d $@ |awk '{print $$!}';

             limit=$(CONFIG_BOARD_SIZE_LIMIT);

            if test

    actual=gt

    limit; then

                     echo "$@ exceeds file size limit:";

                     echo "limit:$$limit bytes";

                    echo "actual: $$actual bytes";

                    echo "excess:$$((actual-limit))bytes";

                    exit 1;

            fi

    else

    BOARD_SIZE_CHECK =

    Endif

    首先看CONFIG_BOARD_SIZE_LIMIT是否被定义了(是否定义了,在autoconf.mk文件中查看,它的意思是规定了文件大小的上限),如果没定义,BOARD_SIZE_CHECK为空,如果定义了,就比较目标文件的实际大小与他的上限大小(CONFIG_BOARD_SIZE_LIMIT的值),如果前者大于后者,就退出,如前者小于后者,则继续执行。

    接着分析上面蓝色字体的部分

    如果在autoconf.mk中定义了CONFIG_S5PC210 = y,则执行mkbl2命令,这个命令是干嘛的呢?目前还不清楚

    $(obj)u-boot.ldr: $(obj)u-boot  

                   $(CREATE_LDR_ENV)

                   $(LDR)-T $(CONFIG_BFIN_CPU)-c $@ $<$(LDR_FLAGS)

                   $(BOARD_SIZE_CHECK)

    生成u-boot.ldr文件

    $(obj)u-boot.ldr.hex:  $(obj)u-boot.ldr 

                       $(OBJCOPY)${OBJCFLAGS}-O ihex $<$@ -I binary

                      

    $(obj)u-boot.ldr.srec: $(obj)u-boot.ldr 

                        $(OBJCOPY)${OBJCFLAGS} -O srec $< $@ -I binary

    生成u-boot.ldr.hex和u-boot.ldr.sec文件

    $(obj)u-boot.img:         $(obj)u-boot.bin

                       $(obj)tools/mkimage -A $(ARCH) -T firmware -C none

                      -a$(CONFIG_SYS_TEXT_BASE) -e 0

                      -n$(shell sed -n -e 's/.*U_BOOT_VERSION//p'$(VERSION_FILE)|

                              sed -e 's/''[]*$$/for $(BOARD)board''/' )

                      -d$<$@

                      

    Mkimage是给u-boot.bin增加0x40个字节大小的头部信息的工具,其各个参数的意义如下:

      -A 所支持的体系架构,这里是arm

      -T  镜像类型

      -C none  不压缩

      -a  指定映像在内存中的加载地址,映像下载到内存中的时候,要按照这个参数来加载

      -e   指定映像运行的入口地址

      -n   指定映像名称

      -d   指定生成映像的源文件

    $(obj)u-boot.imx:     $(obj)u-boot.bin 

                       $(obj)tools/mkimage -n $(IMX_CONFIG) -T imximage

                       -e $(CONFIG_SYS_TEXT_BASE) -d $<$@

    $(obj)u-boot.kwb:      $(obj)u-boot.bin

                       $(obj)tools/mkimage -n $(CONFIG_SYS_KWD_CONFIG) -T kwbimage

                       -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) -d $<$@

    类似于上面

    $(obj)u-boot.dis:$(obj)u-boot

                       $(OBJDUMP) -d $< > $@

    通过u-boot文件生成u-boot.dis  (u-boot.dis是u-boot的反汇编代码)

    GEN_UBOOT =

                      UNDEF_SYS='$(OBJDUMP) -x $(LIBBOARD) $(LIBS)|

                     sed -n -e 's/.*SYM_PREFIX)__u_boot_cmd_.*/-u1/p'sprt|uniq;

                     cd $(LDR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS)

                         --start-group $(__LIBS) --end-group $(P;ATFORM_LIBS)

                            -Map u-boot.map -o u-boot

                      

    由连接工具生成u-boot文件,并生成映射文件u-boot.map,具体的细节我也没看很懂

    $(obj)u-boot: depend

                      $(SUBDIRS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds

                      $(GEN_UBOOT)

    这个是ELF格式的u-boot文件生成规则,后面那些变量都是它的依赖

    先看depend

    depend dep:     $(TIMESTAMP_FILE) $(VERSION_FILE)  

                        $(obj)include/autoconf.mk

                        $(obj)include/generated/generic -asm-foosets.h

                       for dir in $(SUBDIRS) $(CPUDIR) $(dir $(LDSCRIPT));do

                                   $(MAKE) -C $$ dir _depend;done

    依次进入到$(SUBDIRS)$(CPUDIR)和$(dir $(LDSCRIPT))目录,执行make _depend命令。_depend定义在顶层目录的rules.mk文件中,总的说来,依赖depend就是在相关的目录下生成.depend文件,.depend文件的内容列出了每个目标文件的依赖文件

    UBOOT的Makefile至此就大致分析完了,可能还有些地方说的不是很明白,望大家指正,接下来就要分析源码了

  • 相关阅读:
    DRUPAL-PSA-CORE-2014-005 && CVE-2014-3704 Drupal 7.31 SQL Injection Vulnerability /includes/database/database.inc Analysis
    WDCP(WDlinux Control Panel) mysql/add_user.php、mysql/add_db.php Authentication Loss
    Penetration Testing、Security Testing、Automation Testing
    Tomcat Server Configuration Automation Reinforcement
    Xcon2014 && Geekpwn2014
    phpMyadmin /scripts/setup.php Remote Code Injection && Execution CVE-2009-1151
    Linux System Log Collection、Log Integration、Log Analysis System Building Learning
    The Linux Process Principle,NameSpace, PID、TID、PGID、PPID、SID、TID、TTY
    Windows Management Instrumentation WMI Security Technology Learning
    IIS FTP Server Anonymous Writeable Reinforcement, WEBDAV Anonymous Writeable Reinforcement(undone)
  • 原文地址:https://www.cnblogs.com/AndyChen1/p/8339991.html
Copyright © 2011-2022 走看看