uboot的Makefile分析

本文详细解析了 U-Boot 的 Makefile 结构,包括版本号定义、编译架构和操作系统的设置、静默编译方法、编译输出路径管理、交叉编译配置等内容。并介绍了 U-Boot 的配置过程及链接脚本生成机制。
摘要由CSDN通过智能技术生成

uboot的Makefile分析

1.uboot的版本号

VERSION = 1   //主版本号

PATCHLEVEL = 3  //次版本号

SUBLEVEL = 4   //第三版本号

EXTRAVERSION =  //另外附加的版本号信息

Makefile最终生成一个变量U_BOOT_VERSION,这个变量记录了makefile配置的版本号。

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

VERSION_FILE = $(obj)include/version_autogenerated.h  //放到此.h中

version_autogenerated.h 是编译过程中自动生成的,里面定义了一个宏,这个宏就是我们Makefile配置的uboot版本号。

例:#define U_BOOT_VERSION "U-Boot 1.3.4" (启动uboot时就会有打印信息)

 

2.HOSTARCH和HOSTOS

HOSTARCH := $(shell uname -m | \

sed -e s/i.86/i386/ \

    -e s/sun4u/sparc64/ \

    -e s/arm.*/arm/ \

    -e s/sa110/arm/ \

    -e s/powerpc/ppc/ \

    -e s/ppc64/ppc/ \

    -e s/macppc/ppc/)

 

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

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

 

export HOSTARCH HOSTOS

由代码可以看出,在shell中执行uname -m可以得到电脑CPU的版本号。Shell中的“|”叫做管道,管道的作用是把前面的输出作为后面的输入,最终个输出是我们整个试子的输出。

HOST + ARCH :表示主机的CPU架构。

 

3.静默编译

为了只打印想要的结果,一般就会静默执行。

# Allow for silent builds

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

XECHO = echo

else

XECHO = :

Endif

使用静默编译的方法为:编译时使用make -s,s会作为MAKEFLAGS传给makefile,XECHO 就会变成空(,前面表示空,有了S就非空),实现了静默编译。


4.两种编译方法

1):默认情况下是在当前编译文件夹下的,o文件会被编译到当前的文件夹中,这种方法叫做原地编译。

优点:处理方法简单。

缺点:是源文件目录变得臃肿,一套源代码只能按照一种配置和编译方法进行处理,无法同时维护2种或2种以上的配置编译方式。

用法:直接默认就行。

2):支持输出文件夹单独输出文件夹的编译。

编译时将输出结果放到同一个目录下,方便管理。

用法:

#U-boot build supports producing a object files to the separate external

# directory. Two use cases are supported:

# 1) Add O= to the make command line

# 'make O=/tmp/build all'

# 2) Set environement variable BUILD_DIR to point to the desired location

# 'export BUILD_DIR=/tmp/build'

# 'make'

# The second approach can also be used with a MAKEALL script

# 'export BUILD_DIR=/tmp/build'

# './MAKEALL'

# Command line 'O=' setting overrides BUILD_DIR environent variable.

ifneq ($(BUILD_DIR),)

saved-output := $(BUILD_DIR)

 

# Attempt to create a output directory.

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

 

# Verify if it was successful.

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

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

endif # ifneq ($(BUILD_DIR),)

 

OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))  //目标文件

SRCTREE := $(CURDIR)   //源文件

TOPDIR := $(SRCTREE)

LNDIR := $(OBJTREE)

export TOPDIR SRCTREE OBJTREE   //导出变量

第一种:make o=输出目录

第二种:export  BUILD_DIR=输出目录,然后再make(如果两种都指定了,那么会执行make o=,此表达会有更高的优先级)

 

4.OBJTREE、SRCTREE、TOPDIR

OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))  //目标文件

SRCTREE := $(CURDIR)   //源文件

TOPDIR := $(SRCTREE)

 

OBJTREE:编译出的.o文件存放的根目录。在默认的情况下,OBJTREE等于当前目录,如果指定相应目录,make o=xx,OBJTREE就是指定的目录。

SRCTREE:源码目录。(在默认情况下OBJTREE和SRCTREE相等)

TOPDIR:源码目录的根目录。

 

5.MKCONFIG

 MKCONFIG是makefile定义的一个变量,它的值就是根目录下的mkconfig,这个makefile是一个脚本,是uboot配置阶段的配置脚本。

 

6.include $(obj)include/config.mk


include $(obj)include/config.mk

export ARCH CPU BOARD VENDOR SOC

 

在配置过程中,也就是make x210_sd_config之后才生成这个文件,在此我们配置的内容为:

