二 编译
2.1 makefile的执行顺序
makefile最开始执行的是一些独立的赋值与函数,make命令之后有目标的话执行目标,make之后如果没有跟目标,默认只执行第一个
num1=123
test1:
echo $(num1)
test2:
echo $(num2)
num2=456
$(error num1 is$(num1) num2 is $(num2))
命令make只执行test1 命令make test2只执行test2
但在目标执行之前都会执行num1与num2的赋值与最后的error函数
2.2 第一个目标ALL执行之前
u-boot支持将所有编译生成的.o文件或者其他文件全部输出到指定好的目录
第一种方法:‘make O=/tmp/build all’
第一种方法:设置全局环境变量BUILD_DIR
'export BUILD_DIR=/tmp/build'
'make'
第二种脚本也可以通过MAKEALL脚本实现
'export BUILD_DIR=/tmp/build'
'./MAKEALL'
如果没有显式指定使用哪种方式,编译脚本会自动进行本地编译,目标文件被存放在当前文件夹里
ifdef O
ifeq ("$(origin O)", "command line")
BUILD_DIR:= $(O)
endif
endif
# 语法:
# $(origin variable)
#
# $(origin O)
# 可以判断变量O从哪里来的,即变量O定义的路径
# 如果O以命令行的方式定义,则$(originO)=command line
ifneq ($(BUILD_DIR),)
saved-output:= $(BUILD_DIR)
# 如果BUILD_DIR有定义,saved-output=$(BUILD_DIR)=O
# Attempt tocreate a output directory.
$(shell [ -d${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})
[ -d ${BUILD_DIR}]
# 文件比较运算符
# -e filename如果 filename存在,则为真 [ -e /var/log/syslog ]
# -d filename如果 filename为目录,则为真 [ -d /tmp/mydir ]
# -f filename如果 filename为常规文件,则为真 [ -f/usr/bin/grep ]
# -L filename如果 filename为符号链接,则为真 [ -L/usr/bin/grep ]
# -r filename如果 filename可读,则为真 [ -r /var/log/syslog ]
# -w filename如果 filename可写,则为真 [ -w /var/mytmp.txt ]
# -x filename如果 filename可执行,则为真 [ -L /usr/bin/grep ]
# 如果${BUILD_DIR},则创建目录
# mkdir -p -p如果上层目录不存在,则同时创建上层目录
# 如:mkdir -p /tmp/build 如tmp目录不存在时,会先创建tmp目录
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
exportREMOTE_BUILD
endif
# CURDIR makefile的内嵌变量,表示当前路径
# 当前路径为$(CURDIR)=/u-boot-1.1.6
# make O=/tmp/build
# 当有-O选项 $(BUILD_DIR)=/u-boot-1.1.6/tmp/build
# 编译时加-O
# OBJTREE = $(BUILD_DIR)=/u-boot-1.1.6/tmp/build
# SRCTREE = $(CURDIR) =/u-boot-1.1.6
# TOPDIR = $(SRCTREE) =/u-boot-1.1.6
# LNDIR = $(OBJTREE) =/u-boot-1.1.6/tmp/build
#
# MKCONFIG = $(SRCTREE)/mkconfig =/u-boot-1.1.6/mkconfig
# REMOTE_BUILD = 1
ifneq ($(OBJTREE),$(SRCTREE))
obj:= $(OBJTREE)/
src:= $(SRCTREE)/
else
obj:=
src:=
endif
export obj src
ifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk))
# load ARCH,BOARD, and CPU configuration
include $(OBJTREE)/include/config.mk
export ARCH CPU BOARD VENDOR SOC
# obj := $(OBJTREE) =/u-boot-1.1.6/tmp/build/
# src := $(SRCTREE) =/u-boot-1.1.6/
# $(wildcard *.c)
# Makefile中,通配符会被自动展开。但在变量的定义和函数引用时通配符将失效。
# 这种情况下如果需要通配符有效,就需要使用函数“wildcard”
# 目录下生成可执行文件的好例子:
# objects := $(patsubst %.c,%.o,$(wildcard*.c))
# foo : $(objects)
# cc -o foo $(objects)
# 首先使用“wildcard”函数获取工作目录下的.c文件列表;
# 之后将列表中所有文件名的后缀.c替换为.o
# 最后cc生成可执行文件foo
# 添加第一章中生成的config.mk
# ARCH =arm
# CPU =arm920t
# BOARD =100ask24x0
# ARCHSOC =s3c24x0
ifndef CROSS_COMPILE
ifeq ($(ARCH),arm)
CROSS_COMPILE= arm-linux-
endif
endif
export CROSS_COMPILE
# load otherconfiguration
include $(TOPDIR)/config.mk
# 定义交叉编译
# CROSS_COMPILE= arm-linux-
# TOPDIR = $(SRCTREE) =/u-boot-1.1.6
# include u-boot-1.1.6目录下的 config.mk
#########################################################################
# U-Bootobjects....order is important (i.e. start must be first)
OBJS =cpu/$(CPU)/start.o
ifeq ($(CPU),i386)
OBJS += cpu/$(CPU)/start16.o
OBJS += cpu/$(CPU)/reset.o
endif
OBJS:= $(addprefix $(obj),$(OBJS))
# 根据配置文件 CPU =arm920t
# 也会判断是否是其他CPU
# 如果CPU等于其他值,还需要 +=其他编译好的.o文件
# $(addprefix fixstring,string1 string2...)
# 给每个string前添加一个字符串fixstring
# 如果make有-O参数为tmp/build/
# obj := $(OBJTREE)/
# OBJS=/u-boot-1.1.6/tmp/build/cpu/arm920t/start.o
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.afs/ext2/libext2fs.a
...
LIBS += common/libcommon.a
LIBS +=$(BOARDLIBS)
LIBS:= $(addprefix $(obj),$(LIBS))
.PHONY: $(LIBS)
# 添加各处的库文件
# Add GCC lib
PLATFORM_LIBS += \
-L $(shell dirname `$(CC) $(CFLAGS)-print-libgcc-file-name`) -lgcc
# -L指定寻找库的路径
# dirname取一个文件存储路径
# CFLAGS 主要是指makefile中的隐式规则里会用到的常见预定义变量,
# 是C编译器的选项,无默认值
# CC c预编译器的名称,默认是cc
# -lgcc代表链接器要连接的GCC的支持库为libgcc.a gcc会自动加lib与.a
# 如 -lc 代表链接器将要连接的GCC的标准C库libc.a
# root@ubuntu:~$ arm-linux-gcc-print-libgcc-file-name
# /work/tools/gcc-3.4.5-glibc-2.3.6/lib/gcc/arm-linux/3.4.5/libgcc.a
# -print-libgcc-file-name取得$(CC)的支持库,加shell dirname
# 取得路径:
# /work/tools/gcc-3.4.5-glibc-2.3.6/lib/gcc/arm-linux/3.4.5/
关于参数-I -L与-lgcc
-Ilib/gcc/arm-linux/3.4.5/ -L lib/gcc/arm-linux/3.4.5/ -lgcc
-Ilib/gcc/arm-linux/3.4.5/
表示将lib/gcc/arm-linux/3.4.5/目录作为第一个寻找头文件的目录
-Llib/gcc/arm-linux/3.4.5/
表示将lib/gcc/arm-linux/3.4.5/目录作为第一个寻找库文件的目录
-lgcc 表示在上面的lib的路径中寻找libgcc.so动态库文件
(如果gcc编译选项中加入了“-static”表示寻找libworld.a静态库文件)
# The"tools" are needed early, so put this first
# Don't includestuff already done in $(LIBS)
SUBDIRS= tools \
examples \
post \
post/cpu
.PHONY: $(SUBDIRS)
__OBJS:= $(subst $(obj),,$(OBJS))
__LIBS:= $(subst $(obj),,$(LIBS))
# $(subst FROM,TO,TEXT)makefile中字符串替换函数,将TEXT中的FROM变为TO
# __OBJS=$OBJS去掉$(obj)
#
# OBJS=/u-boot-1.1.6/tmp/build/cpu/arm920t/start.o
# obj :=$(OBJTREE)=$(BUILD_DIR)=/u-boot-1.1.6/tmp/build
# __OBJS = cpu/arm920t/start.o