vivi开发笔记(三):Makefile详解
2012-06-05 15:28
204 查看
原文地址:vivi开发笔记(三):Makefile详解
作者:piaoxiang
在Linux下面,要分析一个项目,首先应该读Makefile。前面有了一定的Makefile基础,现在虽然还不能写复杂的Makefile脚本,但是参考资料,还可以读懂vivi的Makefile。不过vivi的Makefile给我的感觉是在组织上有点凌乱,读起来有点费劲。只有真正理解了这个项目的组织,才能明白凌乱在何处。这中间都是按照自己的认识过程,尝试了各种方法来分析,基本上完成了按照自己理解改写的Makefile。编译完成重新下载到nand
flash里面,验证没有问题。
下面首先给出改写的Makefile。我尝试使用英语注释,可能不太通顺。但是,第一步总是要迈出的,早总比晚要好。
修改的幅度比较大,但是这样组织之后,清晰了很多,至少我是这样感觉。现在一般的命令处理有:
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。
作者:piaoxiang
文章说明:calmarrow(lqm)原创 文章引自:http://piaoxiang.cublog.cn |
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。
|
相关文章推荐
- PiscisOS开发笔记_2_开发方法详解
- linux设备驱动开发详解 阅读笔记3(第一篇入门)
- Android开发笔记之:Handler Runnable与Thread的区别详解
- Python开发技术详解-笔记_第03章-Python的控制语句
- Android开发笔记之: 数据存储方式详解
- vivi开发笔记【专辑】
- vivi_Makefile分析笔记
- Android开发笔记之:Log图文详解(Log.v,Log.d,Log.i,Log.w,Log.e)
- Linux设备驱动开发详解--笔记9--异步通知与异步I/O
- Android开发学习笔记:Intent的简介以及属性的详解
- Linux/Unix开发之make和makefile详解
- java邮件开发详解笔记(创建一个内嵌图片和附件的邮件)
- 《FLEX4.0 RIA开发详解》自学笔记 第3篇 组件篇
- android开发笔记之Makefile(二)
- Android开发学习笔记:Intent的简介以及属性的详解
- Android开发笔记之:ListView刷新顺序的问题详解
- 【Android开发学习笔记之一】5大布局方式详解
- PHP+MySQL开发技术详解—学习笔记
- 嵌入式软件开发培训笔记——Makefile编写
- Android开发学习笔记:Intent的简介以及属性的详解