您的位置:首页 > 其它

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

2012-06-05 15:28 204 查看
原文地址vivi开发笔记(三):Makefile详解
作者piaoxiang

文章说明: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
下载:下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: