个人在看VIVI的makefile时的一些认识(部分内容已经被我修改,初步的草稿,还将继续修正):
总MAKEFILE最终目的就是要生成VIVI,所以从生成VIVI的规则开始分析。前面的部分都是在后面规则里面需要用到的定义。
#版本信息和体系结构
VERSION = 0
PATCHLEVEL = 1
SUBLEVEL = 4
VIVIRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)
ARCH := arm
#选择相应的SHELL
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; /
else if [ -x /bin/bash ]; then echo /bin/bash; /
else echo sh; fi ; fi)
TOPDIR := $(shell /bin/pwd)
#
# change this to point to the Linux include directory
#
LINUX_INCLUDE_DIR = /usr/local/arm/2.95.3/include
#VIVI的头文件路径
VIVIPATH = $(TOPDIR)/include
#一系列的工具和编译选项
HOSTCC = gcc
HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
CROSS_COMPILE = /usr/local/arm/2.95.3/bin/arm-linux-
#
# 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
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
MAKEFILES = $(TOPDIR)/.config
MD5SUM = md5sum
PERL = perl
AWK = awk
export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE /
CONFIG_SHELL TOPDIR VIVIPATH HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC /
CPP AR NM STRIP OBJCOPY OBJDUMP MAKE MAKEFILES MD5SUM PERL AWK
#总的依赖为vivi,version,.config,如果.config存在那么将其包含,利用其中的配置信息,如果不存在那么需要通过依赖建立这个文件,
#所以在不存在时定义CONFIGURATION = config,并使CONFIGURATION成为依赖。
ifeq (.config,$(wildcard .config))
include .config
else
CONFIGURATION = config
#do-it-all: $CONFIGURATION
#从下面分析来看这一句并不是必须的,在下面的vivi的生成规则中已经包含了对$CONFIGURATION的依赖,可以执行config操作。
endif
#MAKE入口点
all: do-it-all
do-it-all: Version vivi
#接下来就是要看这两个文件怎么生成
#
# standard CFLAGS
#
CPPFLAGS := -I$(VIVIPATH) -I$(LINUX_INCLUDE_DIR)
#CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 /
# -fomit-frame-pointer -fno-strict-aliasing -fno-common
#normal flags
CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -O2 -fPIC -fomit-frame-pointer
#symbol table make up
#CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -O2 -fPIC -fomit-frame-pointer -ggdb
AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
#
# Location of the gcc arm libs.
#
ARM_GCC_LIBS = /usr/local/arm/2.95.3/lib/gcc-lib/arm-linux/2.95.3
OBJCOPYFLAGS = -R .comment -R .stab -R .stabstr
CLIBS = -L$(ARM_GCC_LIBS) -lgcc -lc
#laputa symbolic 这里的.lds文件需要编写
LINKFLAGS = -Tarch/vivi.lds -Bstatic
CORE_FILES = init/main.o init/version.o lib/lib.o
LIBS := lib/priv_data/priv_data.o
SUBDIRS = drivers lib
#下面这个写法我觉得很好,如果配置文件中有相应的配置,那么该配置就是y,对应的驱动被追加,将最后的追加结果给驱动。
DRIVERS-y :=
DRIVERS-$(CONFIG_SERIAL) += drivers/serial/serial.o
DRIVERS-$(CONFIG_MTD) += drivers/mtd/mtd.o
DRIVERS := $(DRIVERS-y)
#清除操作对应的文件
#最终生成的一些文件
CLEAN_FILES = /
vivi-elf /
vivi /
vivi.nm /
vivi.map
#配置过程生成的一些文件
DISTCLEAN_FILES = /
include/autoconf.h include/version.h /
scripts/lxdialog/*.o scripts/lxdialog/lxdialog /
.menuconfig.log /
.config .config.old
#由于在生成最终文件的时候要用到arch文件夹中的目标文件,调用其makefile进行生成
include arch/Makefile
export CPPFLAGS CFLAGS AFLAGS
export DRIVERS LDFLAGS
#因为compile.h 中保存的是最后一次编译过程中生成的时间,工具等信息,它被include/version.h调用,需要更新,所以将其删除
Version: dummy
@rm -f include/compile.h
#生成最终vivi文件的规则,可以看一下需要的依赖有没有全部有相应生成的地方
vivi: include/version.h $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
$(LD) -v $(LINKFLAGS) /
$(HEAD) /
$(CORE_FILES) /
$(DRIVERS) /
$(LIBS) /
-o vivi-elf $(CLIBS)
$(NM) -v -l vivi-elf > vivi.map
$(OBJCOPY) -O binary -S vivi-elf vivi $(OBJCOPYFLAGS)
#这里对以上用到各文件进行一个分析:HEAD在arch目录下定义,上面已经include了相应的makefile进行规则定义,打开看一下可知主
#要是根据配置文件(主Makefile包含了.config,这样看来先make config一下比较稳妥)追加了一些与体系结构等有关的编译规则、定义了MACHINE PROCESSOR TEXTADDR,修改了SUBDIRS #CORE_FILE CLEAN_FILES 使其包含了这个目录下相关的文件而
#head.o的生成则是由主Makefile中include Rules.make来完成。
#其中vivi:$(HEAD) arch/vivi.lds arch/vivi.lds: $(LDSCRIPT) dummy @sed s/TEXTADDR/$(TEXTADDR)/ $(LDSCRIPT) >$@
#使得vivi包含了对$(HEAD)的依赖,由于其中的连接方式等可能与总的vivi那边不大一样,所以写在了子Makefile中。
#总的来看该子makefile主要的任务是根据CPU的相关信息来调整总操作和选项。
#几种config操作:通过相应的脚本和config.in文件中的选择与用户交互完成.config文件生成。以config操作为例,其中
#scripts/Configure脚本是模仿LINUX的,打开看一下可知config.in需要根据自己的需要进行修改,主要功能是提醒用户可以选择的配置
#以及完成相应配置的保存。主要有如:comment、bool、hex等这些语句来提示和保存信息。最后有source lib/priv_data/Config.in
#source drivers/serial/Config.in source drivers/mtd/Config.in source lib/Config_cmd.in几个配置选择文件的调入。打开看下这些子config.in可知,它们又调入了更下一层的config.in文件,这样要提示用户一个新的可配置的模块时,只需要写好该模块自己的config.in提示文件,并在它所属的上一层config.in中用source调用即可。
oldconfig:
$(CONFIG_SHELL) scripts/Configure -d arch/config.in
config:
$(CONFIG_SHELL) scripts/Configure arch/config.in
menuconfig: include/version.h
$(MAKE) -C scripts/lxdialog all
$(CONFIG_SHELL) scripts/Menuconfig arch/config.in
clean:
find . /( -name '*.o' -o -name core -o -name ".*.flags" /) -type f -print /
| grep -v lxdialog/ | xargs rm -f
rm -f $(CLEAN_FILES)
distclean: clean
rm -f $(DISTCLEAN_FILES)
#执行其他子目录下的makefile
linuxsubdirs: $(patsubst %, _dir_%, $(SUBDIRS))
#使用patsubst避免目标和操作的文件重名
$(patsubst %, _dir_%, $(SUBDIRS)) : include/version.h
$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C $(patsubst _dir_%, %, $@)
#还没有看明白以下两句有何精髓...可能是在别的makefile中有用到下面两个目标
$(TOPDIR)/include/version.h: include/version.h
$(TOPDIR)/include/compile.h: include/compile.h
#在前面为了产生新的version.h,前面已经通过make Version或者通过make入口后删除了compile.h文件,在成为依赖时重新生成
include/compile.h: $(CONFIGURATION) include/version.h
@echo -n /#define UTS_VERSION /"/#$(VIVIRELEASE) > .ver
@if [ -f .name ]; then echo -n /-`cat .name` >> .ver; fi
@echo ' '`date`'"' >> .ver
@echo /#define VIVI_COMPILE_TIME /"`date +%T`/" >> .ver
@echo /#define VIVI_COMPILE_BY /"`whoami`/" >> .ver
@echo /#define VIVI_COMPILE_HOST /"`hostname`/" >> .ver
@if [ -x /bin/dnsdomainname ]; then /
echo /#define VIVI_COMPILE_DOMAIN /"`dnsdomainname`/"; /
elif [ -x /bin/domainname ]; then /
echo /#define VIVI_COMPILE_DOMAIN /"`domainname`/"; /
else /
echo /#define VIVI_COMPILE_DOMAIN ; /
fi >> .ver
@echo /#define VIVI_COMPILER /"`$(CC) $(CFLAGS) -v 2>&1 | tail -1`/" >> .ver
@mv -f .ver $@
include/version.h:
@echo /#define VIVI_RELEASE /"$(VIVIRELEASE)/" > .ver
@echo /#define VIVI_VERSION_CODE `expr $(VERSION) //* 65536 + $(PATCHLEVEL) //* 256 + $(SUBLEVEL)` >> .ver
@echo '#define VIVI_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))' >>.ver
@mv -f .ver $@
init/version.o: init/version.c include/compile.h
$(CC) $(CFLAGS) -DUTS_MACHINE='"$(ARCH)"' -c -o init/version.o init/version.c
init/main.o: init/main.c
$(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -c -o $*.o $<
#如果需要选择默认的配置文件来复制生成.config并且自动执行后面操作生成vivi,默认配置文件里面定义了一种配置模式,可以打开看一下
#是否能满足需要
%: ./arch/def-configs/%
$(MAKE) distclean
cp arch/def-configs/$* ./.config -f
$(MAKE) oldconfig
$(MAKE)
#通过make ..config 可以查看是否存在.config文件,如果不存在将会给出相关提示。
ifdef CONFIGURATION
..$(CONFIGURATION):
@echo
@echo "You have a bad or nonexistent" .$(CONFIGURATION) ": running 'make" $(CONFIGURATION)"'"
@echo
$(MAKE) $(CONFIGURATION)
@echo
@echo "Successful. Try re-making (ignore the error that follows)"
@echo
exit 1
dummy:
else
dummy:
endif
#这一句很重要,很多的通过规则都放在其中,使得很多makefile中只需要给出依赖关系即可
include Rules.make