uboot筆記-Makefile文件分析

uboot筆記-Makefile文件分析

這裏使用九鼎X210開發板的uboot來做分析。uboot版本號u-boot 1.3.4

VERSION = 1
PATCHLEVEL = 3
SUBLEVEL = 4
EXTRAVERSION =
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
VERSION_FILE = $(obj)include/version_autogenerated.h
  • 這裏定義uboot的版本號和配置uboot時,存儲版本號的頭文件路徑
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

#Deal with colliding definitions from tcsh etc.
VENDOR=
  • HOSTARCH-這裏定義主機系統架構和操作系統,使用ubuntu和intel的電腦的情況下一般是i386和i686,這裏sed指令後面的i.86中的.是通配符,這裏滿足所有i.86的宿主機都改爲i386
  • 這裏中間的|是管道符,表示將前面的參數傳遞給後面使用。
  • HOSTOS-定義宿主機的操作系統,使用ubuntu系統的話,這裏的操作系統是Linux,然後後面將所有字符轉換爲大寫,然後再轉換爲小寫,最後宿主機操作系統名稱爲linux
  • export將宿主機型號和操作系統聲明爲全局變量,供其他文件使用
  • VENDOR設置廠商,這裏設置爲空
#Allow for silent builds
ifeq (,$(findstring s,$(MAKEFLAGS)))
XECHO = echo
else
XECHO = :
endif
  • 這裏是檢測是否需要靜默編譯,如果需要靜默編譯,在make後面加上-s,默認不加-s則會在編譯時打印編譯信息。這裏MAKEFLAGS表示在執行makefile的時候,在make後面添加的標誌,如果沒有找到s,則定義XECHO爲echo,否則定義XECHO爲空(這裏:在bash中表示空命令,只起到佔位符的作用)
#########################################################################
#
#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.
#
#When none of the above methods is used the local build is performed and
#the object files are placed in the source directory.
#

ifdef O
ifeq ("$(origin O)", "command line")
BUILD_DIR := $(O)
endif
endif

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

MKCONFIG	:= $(SRCTREE)/mkconfig
export MKCONFIG

ifneq ($(OBJTREE),$(SRCTREE))
REMOTE_BUILD	:= 1
export REMOTE_BUILD
endif

#$(obj) and (src) are defined in config.mk but here in main Makefile
#we also need them before config.mk is included which is the case for
#some targets like unconfig, clean, clobber, distclean, etc.
ifneq ($(OBJTREE),$(SRCTREE))
obj := $(OBJTREE)/
src := $(SRCTREE)/
else
obj :=
src :=
endif
export obj src

#Make sure CDPATH settings don't interfere
unexport CDPATH

#########################################################################
  • 這裏主要是確定源程序文件夾路徑和生成的目標文件存放的路徑。正常情況下,生成的目標文件和源文件存放在同一個文件夾下,但是我們可以指定obj文件存放的路徑。使用方法是make O=/tmp/build all
  • 這裏主要關注src和obj這兩個變量,src存儲源文件路徑,obj存儲目標文件的路徑,在沒有設置obj的情況下,obj和src目錄相同。
#load ARCH, BOARD, and CPU configuration
include $(obj)include/config.mk
export	ARCH CPU BOARD VENDOR SOC
  • 這裏包含了一個config.mk文件,這個文件在uboot源碼裏面找不到,是我們在配置uboot時生成的(從obj這個變量也可以看出是在編譯的時候生成的)具體在配置的哪個階段生成的?還需要看配置過程(具體參考mkconfig腳本文件)。

  • config.mk具體內容如下

ARCH   = arm
CPU    = s5pc11x
BOARD  = x210
VENDOR = samsung
SOC    = s5pc110
  • 這裏包含了config.mk文件後,將ARCH、CPU、BOARD、VENDOR、SOC聲明爲全局變量,這裏面主要是配置相關的內容。關於config.mk的生成過程如下。

    #### 1.1 config.mk文件的生成過程

    在配置uboot的時候,使用命令make x210_sd_config,該命令執行了makefile中x210_sd_config目標,該目標的定義如下:

MKCONFIG	:= $(SRCTREE)/mkconfig
export MKCONFIG