ARCH   = arm

CPU    = s5pc11x

BOARD  = x210

VENDOR = samsung

SOC    = s5pc110

最后export导出的5个变量,就是为了给makefile提供了5个环境变量。而这5个变量的来源是通过调用mkconfig脚本后生成的:

x210_sd_config : unconfig

@$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110

@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk

 

7.ARCH CROSS_COMPILE

ARCH:是上面部分导出的,它的值会影响后面的CROSS_COMPILE,意义就是定义当前编译的目标CPU和架构。

 

CROSS_COMPILE:是定义交叉编译工具链的前缀。原因:不同CPU架构上的交叉编译工具链前缀不一样,而他们的后缀一样,因此用前缀区分不同的CPU架构。

例:

ifeq ($(ARCH),arm)

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

经过ARCH提供arm后,就执行后面语句。

在实际运用时,可以在makefile中去更改设置CROSS_COMPILE的值,也可以在编译时用make CROSS_COMPILE=xxxx来设置,而且编译传参可以覆盖makefile里面的配置。

 

9.链接脚本。

include $(TOPDIR)/config.mk,执行uboot根目录下的config.mk脚本,里面定义了工具链的一些符号:

AS = $(CROSS_COMPILE)as

LD = $(CROSS_COMPILE)ld

CC = $(CROSS_COMPILE)gcc

CPP = $(CC) -E

AR = $(CROSS_COMPILE)ar

NM = $(CROSS_COMPILE)nm

LDR = $(CROSS_COMPILE)ldr

STRIP = $(CROSS_COMPILE)strip

OBJCOPY = $(CROSS_COMPILE)objcopy

OBJDUMP = $(CROSS_COMPILE)objdump

RANLIB = $(CROSS_COMPILE)RANLIB

 

而且包含开发板配置项目:

sinclude $(OBJTREE)/include/autoconf.mk

Autoconf.mk解析:这个文件就是在配置过程中生成的,作用就是指导整个uboot编译过程。里面都是CONFIG_定义的宏/变量,这些宏会指导整个编译的流程(原理就是条件编译,uboot中有很多地方使用条件编译,这样使得uboot的移植性更强)。这个文件生成的源材料是源码目录下的inlcude/configs/xxx.h头文件。

 

ifeq ($(CONFIG_NAND_U_BOOT),y)

LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds

else

LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds

Endif

如果定义了CONFIG_NAND_U_BOOT,生成的链接脚本叫做u-boot-nand.lds,如果未定义就会生成u-boot.lds。

 

ifneq ($(TEXT_BASE),)

CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE)

Endif

makefile配置的过程中,在/board/samsung/x210目录下生成一个config.mk文件,其中的内容就是:TEXT_BASE = 0xc3e00000相当于定义了一个变量。

TEXT_BASE是uboot连接时的链接地址,因为uboot中启用了虚拟地址映射,因此这个C3E00000地址就等于0x23E00000(也可能是33E00000具体地址要取决于uboot中做的虚拟地址映射关系)

 

#####################################################################

export CONFIG_SHELL HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE \

AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP \

MAKE

xport TEXT_BASE PLATFORM_CPPFLAGS PLATFORM_RELFLAGS CPPFLAGS CFLAGS AFLAGS

#####################################################################

 

ifndef REMOTE_BUILD

 

%.s: %.S

$(CPP) $(AFLAGS) -o $@ $<

%.o: %.S

$(CC) $(AFLAGS) -c -o $@ $<

%.o: %.c

$(CC) $(CFLAGS) -c -o $@ $<

 

else

 

$(obj)%.s: %.S

$(CPP) $(AFLAGS) -o $@ $<

$(obj)%.o: %.S

$(CC) $(AFLAGS) -c -o $@ $<

$(obj)%.o: %.c

$(CC) $(CFLAGS) -c -o $@ $<

endif

以上就是makefile的自动推导规则。

 

9.all: $(ALL)

目标all。就是默认的目标,在根目录下执行make时,相当make -all,目标生成的可执行文件为elf格式。

 

Uboot的配置过程

1.makefile脚本的6个参数。

smdkv210single_rev02_config : unconfig

@$(MKCONFIG) $(@:_config=) arm s5pc11x smdkc110 samsung s5pc110

@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/smdkc110/config.mk

x210_sd_config里的_config部分用空替换,得到:x210_sd,这就是第一个参数,所以:

$1: x210_sd

$2: arm

$3: s5pc11x

$4: x210

$5: samsumg

$6: s5pc110

所以,$# = 6

 

