一、概述
1、理解u-boot的makefile需要的准备
linux常用命令、shell脚本基础知识、makefile脚本基础知识
2、Makefile的元素
万变不离其宗,无论工程多么复杂,文件多么庞大,其实源于最简单的makefile。Makefile典型的规则如下。
目标:依赖1,依赖2••••••
命令
举一个简单的例子
nand.bin : head.o nand.o main.o
arm-linux-ld -Tnand.lds -o nand_elf head.o main.o
arm-linux-objcopy -O binary -S nand_elf nand.bin
head.o:head.S
arm-linux-gcc -Wall -c -o head.o head.S
nand.o:nand.c s3c2440_addr.h
arm-linux-gcc -Wall -c -o nand.o nand.c
main.o:main.c s3c2440_addr.h
arm-linux-gcc -Wall -c -o main.o main.c
clean:
rm -f nand.bin nand_elf head.o nand.o main.o
形象的表达:待实现一个产品(目标),这个目的需要确定的原材料才能实现(依赖),还需要一套加工手段来制作(编译规则)。
当最初的makefile设计完成后,为了实现可裁剪、自动化编译等目的,不得不加入更多的makefile规则,当然make工具相应的功能也需要增加。可以肯定:这些增加的规则无非是更加方便、灵活的生成指定目标,更加方便的生成依赖关系,更加方便的生成编译规则。
举例:
更加方便灵活的的生成指定目标:通过选项指定生成目标的路径
更加方便的生成依赖:自动生成依赖文件、通过变量选择编译的源码
更加方便的生成指定规则:隐含规则、模式规则、通过变量选择使用的编译器及选项
3、u-boot Makefile体系的组成
Uboot是一个庞大的工程,需要从众多的源文件中选择部分源文件,采用合适的编译手段,生成特定的目标文件。这不是一个简单的任务,需要顶层的makefile,众多的顶层makefile,makefile的include文件(config.mk、rules.mk)等来完成这个工作。
| 名 称 | 描 述 |
| 顶层Makefile | 从总体上控制着u-boot的编译、连接,定义总目标u-boot.bin |
| 顶层config.mk | 规定了编译的规则,被所有Makefile所调用 |
| 顶层rules.mk | 生成依赖关系,被各级子目录Makefile所调用 |
| 各级子目录Makefile | 决定当前目录的编译、连接 |
| 顶层mkconfig | 在编译之前运行,为编译做准备 |
mkconfig(shel l脚本)是在编译之前做一些准备,笔者认为可以不算做Makefile集体中的一部分。
| 名称 | 描述 |
| include/config.mk | mkconfig所生成,被顶层Makefile所包含,定义ARCH、CPU等全局变量 |
| 各级子目录.depend | 各级子目录makefile所生成,并被各级子目录makefile所包含,定义依赖关系 |
二、Makefile的目标
1、Makefile的总目标
顶层Makefile的总目标all是一个伪目标,有几个分目标(目标文件)组成:$(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)。其实,用户也可以添加其他目标,如$(obj)u-boot.dis、$(obj)u-boot.img、$(obj)u-boot.hex等等。由于是一个伪目标,所以只要输入命令make all,总会重建几个分目标。
ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)
2、Makefile的各级子目录中的目标
子目录中的all定义了当前目录所有要生成的目标,LIB定义了当前目录要生成的静态库,OBJS定义了当前目录由“.c”文件编译生成的目标“.o”,SOBJS定义了当前目录由“.S”文件编译生成的目标“.o”。
all: $(obj).depend $(START) $(LIB)
$(LIB): $(obj).depend $(OBJS) $(SOBJS)
三、Makefile的依赖
1、总目标的依赖
$(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)
总目标的依赖是由“depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)”构成,重要的元素是“$(OBJS) $(LIBS)”。下面,我们看看“$(OBJS) $(LIBS)”,它们又是什么构成的,从而查看u-boot是怎样选择参与编译连接的文件的。
编译的过程是(*.c *.S) -- > (*.o *.a) --> (*.bin),但是make工具分析Makefile的过程是相反的。为了生成(*.bin) 需要依赖(*.o *.a),为了生成(*.o *.a)间接的又需要(*.c *.S),可以说(*.c *.S)是最初的依赖(原材料)。
Uboot是一个通用的启动代码,可以在众多的硬件平台上例如arm、powerpc,和操作系统上运行,例如vxworks、linux等等。源码中有相应的源文件包,例如lib_ppc,lib_arm等等。其实,还有各种驱动,网卡、显示器、串口、键盘等等。但是,对于一个特定的应用目标,它的硬件平台是确定的,所用的操作系统也是确定的,它的外设也是确定的。所以,需要对这些源文件进行裁剪。
在执行make all之前,首先要执行make *_config例如make smdk2410_config,通过执行mkconfig脚本,可以确定所用cpu的架构(ARCH)例如arm ,cpu的种类(CPU)例如arm920t,开发板(BOARD)例如smdk2410 ,soc(SOC)例如 s3c24x0,这些信息保存在mkconfig脚本生成的makefile包含文件include/config.mk中。include/config.mk会被包含进入顶层makefile中,根据这个文件所定义的变量值,从而确定用那些文件(依赖),例如lib_arm/,board/smdk2410,cpu/arm920t等等。这是一种大方向上的裁剪方式。
至于所用外设之类的裁剪方式,不是通过makefile来实现的,而是通过C语言的预处理实现的,配置文件是include/configs/<board_name>.h,例如include/configs/smdk2410.h。倘若smdk2410开发板上有CS8900网卡,可以通过在配置文件中定义一个宏来实现对网卡驱动的调用,例如“#define CONFIG_DRIVER_CS8900 1”。
本文主要讨论的是makefile的分析,所以就来看看makefile是怎样裁剪源文件的。
OBJS = cpu/$(CPU)/start.o ifeq ($(CPU),i386) OBJS += cpu/$(CPU)/start16.o OBJS += cpu/$(CPU)/reset.o endif ifeq ($(CPU),ppc4xx) OBJS += cpu/$(CPU)/resetvec.o endif ifeq ($(CPU),mpc83xx) OBJS += cpu/$(CPU)/resetvec.o endif ifeq ($(CPU),mpc85xx) OBJS += cpu/$(CPU)/resetvec.o endif ifeq ($(CPU),mpc86xx) OBJS += cpu/$(CPU)/resetvec.o endif ifeq ($(CPU),bf533) OBJS += cpu/$(CPU)/start1.o cpu/$(CPU)/interrupt.o cpu/$(CPU)/cache.o OBJS += cpu/$(CPU)/cplbhdlr.o cpu/$(CPU)/cplbmgr.o cpu/$(CPU)/flush.o endif LIBS = lib_generic/libgeneric.a LIBS += board/$(BOARDDIR)/lib$(BOARD).a LIBS += cpu/$(CPU)/lib$(CPU).a ifdef SOC LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a endif LIBS += lib_$(ARCH)/lib$(ARCH).a LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \ fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a LIBS += net/libnet.a LIBS += disk/libdisk.a LIBS += rtc/librtc.a LIBS += dtt/libdtt.a LIBS += drivers/libdrivers.a LIBS += drivers/nand/libnand.a LIBS += drivers/nand_legacy/libnand_legacy.a LIBS += drivers/sk98lin/libsk98lin.a LIBS += post/libpost.a post/cpu/libcpu.a LIBS += common/libcommon.a LIBS += $(BOARDLIBS)