unconfig:
   @rm -f $(obj)include/config.h $(obj)include/config.mk \
   	$(obj)board/*/config.tmp $(obj)board/*/*/config.tmp \
   	$(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep \
   	$(obj)board/$(VENDOR)/$(BOARD)/config.mk
x210_sd_config :	unconfig
   @$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110
   @echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk

X210_sd_config有一個依賴,因此,在執行目標時,先執行該依賴,unconfig依賴主要清除了舊的配置文件,然後執行新的配置,配置過程如下:

  • 首先MKCONFIG表示頂層目錄下mkconfig腳本,這裏執行mkconfig腳本,並且給該腳本傳遞6個參數,這六個參數分別是

    • x210_sd – $(@:_config=),表示把目標中的_config替換成=號後面的空(即刪除_config)
    • arm
    • s5pc11x
    • x210
    • samsung
    • S5pc110
  • 執行第二句,在board/samsung/x210文件夾下面新建一個config.mk文件,並將字符串TEXT_BASE = 0xc3e00000寫入文件中

    1.2 mkconfig腳本分析

    mkconfig腳本實現了uboot配置階段的大部分工作。

APPEND=no	# Default: Create new config file
BOARD_NAME=""	# Name to print in make output

while [ $# -gt 0 ] ; do
   case "$1" in
   --) shift ; break ;;
   -a) shift ; APPEND=yes ;;
   -n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
   *)  break ;;
   esac
done

[ "${BOARD_NAME}" ] || BOARD_NAME="$1"