while [ $# -gt 0 ] ; do

case "$1" in

--) shift ; break ;;

-a) shift ; APPEND=yes ;;

-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;

*)  break ;;

esac

Done

 

Maconfig的内容:

[ "${BOARD_NAME}" ] || BOARD_NAME="$1"  //判断BOARD_NAME是否有值。

 

[ $# -lt 4 ] && exit 1

[ $# -gt 6 ] && exit 1

mkconfig脚本传参只能是4、5、6,如果大于6或者小于4都不行。

往后的:

ifeq ($(ARCH),arm)

#CROSS_COMPILE = arm-linux-

#CROSS_COMPILE = /usr/local/arm/4.4.1-eabi-cortex-a8/usr/bin/arm-linux-

#CROSS_COMPILE = /usr/local/arm/4.2.2-eabi/usr/bin/arm-linux-

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

Endif

.............

以上都是在创建符号链接,创建的这些符号链接是整个配置过程是核心,这些符号链接文件(文件夹)的主要作用是给头文件包含等过程提供指向性连接。根本目的是让uboot具有可移植性。

 

创建的符号链接:

if [ "$SRCTREE" != "$OBJTREE" ] ; then

mkdir -p ${OBJTREE}/include

mkdir -p ${OBJTREE}/include2

cd ${OBJTREE}/include2

rm -f asm

ln -s ${SRCTREE}/include/asm-$2 asm  (第一个)

LNPREFIX="../../include2/asm/"

cd ../include

rm -rf asm-$2

rm -f asm

mkdir asm-$2

ln -s asm-$2 asm

else

cd ./include

rm -f asm

ln -s asm-$2 asm

fi

 

rm -f asm-$2/arch

 

if [ -z "$6" -o "$6" = "NULL" ] ; then

ln -s ${LNPREFIX}arch-$3 asm-$2/arch  

else

ln -s ${LNPREFIX}arch-$6 asm-$2/arch  //第二个

Fi

 

if [ "$2" = "arm" ] ; then

rm -f asm-$2/proc

ln -s ${LNPREFIX}proc-armv asm-$2/proc  //第三个

Fi

 

if [ "$3" = "s5pc1xx" ] ; then

        rm -f regs.h

        ln -s $6.h regs.h

        rm -f asm-$2/arch

        ln -s arch-$3 asm-$2/arch  //第四个

Fi

 

if [ "$2" = "arm" ] ; then

rm -f asm-$2/proc

ln -s ${LNPREFIX}proc-armv asm-$2/proc  //第五个

Fi

 

第一个:在include目录下创建asm文件,指向asm-arm。

第二个:在include/asm-arm下创建一个arch文件,指向include/asm-arm/arch-s5pc110。

第三个:在include目录下创建regs.h文件,指向include/s5pc110.h删除第二个。

第四个:在include/asm-arm下创建一个arch文件,指向include/asm-arm/arch-s5pc11x

第五个:在include/asm-arm下创建一个proc文件,指向include/asm-arm/Proc-armv

总结:一共创建了4个符号链接。这4个符号链接将来在写代码过程中,头文件包含时非常有用。譬如一个头文件包含可能是:#include <asm/xx.h>

 

创建include/config.mk文件

echo "ARCH   = $2" >  config.mk

echo "CPU    = $3" >> config.mk

echo "BOARD  = $4" >> config.mk

 

[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk

[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC    = $6" >> config.mk

创建include/config.mk文件是为了让主Makefile在第133行去包含的。

 

x210_sd.h文件会被用来生成一个autoconfig.mk文件,这个文件会被主Makefile引入,指导整个编译过程。

 

Uboot的连接脚本

ENTRY(_satrt)

用来指定整个程序的入口,想C语言的main。

2种指定程序的连接地址:一种是makefile中ld的flags用-Ttext  0x20000000

来指定;第二种是在连接脚本的SECTIONS开头用.=0x2000000,来指定。如果两种指定,那么会以-Ttext为准。

uboot的最终链接起始地址就是在Makefile中用-Ttext 来指定的,TEXT_BASE变量。最终来源是Makefile中配置对应的命令中,在make xxx_config时得到的。

 

在代码段中要注意文件的排列的顺序,指定必须放在前面部分的那些文件就是那些必须安排在16kb的文件,这些文件会在前16kb被调用,后面的16k的顺序就不那么重要了。

连接脚本这跑那个除了.text .data .rodata  bss等编译器工具自带的段以外,编译工具还允许我们自定义段,譬如uboot总的.u_boot_cmd段就是自定义段。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值