跳至主要内容

【转】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系统总...

【转】GPIO编程模拟I2C入门

ARM编程:ARM普通GPIO口线模拟I2C  请教个问题: 因为需要很多EEPROM进行点对点控制,所以我现在要用ARM的GPIO模拟I2C,管脚方向我设 置的是向外的。我用网上的RW24C08的万能程序修改了一下,先进行两根线的模拟,SDA6, SCL6,但是读出来的数不对。我做了一个简单的实验,模拟SDA6,SCL6输出方波,在示波 器上看到正确方波,也就是说,我的输出控制是没问题的。 哪位大哥能指点一下,是否在接收时管脚方向要设为向内?(不过IOPIN不管什么方向都可 以读出当前状态值的阿) 附修改的RW24C08()程序: #define  SomeNOP() delay(300); /**/ /* *********************************  RW24C08   **************************************** */ /**/ /* ----------------------------------------------------------------------------- ---  调用方式:void I2CInit(void)   函数说明:私有函数,I2C专用 ------------------------------------------------------------------------------- -- */ void  I2CInit( void ) ... {  IO0CLR  =  SCL6;      // 初始状态关闭总线  SomeNOP();  // 延时   I2CStop();  // 确保初始化,此时数据线是高电平 }   /**/ /* ---------------------------------------------------------------------------- ----  调用方式:void I2CSta...

【转】cs8900网卡的移植至基于linux2.6内核的s3c2410平台

cs8900网卡的移植至基于linux2.6内核的s3c2410平台(转) 2008-03-11 20:58 硬件环境:SBC-2410X开发板(CPU:S3C2410X) 内核版本:2.6.11.1 运行环境:Debian2.6.8 交叉编译环境:gcc-3.3.4-glibc-2.3.3 第一部分 网卡CS8900A驱动程序的移植 一、从网上将Linux内核源代码下载到本机上,并将其解压: #tar jxf linux-2.6.11.1.tar.bz2 二、打开内核顶层目录中的Makefile文件,这个文件中需要修改的内容包括以下两个方面。 (1)指定目标平台。 移植前:         ARCH?= $(SUBARCH) 移植后: ARCH            :=arm (2)指定交叉编译器。 移植前: CROSS_COMPILE ?= 移植后: CROSS_COMPILE   :=/opt/crosstool/arm-s3c2410-linux-gnu/gcc-3.3.4-glibc-2.3.3/bin/arm-s3c2410-linux-gnu- 注:这里假设编译器就放在本机的那个目录下。 三、添加驱动程序源代码,这涉及到以下几个方面。(1)、从网上下载了cs8900.c和cs8900.h两个针对2.6.7的内核的驱动程序源代码,将其放在drivers/net/arm/目录下面。 #cp cs8900.c ./drivers/net/arm/ #cp cs8900.h ./drivers/net/arm/ 并在cs8900_probe()函数中,memset (&priv,0,sizeof (cs8900_t));函数之后添加如下两条语句: __raw_writel(0x2211d110,S3C2410_BWSCON); __raw_writel(0x1f7c,S3C2410_BANKCON3); 注:其原因在"第二部分"解释。 (2)、修改drivers/net/arm/目录下的Kconfig文件,在最后添加如...