总结于朱有鹏老师的嵌入式课程,感谢朱老师
VERSION = 1 //主板本号
PATCHLEVEL = 3 //次版本号
SUBLEVEL = 4 //再次版本号
EXTRAVERSION = //另外附加的版本信息
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)//记录了Makefile中配置的版本号
VERSION_FILE = $(obj)include/version_autogenerated.h //宏定义了我们在Makefile中配置的uboot的版本号
HOSTARCH := $(shell uname -m | \ //uname -m得到电脑的CPU的版本号
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/') //得出系统版本,如linux
export HOSTARCH HOSTOS
ifeq (,$(findstring s,$(MAKEFLAGS))) //在执行编译的那条指令如make -s 中寻找是否有s。这里是判断与空是否相等
XECHO = echo //相等说明没有s,则不执行静默输出
else
XECHO = : //不相等说明有s,则执行静默输出
endif
编译方法有原地编译和单独输出文件夹编译两种:
编译出来的.o文件会放在同一文件夹下。这种方式叫原地编译。这种方法虽然简单但污染了源文件目录,而且一套源代码只能按照一种配置和编译方法进行处理。make O=输出目录
单独输出文件夹方式的编译基本思路就是在编译时另外指定一个输出目录,将来所有的编译生成的.o文件或生成的其他文件全部丢到那个输出目录下去。export BUILD_DIR=输出目录 然后再make,如果既有BUILD_DIR环境变量存在,又有O=xx,则O=xx具有更高优先级
ifdef O //如果有o
ifeq ("$(origin O)", "command line") //对比0的内容跟“command line”命令行里的o
BUILD_DIR := $(O) //相等则编译目录为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)) //编译出的.o文件存放的目录的根目录
SRCTREE := $(CURDIR)
TOPDIR := $(SRCTREE) //源码目录
LNDIR := $(OBJTREE)
export TOPDIR SRCTREE OBJTREE //导出环境变量
MKCONFIG := $(SRCTREE)/mkconfig //源码根目录下面的mkconfig是uboot配置阶段的配置脚本
export MKCONFIG
ifneq ($(OBJTREE),$(SRCTREE)) //如果编译目录与源目录不同
REMOTE_BUILD := 1 //标志位表示远程编译
export REMOTE_BUILD //标志位输出为环境变量
endif
ifneq ($(OBJTREE),$(SRCTREE)) //如果编译目录与源目录不同
obj := $(OBJTREE)/
src := $(SRCTREE)/
else
obj :=
src :=
endif
export obj src
ifeq ($(obj)include/config.mk,$(wildcard $(obj)include/config.mk))
//include/config.mk和我们配置过程有关,是由配置过程根据我们的配置自动生成的。
# load ARCH, BOARD, and CPU configuration
include $(obj)include/config.mk
export ARCH CPU BOARD VENDOR SOC
2个很重要的环境变量:
ARCH值来自于我们的配置过程会影响后面的CROSS_COMPILE环境变量的值。意义是定义当前编译的目标CPU的架构。
CROSS_COMPILE是定义交叉编译工具链的前缀的。不同CPU架构上的交叉编译工具链,只是前缀不一样,后缀都是一样的。因此定义时把前缀和后缀分开。定义如下
ifndef CROSS_COMPILE
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE =
else
ifeq ($(ARCH),ppc)
CROSS_COMPILE = ppc_8xx-
endif
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
ifeq ($(ARCH),i386)
CROSS_COMPILE = i386-linux-
endif
ifeq ($(ARCH),mips)
CROSS_COMPILE = mips_4KC-
endif
ifeq ($(ARCH),nios)
CROSS_COMPILE = nios-elf-
endif
ifeq ($(ARCH),nios2)
CROSS_COMPILE = nios2-elf-
endif
ifeq ($(ARCH),m68k)
CROSS_COMPILE = m68k-elf-
endif
ifeq ($(ARCH),microblaze)
CROSS_COMPILE = mb-
endif
ifeq ($(ARCH),blackfin)
CROSS_COMPILE = bfin-uclinux-
endif
ifeq ($(ARCH),avr32)
CROSS_COMPILE = avr32-linux-
endif
ifeq ($(ARCH),sh)
CROSS_COMPILE = sh4-linux-
endif
ifeq ($(ARCH),sparc)
CROSS_COMPILE = sparc-elf-
endif # sparc
endif # HOSTARCH,ARCH
endif # CROSS_COMPILE
export CROSS_COMPILE
在创建mkconfig时传入了六个参数
@$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110
$(@:_config=):把@即x210_sd_config里的_config部分用空替换
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
autoconfig.mk指导整个uboot的编译过程,内容是很多CONFIG_开头的宏。这些宏/变量会影响我们uboot编译过程的走向。源码目录的inlcude/configs/xxx.h头文件来产生这个文件。
链接脚本
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是在Nand版本情况下才使用的,X210都是iNand版本的,因此没有这个宏。没有u-boot-nand.lds有u-boot.lds这个链接脚本
TEXT_BASE
ifneq ($(TEXT_BASE),)
CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE)
endif
TEXT_BASE是将来我们整个uboot链接时指定的链接地址。因为uboot中启用了虚拟地址映射,因此这个C3E00000地址就等于0x23E00000。
自动推导规则
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
BOARD_NAME变量是否有值,如果有值就维持不变;如果无值就给他赋值为$1
[ "${BOARD_NAME}" ] || BOARD_NAME="$1"
如果$#小于4,则exit 1
[ $# -lt 4 ] && exit 1
如果$#大于6,则也返回1
[ $# -gt 6 ] && exit 1
创建符号链接作用是给头文件包含等过程提供指向性连接
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 //在include目录下创建asm文件,指向asm-arm。
rm -f asm
ln -s asm-$2 asm
fi
rm -f asm-$2/arch
if [ -z "$6" -o "$6" = "NULL" ] ; then //在inlcude/asm-arm下创建一个arch文件,指向include/asm-arm/arch-s5pc110
ln -s ${LNPREFIX}arch-$3 asm-$2/arch
else
ln -s ${LNPREFIX}arch-$6 asm-$2/arch
fi
# create link for s3c24xx SoC
if [ "$3" = "s3c24xx" ] ; then
rm -f regs.h
ln -s $6.h regs.h
rm -f asm-$2/arch
ln -s arch-$3 asm-$2/arch
fi
# create link for s3c64xx SoC
if [ "$3" = "s3c64xx" ] ; then
rm -f regs.h
ln -s $6.h regs.h
rm -f asm-$2/arch
ln -s arch-$3 asm-$2/arch
fi
# create link for s5pc1xx SoC
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
# create link for s5pc11x SoC
//在include目录下创建regs.h文件,指向include/s5pc110.h 删除第二个。
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 //在inlcude/asm-arm下创建一个arch文件,指向include/asm-arm/arch-s5pc11x
fi
# create link for s5p64xx SoC
if [ "$3" = "s5p64xx" ] ; then
rm -f regs.h
ln -s $6.h regs.h
rm -f asm-$2/arch
ln -s arch-$3 asm-$2/arch
fi
# create link for s5p644x SoC
if [ "$3" = "s5p644x" ] ; 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 //在include/asm-arm下创建一个proc文件,指向include/asm-arm/proc-armv
rm -f asm-$2/proc
ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi
# create link for s3c64xx-mp SoC
if [ "$3" = "s3c64xx-mp" ] ; then
rm -f regs.h
ln -s $6.h regs.h
rm -f asm-$2/arch
ln -s arch-$3 asm-$2/arch
fi
创建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.h文件
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 $1 .h>" >>config.h