[ $# -lt 4 ] && exit 1
[ $# -gt 6 ] && exit 1

echo "Configuring for ${BOARD_NAME} board..."
- 這裏我們沒有給mkconfig文件傳遞-- -a -n等參數,因此,在while中匹配\*,執行break,跳出while循環
- BOARD\_NAME沒有定義,是空,因此,\[ "${BOARD\_NAME}" ]結果是false,需要執行後面的語句,BOARD\_NAME的值爲傳遞的第一個參數,即X210\_sd
- 參數小於4個或者大於六個,就返回1,表示錯誤
- 最後打印出配置提示文本
#
#Create link to architecture specific headers
#
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
- 這裏判斷目標文件和源文件是否在同一目錄,在同一個目錄執行else,不在同一個目錄執行then後面的,這裏我們在同一個目錄,則進入到./include文件夾下,刪除asm文件,然後給asm-arm文件創建符號鏈接asm
- 刪除asm-arm文件夾下面的arch文件
- 判斷第六個參數是否爲空,這裏不爲空,就給arch-s5pc110建立符號鏈接asm-arm/arch
#create link for s5pc11x SoC
if [ "$3" = "s5pc11x" ] ; then
        rm -f regs.h
        ln -s $6.h regs.h
        rm -f asm-$2/arch
        ln -s arch-$3 asm-$2/arch
fi
- 這裏判斷$3爲s5pc11x,則會刪除regs.h,給s5pc110.h建立regs.h符號鏈接
- 刪除asm-arm/arch文件,然後給arch-s5pc11x 建立符號鏈接asm-arm/arch
if [ "$2" = "arm" ] ; then
	rm -f asm-$2/proc
	ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi
- 這裏給asm-arm/proc-armv創建符號鏈接asm-arm/proc
#
#Create include file for Make
#
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
- 這裏創建config.mk文件,並向裏面寫入ARCH、CPU、BOARD、VENDOR、SOC,這個文件就是主Makefile包含的文件(上文分析的文件)
#
#Create board specific header file
#
if [ "$APPEND" = "yes" ]	# Append to existing config file
then
	echo >> config.h
else
	> config.h		# Create new config file
fi
echo "/* Automatically generated - do not edit */" >>config.h
echo "#include <configs/$1.h>" >>config.h

exit 0
- 這裏在include文件夾下創建config.h頭文件,並向裏面寫入`#include <configs/s210_sd.h>`
- 執行完之後,`exit 0`返回,表示執行成功

分析完mkconfig文件之後,可以返回主Makefile繼續分析剩餘部分。

ifndef CROSS_COMPILE
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE =
else
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
endif	# HOSTARCH,ARCH
endif	# CROSS_COMPILE

export	CROSS_COMPILE
  • 這段主要是定義交叉編譯工具鏈路徑及前綴,如果交叉編譯工具已經導出到環境變量,也可以使用環境變量定義的前綴名,主要給瞎mainconfig.mk文件中定義編譯工具使用。
#load other configuration
include $(TOPDIR)/config.mk
  • 這裏包含另一個makefile文件–config.mk
  • config.mk文件中主要是和編譯器編譯鏈接相關的一些東西,這裏只看和我們相關的
#
#Include the make variables (CC, etc...)
#
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
  • 這些變量定義編譯器相關工具
#Load generated board configuration
sinclude $(OBJTREE)/include/autoconf.mk
  • 包含開發板配置文件autoconf.mk,該文件是在uboot編譯的時候自動生成的,打開裏面的部分內容如下:
CONFIG_CMD_FAT=y
CONFIG_USB_OHCI=y
CONFIG_SYS_CLK_FREQ=24000000
CONFIG_CMD_ITEST=y
CONFIG_S3C_HSMMC=y
CONFIG_DISPLAY_BOARDINFO=y
CONFIG_CMD_XIMG=y
CONFIG_CMD_CACHE=y
CONFIG_STACKSIZE="0x40000"
CONFIG_BOOTDELAY=3
CONFIG_CHECK_MPLL_LOCK=y
CONFIG_NR_DRAM_BANKS=2
CONFIG_ETHADDR="00:40:5c:26:0a:5b"
CONFIG_CMD_CONSOLE=y
CONFIG_SW_WORKAROUND=y
CONFIG_GATEWAYIP="192.168.0.1"
CONFIG_DRIVER_DM9000=y
CONFIG_ZIMAGE_BOOT=y
CONFIG_CMD_REGINFO=y
CONFIG_MMC=y
CONFIG_NAND_BL1_8BIT_ECC=y
CONFIG_CMD_MISC=y
CONFIG_ZERO_BOOTDELAY_CHECK=y
CONFIG_ENV_OVERWRITE=y
CONFIG_CMD_NET=y
CONFIG_CMD_NFS=y
  • 從上面可以看出,裏面包含的都是CONFIG_開頭的變量,這些變量就來源於x210_sd.h文件中的宏定義
ifdef	ARCH
sinclude $(TOPDIR)/$(ARCH)_config.mk	# include architecture dependend rules
endif
ifdef	CPU
sinclude $(TOPDIR)/cpu/$(CPU)/config.mk	# include  CPU	specific rules
endif
ifdef	SOC
sinclude $(TOPDIR)/cpu/$(CPU)/$(SOC)/config.mk	# include  SoC	specific rules
endif
ifdef	VENDOR
BOARDDIR = $(VENDOR)/$(BOARD)
else
BOARDDIR = $(BOARD)
endif
ifdef	BOARD
sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk	# include board specific rules
endif
  • 這些文件包含了編譯器相關的屬性定義
ifndef LDSCRIPT
#LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds.debug
ifeq ($(CONFIG_NAND_U_BOOT),y)
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds
else
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds
endif
endif
  • 這裏如果定義了CONFIG_NAND_U_BOOT,鏈接腳本就使用u-boot-nand.lds,我們這裏沒有定義,因此使用u-boot.lds作爲鏈接腳本
LDFLAGS += -Bstatic -T $(LDSCRIPT) $(PLATFORM_LDFLAGS)
ifneq ($(TEXT_BASE),)
LDFLAGS += -Ttext $(TEXT_BASE)
endif
  • 這裏如果定義了TEXT_BASE,則在鏈接屬性中添加TEXT_BASE作爲鏈接地址
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,接着往下,就是make編譯的目標(這裏只截取部分代碼)

ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND) $(obj)u-boot.dis
ifeq ($(ARCH),blackfin)
ALL += $(obj)u-boot.ldr
endif

all:		$(ALL)

$(obj)u-boot.hex:	$(obj)u-boot
		$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@

$(obj)u-boot.srec:	$(obj)u-boot
		$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
########以下部分省略

這就是make執行uboot編譯的時候執行的目標文件,執行整個uboot的編譯鏈接過程,最終生成uboot.bin文件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章