跳至主要内容

【转】vivi开发笔记(三):Makefile详解

文章说明:calmarrow(lqm)原创

文章引自:http://piaoxiang.cublog.cn

 
    在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
下载: 下载

评论

此博客中的热门博文

【转】AMBA、AHB、APB总线简介

AMBA 简介 随着深亚微米工艺技术日益成熟,集成电路芯片的规模越来越大。数字IC从基于时序驱动的设计方法,发展到基于IP复用的设计方法,并在SOC设计中得到了广泛应用。在基于IP复用的SoC设计中,片上总线设计是最关键的问题。为此,业界出现了很多片上总线标准。其中,由ARM公司推出的AMBA片上总线受到了广大IP开发商和SoC系统集成者的青睐,已成为一种流行的工业标准片上结构。AMBA规范主要包括了AHB(Advanced High performance Bus)系统总线和APB(Advanced Peripheral Bus)外围总线。   AMBA 片上总线        AMBA 2.0 规范包括四个部分:AHB、ASB、APB和Test Methodology。AHB的相互连接采用了传统的带有主模块和从模块的共享总线,接口与互连功能分离,这对芯片上模块之间的互连具有重要意义。AMBA已不仅是一种总线,更是一种带有接口模块的互连体系。下面将简要介绍比较重要的AHB和APB总线。 基于 AMBA 的片上系统        一个典型的基于AMBA总线的系统框图如图3所示。        大多数挂在总线上的模块(包括处理器)只是单一属性的功能模块:主模块或者从模块。主模块是向从模块发出读写操作的模块,如CPU,DSP等;从模块是接受命令并做出反应的模块,如片上的RAM,AHB/APB 桥等。另外,还有一些模块同时具有两种属性,例如直接存储器存取(DMA)在被编程时是从模块,但在系统读传输数据时必须是主模块。如果总线上存在多个主模块,就需要仲裁器来决定如何控制各种主模块对总线的访问。虽然仲裁规范是AMBA总线规范中的一部分,但具体使用的算法由RTL设计工程师决定,其中两个最常用的算法是固定优先级算法和循环制算法。AHB总线上最多可以有16个主模块和任意多个从模块,如果主模块数目大于16,则需再加一层结构(具体参阅ARM公司推出的Multi-layer AHB规范)。APB 桥既是APB总线上唯一的主模块,也是AHB系统总线上的从模块。其主要功能是锁存来自AHB系统总...

【转】select问题

问: 该串口初始化如下 ioctl(comm2Fd,FIOBAUDRATE,9600) ioctl(comm2Fd,FIOSETOPTIONS,OPT_RAW) 使用如下 FD_ZERO   (&readFds); FD_SET   (comm2Fd,   &readFds);   width   =   comm2Fd   +   1; FD_ISSET   (comm2Fd,   &readFds); FOREVER { if(timeoutvalue==0) { printf("\nselect   start!\n"); selectnum   =   select   (width,   &readFds,   NULL,   NULL,   NULL); printf("\nselect   over!\n"); }                                 ........... } 现在的状况是程序跑一段时间后会死机或这个串口通讯任务死掉,每次死机都是"select   start!"打印出来,而"select   over!"打印不出来,在仅这个串口通讯任务死掉的情况下,用comm1Fd超级终端登陆,查询任务状态,会发现tExcTask任务居然处于挂起状态??? 哪位大哥帮忙分析一下或给予一点提示,小弟不胜感激!! 答: sele...

搞笑

1.55岁的周润发宣布死后将捐出99%的财产,什么都不想带走。作家顾晓军评论道:千万不要捐到大陆来,不要害了无辜的官员。 2.发改委成立至今只做过两件事:1)涨价,2)替涨价辩护。 3.目前中国有效的反腐手段有:1夫妻反目;2家中被盗;3情人举报;4狗咬狗,5站错队 4.国外奶粉热销中国的原因:1没有三聚氰胺;2如果有,可以索赔巨款;3如果索赔不成,不会坐牢 5.1955年中国的人均收入是韩国的3.2倍,日本的1.1倍。但经过50多年翻天覆地的增长,2008年中国的人均收入是日本的3%,韩国7%,但韩国、日本从来没宣布自己经济怎么翻番,只有中国是天天说自己翻了很多番。 6.中国人固有一死,或死于地沟油,或死于石灰面粉,或死于结石奶粉,或死于毒疫苗,或死于危房,或死于拆迁,或死于躲猫猫,或死于日记,或死于酒色,或死于车轮下,或死于被自杀……死并不可怕,可怕的是你根本不知道自己是怎么死的! 7.中国不一定是和邻国土地争端最多的国家,但肯定是和本国公民土地争端最多的国家。 8.在谈所谓大国崛起之时,请扪心自问:你的收入崛起没有、你的住房面积崛起没有、你的护照免签国家数量崛起没有、你的食品安全崛起没有、你的医保社保崛起,你的国防力量增强了没有...如果都没有,那么大国再崛起关你P事。 9.日本人冈本真夜1997年的一首歌无耻地抄袭了我们2010年世博会的会歌,太可恶了!!? 10.什么是奇迹?我建了一座豆腐渣大楼,然后雇了150个短工装修,很多人说这房子容易塌,我充耳不闻。结果「哗啦」的塌了,把他们埋在废墟里整整八天八夜,我找人挖开塌坍时,有一百多人活着。这是个奇迹,更奇迹的是我他妈不但无罪,表彰会上我还成了救人的大英雄! 11.统计局宣布:中国城市人均月收入已突破9000人民币大关。拖祖国后腿的请自觉转发。 看到这个消息我不禁黯然神伤,仔细算算,我何止才拖了祖国的大腿,我都扒到祖国的臀部了,对不起,祖国---我是否扯到你的蛋了!!