在Linux下面,要分析一个项目,首先应该读Makefile。前面有了一定的Makefile基础,现在虽然还不能写复杂的Makefile脚本,但是参考资料,还可以读懂vivi的Makefile。不过vivi的Makefile给我的感觉是在组织上有点凌乱,读起来有点费劲。只有真正理解了这个项目的组织,才能明白凌乱在何处。这中间都是按照自己的认识过程,尝试了各种方法来分析,基本上完成了按照自己理解改写的Makefile。编译完成重新下载到nand flash里面,验证没有问题。
下面首先给出改写的Makefile。我尝试使用英语注释,可能不太通顺。但是,第一步总是要迈出的,早总比晚要好。
# Modified by Qingmin Liu(piaoxiangxinling@163.com, Shandong University) # Date: 2007-07-26 # Desc: This document is only used for studying. If you want to talk about # vivi or embedded system, I am very glad to receive your email. # # Section 1: vivi version #
# 3 rows below supplies with a numbering scheme, which comes from Linux # kernel. This numbering scheme uses three numbers separated by dots to # identify the releases. The first number designates the version, the # second designates the patch, and the third designates the release. # # Usually, you should use a kernel from the latest stable series for your # embedded system. VERSION = 0 PATCHLEVEL = 1 SUBLEVEL = 4
# This macro definations is used to supply users with version information, # and you will find the usage in [init/version.c]. If you port vivi to your # own board successfully, the version information displays at the beginning # through the debug serial. # # VIVIRELEASE = 0.1.4 VIVIRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL) # # Section 2: target architecture #
# Architecture is arm. If you don't understand architecture, I think, you'd # better search some data on the internet. ARCH := arm
# # Section 3: tools #
# CONFIG_SHELL gets the shell that is used on your host. In my host, OS is # Redhat Linux 9.0, and bash shell is the default one. # # This is used to execute the config scripts in [scripts]. And this is vivi's # core about interactive configuration. #
# You need to know some about Makefile if you don't know $(shell ..). In fact, # it works to search the shell: /bin/bash --> sh. In my host, it works well. # for example, # $which bash # /bin/bash # $which sh # /bin/sh CONFIG_SHELL := $(shell if [ -x /bin/bash ]; then echo /bin/bash; \ else echo /bin/sh; fi) # HOST tool HOSTCC = gcc HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer export HOSTCC HOSTCFLAGS
# TARGET tool CROSS_COMPILE = /usr/local/arm/2.95.3/bin/arm-linux- 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
export AS LD CC CPP AR
# # Section 4: parameters #
# TOPDIR means top directory of your project. More accurately, it means the # directory of "Makefile" because you must step into the directory of Makefile # if you want to execute make on your command line. TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD;else /bin/pwd; fi) export TOPDIR
# standard CFLAGS CPPFLAGS := -I$(TOPDIR)/include CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -O2 -fPIC -fomit-frame-pointer AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS) export CFLAGS AFLAGS
# 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 LINKFLAGS = -Tarch/vivi.lds -Bstatic
# # Section 5: files that will be included or handled with. #
# whe you execute make on the command line, MAKEFILES are read at first. MAKEFILES = $(TOPDIR)/.config # core files and so on CORE_FILES = init/main.o init/version.o lib/lib.o LIBS := lib/priv_data/priv_data.o SUBDIRS = drivers lib
# files that will be deleted when "make clean" CLEAN_FILES = \ vivi-elf \ vivi \ vivi.nm \ vivi.map # files that will be deleted when "make distclean" DISTCLEAN_FILES = \ include/autoconf.h .menuconfig.log \ scripts/lxdialog/*.o scripts/lxdialog/lxdialog \ .config .config.old TAGS tags
# # Section 6: drivers added # # define CONFIGURATION if .config exists; # else include .config ifeq (.config, $(wildcard .config)) include .config else CONFIGURATION = config endif
# drivers added by .config setup # if CONFIG_SERIAL=y and CONFIG_MTD=y, DRIVERS equals "drivers/serial/serial.o drivers/mtd/mtd.o" DRIVERS-y := DRIVERS-$(CONFIG_SERIAL) += drivers/serial/serial.o DRIVERS-$(CONFIG_MTD) += drivers/mtd/mtd.o DRIVERS := $(DRIVERS-y) # # Section 7: sub Makefile #
include arch/Makefile
# # Section 8: real handle # .PHONY: all do-it-all
# make all # execute all handle procedure by the config all: do-it-all # search .config.If it exists, read .config first and equals "make Version; make vivi". # else define CONFIGURATION and it equals "make config" ifdef CONFIGURATION do-it-all: $(CONFIGURATION) else do-it-all: Version vivi endif # make Version # delete [include/compile.h] Version: $(RM) include/compile.h # make vivi # create target file -- vivi # please remember: prerequisites in sequence. vivi: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs $(LD) -v $(LINKFLAGS) \ $(HEAD) \ $(CORE_FILES) \ $(DRIVERS) \ $(LIBS) \ -o $@-elf $(CLIBS) $(NM) -v -l $@-elf > $@.map $(OBJCOPY) -O binary -S $@-elf $@ $(OBJCOPYFLAGS) @echo @echo " ^_^ The vivi boot image file is: $(shell pwd)/$@, and you \ can download it to your [nor | nand] flash." @echo
# make oldconfig # configure by the .config oldconfig: $(CONFIG_SHELL) scripts/Configure -d arch/config.in # make config # configure by the [arch/defconfig] config: $(CONFIG_SHELL) scripts/Configure arch/config.in # make menuconfig # configure in forms of menutext menuconfig: $(MAKE) -C scripts/lxdialog all $(CONFIG_SHELL) scripts/Menuconfig arch/config.in # make clean # delete middle files clean: find . \( -name '*.o' -o -name core -o -name ".*.flags" \) -type f -print \ | grep -v lxdialog/ | xargs rm -f $(RM) $(CLEAN_FILES) # make distclean # delete middle files and configure files distclean: Version clean $(RM) $(DISTCLEAN_FILES) # make myboard_config # Configuration targets. Use these to select a # configuration for your architecture # # here, @ makes the command no echo back.and "CFG=$(@:_config=)" uses the advanced # function of variables.for example, # foo:=a.o b.o c.o # bar:=$(foo:.o=.c) # so bar = a.c b.c c.c %_config: @ ( \ CFG=$(@:_config=); \ if [ -f arch/def-configs/$$CFG ]; then \ [ -f .config ] && mv -f .config .config.old; \ cp arch/def-configs/$$CFG .config; \ echo "*** Default configuration for $$CFG installed";\ echo "*** Next, you may run 'make oldconfig'"; \ else \ echo "$$CFG does not exist"; \ fi; \ )
# make myboard # make your work automatically %: ./arch/def-configs/% $(MAKE) distclean cp arch/def-configs/$* ./.config -f $(MAKE) oldconfig $(MAKE) # # Section 9: real handle prerequisites #
# read SUBDIRS # here SUBDIRS = drivers lib linuxsubdirs: $(patsubst %, _dir_%, $(SUBDIRS)) # read sub Makefile in SUBDIRS $(patsubst %, _dir_%, $(SUBDIRS)) : $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C $(patsubst _dir_%, %, $@) # create [include/compile.h] include/compile.h: $(CONFIGURATION) @echo \#define VIVI_RELEASE \"$(VIVIRELEASE)\" > .ver @echo -n \#define UTS_VERSION \"\#$(VIVIRELEASE) >> .ver @if [ -f .name ]; then echo -n \-`cat .name` >> .ver; fi @echo ' '`date`'"' >> .ver @echo \#define VIVI_COMPILE_BY \"`whoami`\" >> .ver @echo \#define VIVI_COMPILE_HOST \"`hostname`\" >> .ver @echo \#define VIVI_COMPILER \"`$(CC) $(CFLAGS) -v 2>&1 | tail -1`\" >> .ver @mv -f .ver $@ # compile [init/version.c] init/version.o: init/version.c include/compile.h $(CC) $(CFLAGS) -DUTS_MACHINE='"$(ARCH)"' -c $< -o $@ # compile [init/main.c] init/main.o: init/main.c $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -c $< -o $@ # create TAGS TAGS: etags `find include -name '*.h'` find $(SUBDIRS) init -name '*.[ch]' | xargs etags -a # Exuberant ctags works better with -I tags: CTAGSF=`ctags --version | grep -i exuberant >/dev/null && \ echo "-I __initdata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_NOVERS"`; \ ctags $$CTAGSF `find include -name '*.h'` && \ find $(SUBDIRS) init -name '*.[ch]' | xargs ctags $$CTAGSF -a # # Section 10: default rules #
include Rules.make # # Section 11: debug #
debug: @echo "VIVIRELEASE: $(VIVIRELEASE)" @echo "ARCH: $(ARCH)" @echo "CONFIG_SHELL: $(CONFIG_SHELL)" @echo "CROSS_COMPILE: $(CROSS_COMPILE)" @echo "TOPDIR: $(TOPDIR)" @echo "SUBDIRS: $(SUBDIRS)" @echo "CONFIGURATION: $(CONFIGURATION)" @echo "DRIVERS: $(DRIVERS)" |
修改的幅度比较大,但是这样组织之后,清晰了很多,至少我是这样感觉。现在一般的命令处理有:
make clean:清理中间生成文件,不包括配置文件
make distclean:清理所有生成文件
make config:文本配置,如果没有[.config],默认读取[arch/defconfig]
make oldconfig: 文本配置,默认读取[.config]
make menuconfig:图像配置,需要图形库的支持
make debug:变量调试
make vivi:编译,生成目标文件
make myboard_config:假设我的配置保存为[arch/def-configs/myboard],那么此命令的结果是把该配置复制到[.config]。如果原来存在[.config],则把原来的[.config]更改为[.config.old].
make myboard:假设我的配置保存为[arch/def-configs/myboard],那么此命令实现了自动化编译。首先清理所有的生成文件,然后把myboard读取到[.config],根据此配置编译生成最终的vivi目标文件。
我常用的做法是:(1)make smdk2410_config(2)make menuconfig(3)make vivi(4)cp .config ./arch/def-configs/myboard.如果以后改变程序,而不改变配置,就可以执行make distclean.理解了整个过程,对这些就可以熟练应用了。也可以自己添加适合自己的编译命令。
Makefile采用了主Makefile和子Makefile配合的方式,它们之间的联系如下:
首先,读取主Makefile,主Makefile通过该"include arch/Makefile"完成包含,主要是一些相关的配置。至于其他的子Makefile,在执行make vivi时,有依赖关系linuxsubdirs,这个部分就是完成读取并完成所有其他子Makefile.具体就在下面语句。
linuxsubdirs: $(patsubst %, _dir_%, $(SUBDIRS))
# read sub Makefile in SUBDIRS
$(patsubst %, _dir_%, $(SUBDIRS)) :
$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C $(patsubst _dir_%, %, $@)
所有的显示规则和隐式规则都在Rules.make里,也是用include引入,这样就形成了一条链,完美的管理着你的项目。另外,配置部分需要在另外一篇文档中总结。需要读scripts下的脚本,现在还没有读完。
相对于vivi原始工程,做了一个patch。
| 文件: | patch.rar | 大小: | 6KB | 下载: | 下载 | |
评论
发表评论