个人在看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