分析uClinux中Makefile文件的方法
uClinux中Makefile文件整体分析作者:佚名来源:不详发布时间:2006-9-218:15:08发布人:zangyl
减小字体增大字体
(转载)
1、概述
uClinux/目录下的这个Makefile是个总领式的文件,通过它又层层包含调用各个目录、子目录下面对应Makefile,就这样层层调用下去,从而完成整个软件系统的编译。
2、具体分析
下面根据uClinux/Makefile文件的内容(内容有删节)大致介绍一下整个编译的调用关系。
----------------------------------------------------------------------------------------
includecommon.mk
----------------------------------------------------------------------------------------
首先包含common.mk,它里面定义了一些通用的全局变量,例如:common.mk文件中有如下内容:
.EXPORT_ALL_VARIABLES:
(相当于C中的extern关键字,表示下面的宏变量可以为其它文件所使用)
ROOTDIR=$(shellpwd)
TOOLS=$(ROOTDIR)/tools
----------------------------------------------------------------------------------------
.EXPORT_ALL_VARIABLES
----------------------------------------------------------------------------------------
输出下面所有全局变量
----------------------------------------------------------------------------------------
IMAGEFILE=image.bin
IMAGEZFILE=imagez.bin
ELFFILE=image.elf
SRECFILE=image.srec
IMAGE=$(ROOTDIR)/images/$(IMAGEFILE)
IMAGEZ=$(ROOTDIR)/images/$(IMAGEZFILE)
ELFIMAGE=$(ROOTDIR)/images/$(ELFFILE)
SRECIMAGE=$(ROOTDIR)/images/$(SRECFILE)
ROMFS=$(ROOTDIR)/romfs
ROMFSIMG=$(ROOTDIR)/images/romfs.img
TOPDIR=$(ROOTDIR)/linux
HOSTCC=unsetGCC_EXEC_PREFIX;gcc-I$(TOPDIR)/include
DIRS=linuxlibuser
----------------------------------------------------------------------------------------
all告诉编译器执行make都要分完成哪些工作步骤,这是最重要的地方!
看一个Makefile首先要从它的all看起,就相当于C语言的main()函数的作用。
然后再从all层层分析下去。
----------------------------------------------------------------------------------------
all:config-testsubdirsbuild-romfs$(IMAGE)
----------------------------------------------------------------------------------------
这里共四步工作,即:
----------------------------------------------------------------------------------------
*config-test
*subdirs
*build-romfs
*$(IMAGE),即上面的IMAGE变量,Makefile中用$(变量名)来使用变量,这中用法对许多熟悉各种脚本语言的用户并不陌生。
下面在Makefile分别找到各步工作对应的部分:
----------------------------------------------------------------------------------------
(1)config-test:
@if[!-f.config-o!-flinux/.config-o!-f
vendors/.config];then/
----------------------------------------------------------------------------------------
若找不到.config文件或者找不到linux/.config或者找不到
vendors/.config文件,就提示需要makeconfig或者makexconfig
----------------------------------------------------------------------------------------
echo"ERROR:youneedtodoa'makeconfig'first";/
exit1;/
fi
@if[!-dromfs];then/
【必须有romfs这个目录】
echo"ERROR:youneedtorun'makeromfs'asrootfirst";/
exit1;/
fi
(2)subdirs
subdirs:
@if[!-flinux/.depend];then/
【若没找到linux/.depend文件,就提示要makedep】
echo"ERROR:youneedtodoa'makedep'first";
exit1;/
fi
fordirin$(DIRS);domake-C$$dir||exit1;done
----------------------------------------------------------------------------------------
【上面这一句虽短,但确是最主要的工作所在,注意到前面定义了:
DIRS=linuxlibuser
因此这一句:
make-C$$dir
就完成了对内核(linux目录)的编译、对libC库(lib)的编译、对所有应用程序(user下所有指定要编译的目录)的编译。
make-C$$dir就调用对应那个目录下的Makefile,即分别是linux/Makefile,lib/Makefile和user/Makefile,这Makefile又层层包含调用下面的各个目录的Makefile,从而完成整个编译过程。】
其中编译user下各个应用程序时,每个应用程序目录下的Makefile中都要执行如下一句:
$(CONVERT)
这个宏是在uClinux/user/arch/coldfire/目录下的build.mk文件中指定的,这个文件的作用就相当于uClinux/common.mk,它为应用程序的编译定义了许多公共的宏,例如所采用的编译器(CC)等。LINUX内核都是用m68k-coff-gcc编译的,但应用程序可以采用不同的gcc编译器。
这个文件的部分内容如下:
.EXPORT_ALL_VARIABLES:
CC=$(TOOLS)/m68k-elf-gcc
CXX=$(TOOLS)/m68k-elf-g++
AR=$(TOOLS)/m68k-elf-ar
LD=$(TOOLS)/m68k-elf-ld
OBJCOPY=$(TOOLS)/m68k-elf-objcopy
RANLIB=$(TOOLS)/m68k-elf-ranlib
ELF2FLT=$(TOOLS)/elf2flt
GCC_EXEC_PREFIX=$(TOOLS)/m68k-elf-
LIBC=$(ROOTDIR)/lib/libc/libc.a
LIBM=$(ROOTDIR)/lib/libm/libmf.a
LIBNET=$(ROOTDIR)/lib/libnet/libnet.a
LIBDES=$(ROOTDIR)/lib/libdes/libdes.a
LIBPCAP=$(ROOTDIR)/lib/libpcap/libpcap.a
LIBSSL=$(ROOTDIR)/lib/libssl/libssl.a
LIBCRYPTO=$(ROOTDIR)/lib/libssl/libcrypto.a
LIBGCC=$(TOOLS)/gcc-lib/libgcc.a
ARCH=-m5200-Wa,-m5200-DCONFIG_COLDFIRE
DEFS=-Dlinux-D__linux__-Dunix-DEMBED
INCS=$(INCGCC)$(INCLIBC)$(INCLIBM)$(INCVEND)
CCFLAGS=-O2-msoft-float【编译参数】
CFLAGS=$(DEBUG_CFLAGS)$(ARCH)$(DEFS)$(CCFLAGS)$(INCS)-
fno-builtin【编译参数】
LDFLAGS=--sort-common-r$(STARTUP)【链接参数】
最后定义了CONVERT宏:
CONVERT=mv$$@.elf.$$@.elf;/
$(LD)-T$(LDSCRIPT)-Ur-o$$@.elf.$$@.elf;/
$(LD)-T$(LDSCRIPT)-o$$@.gdb.$$@.elf;/
rm-f.$$@.elf;/
$(ELF2FLT)$$(FLTFLAGS)-o$$@$$@.elf
它采用elf2flt工具将编译生成的ELF格式可执行文件转换为uClinux所支持的FLAT文件格式。
【注】
uClinux唯一支持的可执行文件格式就是FLAT格式。其它都不支持。
所以所有要在uClinux上跑的应用都必须转换为FLAT格式。PCREDHATLINUX不支持这种格式的可执行文件,所以这些可执行文件都无法在PC上
执行。
(3)build-romfs
build-romfs:images
make-fromfs.mk
build-romfs后面跟了images,表明它依赖于images先执行的结果:
images:
[-dimages]||mkdirimages
images只是检查是否有images目录,若没有就创建该目录。
下面的make-fromfs.mk就调用执行romfs.mk。
下面是romfs.mk文件中的内容:
这也是个Makefile,因此如前所述,要从它的all入口看起:
all:copy-files
$(TOOLS)/genromfs-v-V"ROMdisk"-f$(ROMFSIMG)-d
$(ROMFSDIR)
all要先依赖copy-files部分的完成:
copy-files:
cp$(RAMFSy)romfs/etc/ramfs.img
[!"$(BINy)"]||cp$(BINy)romfs/bin/.
rmromfs/etc/services
rmromfs/etc/inetd.conf
make-Cuserbuild-romfs
-findromfs-nameCVS|xargsrm-rf
这里主要的工作就是一句:
[!"$(BINy)"]||cp$(BINy)romfs/bin/.
完成user/下各个参与的应用程序目录下的编译生成的可执行文件的收集,将它们复制到romfs/bin/目录下。
下一步就是romfs目录的打包,生成romfs.img二进IMAGE文件,它就是我们常说的ROMFS文件系统的映像文件:
$(TOOLS)/genromfs-v-V"ROMdisk"-f$(ROMFSIMG)-d$(ROMFSDIR)
至此就完成了romfs.mk中的工作,下面返uClinux/Makefile的内容继续:
(4)$(IMAGE)
IMAGE变量为:
IMAGE=$(ROOTDIR)/images/image.bin
这就是最后被复制到/tftpboot/目录下的image.bin文件,也就是最后可以烧写或下载的二进制IMAGE文件。
$(IMAGE):imagesimages/linux.bin
catimages/linux.bin$(ROMFSIMG)>$(IMAGE)
$(TOOLS)/cksum-b-o2$(IMAGE)>>$(IMAGE)
cp$(IMAGE)/tftpboot
首先依赖于images和image/linux.bin。
images/linux.bin:imageslinux/linux
$(TOOLS)/m68k-elf-objcopy-Obinary
--set-section-flags=.romvec=CONTENTS,ALLOC,LOAD,READONLY,CODE
linux/linuximages/linux.bin
image/linux.bin又依赖linux/linux,它是前面make–Clinux时根据linux目录下的Makefile规则编译生成的。然后用m68k-elf-objcopy将linux/linux文件转换为二进制文件images/linux.bin。
然后用:
catimages/linux.binimages/romfs.img>images/image.bin
最后,将images/image.bin复制到/tftpboot目录下,从而完成整个编译过程。
【注意】
Makefile中使用了许多.PHONY:节,它并没有什么作用,只是告知编译器,它的:号后面并不是一个文件。例如:
.PHONY:romfs(没有这句也可以,但是若目录下有一个文件名字叫做romfs,则会报错make:`‘romfs’isuptodate。加了PHONY就是通知编译器,不要把romfs看作一个目标文件。)
romfs:
……
Makefile还提供了许多独立的目标,可以直接用make命令指定目标单独编译。例如:
dep:
@if[!-flinux/.config];then/
echo"ERROR:youneedtodoa'makeconfig'
first";/
exit1;/
fi
make-Clinuxdep
就可以直接makedep执行。
romfs:
make-fromfs_cvs.mk
["$(CONFIG_VENDOR)"]||echo"******/nrun'makeconfig'
first/n******"
make-Cvendors/$(CONFIG_VENDOR)/$(CONFIG_PRODUCT)/.romfs
就可以直接makeromfs执行。
本文地址:http://www.45fan.com/a/question/70463.html