首页 运维 网络学院 查看内容

Make使用说明

2009-6-25 09:23 549 0

摘要:   Make是一种代码维护工具.在大中型项目中,他将根据程序各个模块的更新情况,自动的维护和生成目标.能很好的做到”不多”,”不重””不漏”.  不多:他只更新那些需要更新的文件,而不懂那些并不过时的...
关键词: 文件 目标 Make 命令 makefile 属性 mylib 成员 一个 规则

  Make是一种代码维护工具.在大中型项目中,他将根据程序各个模块的更新情况,自动的维护和生成目标.能很好的做到”不多”,”不重””不漏”.  不多:他只更新那些需要更新的文件,而不懂那些并不过时的东西  不重:是指当make对某个文件进行更新时,即使有很多文件过时,他也将只更新一次,当然,这一次就足够了  不漏:是指他不会漏下任何应该更新的文件.  1,make的基本使用  make在使用时有一系列的规则,他将根就这些规则来解释他的配置脚本,以达到它的设计目的.这个配置脚本的缺剩名是makefile ,Makefile.也可以用其它文件名.我们这里所讲的make的应用就是怎样写出高效,简洁,正确的makefile文件.  Make的使用形式为  Make [option] [macrodef][target]  Option指出make的工作行为,make的具体选项有:  -c dir make在开始运行后的工作目录为指定目录  -e 不允许在makefile中队环境的宏赋值  -f filename 使用指定的文件作makefiel  -k 执行命令出错时,放弃改目标去维护其它目标  -n 按实际运行时的执行顺序现实命令,包括用@开头的命令,但不振的执行  -p -现实makefile中所有的宏定义,河内部规则  -r 忽略内部规则  -s 执行但不显示命令,常用来检查makefile的正确性  -S 执行make时 出错即退出  -t 修改每个目标文件的创建日期,但又不正的创建  -V 打印make的版本号  -x 将所有的宏定义输出的shell环境中  -i  忽略运行make 中的错误,而又不退出make  在使用make 维护目标的时候,为了调试错误,常使用 make 2 > errofile.这样错误信息就都写入了errofile  2.1makefile 的基本书写  make 使用的依据是依赖关系.如又工程example ,他依赖于main.o e1.o e2.o,而main.o 依赖于main.c l.h .e1.o依赖于e1.c l.h ,e2.o 依赖于e2.c.  这样就形成一棵树.及双亲节点,依赖于孩子节点.当make 进行维护时.他呼对这棵树.进行一次后序遍历.如果发现孩子节点形成的时间晚于双亲节点形成的时间.便开始维护.原理十分简单.  现在,我们开始,我们的主要内容: 如何书写makefile.makefile 是供make 使用的一个配置脚本.他是按一定的规则写成的.它的组成是以一个要维护的目标为一个单元,每个单元的书写形式如下:  要维护的目标列表 要维护的目标属性 分割符(一般为 依赖的文件列表 命令行的属性 ;第一条命令  tab键 命令1…..  需要说明的是,第一条命令可以加; 跟在依赖文件列表后,也可以和其它的命令另起一行写.一定要记得加tab键.否则make 不认识.当一条命令太长一行放不下是使用/l来换行.  注释行用#开头.  这样一来.我们前面举的例子就可以写成这样的makfile  example : main.o e1.o e2.o  gcc -o example main.o e1.o e2.o  main.o :main.c l.h  gcc -c main.c  e1.o :e1.c l.h  gcc -c e1.c l.h  e2.o:e2.c  gcc -c e2.c  可以用cat -e -v-t makefile 其中-v-t可以让tab键显示^I ,是makefile 的末尾显示$,这样可以检验,makefile的正确性.  可见,书写一个简单的makefile文件并不困难.然而在大中型项目中.要通过makfile 做大量的维护与调试.这样会是程序员增加很大的工作量.因此,make 引入了一些属性变量,和宏变量,来控制make .甚至可以像c预言的条件编译那样.通过一些shell语句来控制.接下来.我们将一一讲解.  2.2 makfile中的属性控制  2.2.1分割符  分割符一般用: 但也用::,:!:^,:-一下举例说明一下这几个分割符的作用一般目标文件只能出现一次.只有使用::时才可以出现多次如:  a.o::a.c  #命令1  a.o::b.c  #命令2  意思是:如果a.c更新.使用命令1.b.c更新使用命令2  :^ 将指定的依赖文件和目标文件一有的依赖文件结合起来  :- 清除目标文件原有的依赖文件,将指定文件为目标文件的唯一依赖文件  :! 对每个更新过的依赖文件都执行一遍命令菜单  如:  a.o :b.c  a.o:^ c.c  此时a.o 的依赖文件是b.c 和c.c  a.o:- a.c  此时 a.o 的依赖文件只剩下a.c了  2.2.2 命令行属性  命令好属性较简单只有三种  + 当运行条件成熟(依赖文件过时) 始终执行,即使 make 有 -n -q -t 选项  - 当此行出错时,忽略继续运行make  @ 不显示本行命令(make 执行使命令行在屏幕上打印)  2.2.3 目标文件属性  目标属性比较多.这里举几个常用的例子  .IGNORE 类似于命令行中的减号,在本目标维护出错时.并不马上退出make 而是继续运行  .SILENT 类似于命令行中的@ ,维护本目标时不在屏幕上显示  .PRECIOUS 保留中间文件  .LIBARY 说明维护的目标是一个库  .SYMBOL 说明维护的目标是指定入口的库成员  .LIBRARYM 说明维护的是库的一个成员  在使用目标文件的属性时有两种方法  .IGNORE main.o e1.o 和  main.o .IGNORE : ….  ……  e1.o .INGORE :…..  …….  效果是相同的,在实际使用时,可以根据个人的具体情况使用.  2.2.3 伪目标  在make 中有两类目标,一类是实目标.一类是伪目标.伪目标不要求make生成世纪的目标文件,只是完成一些辅助性的工作,如打印,删除等.伪目标有两种.一种是任意给出名字如:  lp:  pr *.c/lp  将所有的源文件分页打印.由于系统中没有lp 文件,他总是认为是过时的,因此这个命令总被执行.  另一种方式是使用linux提供的伪目标  .ERRO :依赖文件  命令行  作用时,一旦遇到错误时,执行命令行  .INCLUDE :file1 file2  作用是: 将文件包含进来,注意:这里的包含不是指针的转移而是拷贝  .INCLUDE /usr  .INCLUDE file1  make 首先在当前目录下寻找file1,如没有则在/usr下找.另一种使用方法是:  /INCLDE <dir/filename>  .IMPORT 将一些宏载入 .如:  .IMPORT shell 这样makefile 便可以使用shell 里的宏了.  .EXPORT 和.IMPORT恰恰相反.是将makefile里定义的宏,输出到环境.不赘述.  当需要维护几个目标时可使用这样的伪目标:  all: main.o main1.o ….  重要说明是: 命令行属性>>目标文件属性>>make 命令行属性  3.宏的使用  我们在各种应用中已熟悉宏的概念.不赘述.在make 中使用宏也要先定以后使用.宏名可以是任意数字.字母 下划线的组合. 不过不能用数字开头.  宏的定义方式有3种  = 直接将后面的字符串赋给宏  := 后面跟字符串常量,将他的值赋给宏  += 宏原来的值加上一个空格,将它的内容赋给宏  宏的应用各是有两种:  $(宏名) 或 ${宏名}  宏名可以嵌套使用.如  h2=mylib.a  index=2  则在makefile 中调用$(h$(index)) ,就等于调用 mylib.a.使用shell 环境的宏.不需要定义.只要用.IMPORT 在如就行.  3.2 内定义宏  控制宏为了控制make 的属性,定义了一系列的内定义宏.分为两类.控制宏用于控制make 的属性.属性宏代表一些特殊的值.  控制宏:  .DIREPATR 表示路径中用于分割目录与文件的分割符一般为 /  .MAKDIR 调用make的绝对路径名  .NULL 空字符串  .PWD 运行make 时活动目录的绝对目录名  .SHELL 运行是的shell 名  另一类宏.我们成为属性宏.和目标文件的属性书写和意义都相同.用于设置这些属性.如  .IGNORE=yes  将整个makefile里的目标文件都设为.IGNORE.其它的属性宏.和目标文件属性里面的相同.  3.3 动态宏  引入动态宏的目的是,简化makefile的书写.他利用了很多一用的代码.但给makefile 带来了不可读性  $@ 当前目标文件的名字  $% 同$@,不过若维护的目标是库时.$@指库名 $% 指库成员  $> 适用于lib(member)的情况$>指库名 如$@  $* 目标文件,去掉后缀  $& 当前目标文件.在所有依赖文件  $^ 当前目标文件 在本单元中的依赖文件  $? 当情目标文件 在所有单元中比目标新的依赖文件  $< 当前目标文件 在本单元中比目标文件新的文件  这些宏只能用在命令行中.make 提供可与此对应的动态宏用在依赖文件中.他们分别是在上面的宏上在加一个$  $$@ 在依赖文件列表中,代表目标文件的名字  等等.这样,我们原先的makefile便可以写成:  example:main.o e1.o e2.o  gcc -c $?  main.c e1.c:$$*.c l.h  gcc -o $*.c  e2.c :$$*.c  gcc -o $*.c  3.4 宏的修改  一个宏定义以后.可以用make的某些功能.对其进行修改  1,如:file=/usr/l/main.c 引入修改描述符:  d :仅展开目录  b :仅展开文件名,不包括扩展名  f :展开全名  这样$(file:d)等于main . 其它的类推  2,替换宏中的字符串 规则 宏名: s /远字符串/新字符串  file =file1.o file2.o file3.o  file:s/file/fun  则file=fun1.o fun2.o fun3.o  3.还有 宏名:^前缀 宏名:+后缀  file= a b c  file=^"1"则  file=1a 1b 1c  4.内部规则  4.1make 的内部规则是系统或者后呼吁定义的一些规则.他在定义时.不必指出全名.只是定义了一些最常用的依赖关系和依赖命令.和c 编程有关的就以下.这几种情况  与c编程又过的文件扩张名是  .o 目标文件  .c c语言源文件  .C c++语言源文件  .h 头文件  与c 相关的规则主要有  .c:  $(CC)$CFLAGS)-O $@ $<  .c .o:  $(CC)$CFLAGS)-c $@ $<  这里面使用到了一些宏.以上两句话的意思是对.c 文件缺剩是的编译.和编译成.o 文件.有必要说一些宏的定义  宏名 初始值 说明  AR Ar 库管理命令  ARFLAGS -ruv 库管理命令选项  CC cc C编译命令  CGLAGS -o C编译命令选项  C++C CC C++编译命令  C++FLAGS -O C++编译命令  MAKE make MAKE命令  MAKEFLAGS NULL MAKE命令选项  LIBSUFFIX .a 库的扩展名  A .a 库的扩展名  有了内部规则.我们的makefile 会更加简练如原先的makefile 我们可以写成  example:main.o e1.o e2.o  gcc -o example main.o e1.o e2.o  main.o e1.o :l.h  4.2修改和定义内部规则  修改内部规则.可以有两种办法:一是修改内部规则用到的宏.而是直接修改内部规则的命令行  如我们前面提到的规则:  .c .o:  $(CC)$(CFLAGS)-c $@ $<  我们只要定义 CC=6788 其命令行就变成了 6788 -O -c $@ $< 原因是makefile 内部的宏定义大于make 的默认定义  至于写该命令行,直接在makefile 中写就行了.他会踢换掉默认的定义 如  .c .o:  $(CC) -c $@ $<  就会以下面这个定义为主  对于一些没有的后缀名可以自己定义,各时如:  new roman 后缀名1 后缀名2 …  .SUFFIXES .n 就定义了一个新的后缀n .从目标文件生成文字表文件的命令是:  nm 目标文件 > 名字表文件  现在我们定义一个内部规则,即.o 文件依赖于通明的.o 文件  .SUFFIXES .n  .o.n  nm $< > $@  这样的话.make 会根据.o文件的更新,自动的维护.n 文件  5.库的使用  5.1库的建立和维护  在开发大中型软件时.常把一些编译好的模块同意放到一个库中.在编译时可以节省时间和空间.  库中的文件一般成为库的成员.成员的表示形式一般为  库名(库成员名) 如: mylib(myrea.o) 用make 维护库时,我们将库名作为目标文件格式如下:  库名: 库名(库成员名1) 库名(库成员名2) 库名(库成员名3)  make 遇到这样的命令行 ,自动吧库名当成目标文件,并赋予.LIBRARY属性 例如:  mylib.a :mylib.a(myread.o) … 也可以这样定义  mylib.a .LIBRAAY :myread.o …还有一种定义方式是:  库名: ((rentry))  make 遇到这种情况,把库名置成.LIBRARY 把entery 置成 .SYMBOL.然后根据entry 找到相应的文件以后的处理和直接些文件相同  make 从.o 文件维护库的命令是  ae -ruv 库名 目标文件名  如维护一个名为mylib的库.makefile 需要这样写  mylib:mylib(f1.o)  gcc -c fi.c  ar -ruv muylib f1.o  rm -f f1.o  mylib:mylib(f2.o)  gcc -c f2.c  ar -ruv muylib f2.o  rm -f f2.o  ……  利用动态宏我们可以将他该成这样:  mylib:mylib(f1.o f2.o…..)  gcc -c ($?:b).c  ar -ruv $@ $?  rm -f $@  我们也可以利用内部规则,来简化所有makefie 中 库的维护  .o.a:  $(AR) $(ARFLAGS) $@ $?  rm -f $?  然后库的makfile 写成  mylib: mylib(f1.o) mylib(f2.o)………  还有一条内部过则是:  .a  make $@  即make 将自动维护所有的库  5.2 利用库进行连接  使用库进行连接时.只需要将库名.o文件名说明就行.形式如下:  库名(库成员名) 或 库名(((成员entery))  例如想在有一可执行程序eampl2.exe 依赖于mylib 中的f1.o ,在makefile 中可以这么写:  eampl2.exe:mylib(f1.o)  #连接命令行(一般是ld)  make 读到这样的规则就知道  mylib 是一个库.有.LIBRAAY的属性  f1.0 是库的成员函数 有.LIBRAYM的属性  eampl2.exe 依赖于f1.o  在这里也有意跳内部规则  .o.e  $(LD) $(LDFLAGES) -o $@ $< $(LDLIB)  其中宏的定义是  LD 连接命令ld  LDFLAGEA ld 的选项]  LDLIB 库名列表  因此只要把你自己定义的库,加到库名列表中,在使用内部规则就行了.如上例可以写成:  LDLIB+=mylib.a # 将自定义的库加到 库名列表中去  eaple2.exe:mylib(f1.o)  7.条件编译  make 中还引入了一些shell 语法.以帮助进行类似于c 语言的于编译的功能.下面是在linux核心的makfile 中抄来的一段.我们可以看一下他是如何进行条件维护的  ifeq (.config,$(wildcard .config))  include .config  ifeq (.depend,$(wildcard .depend))  include .depend  do-it-all: Version vmlinux  else  CONFIGURATION = depend  do-it-all: depend  endif  else  CONFIGURATION = config  do-it-all: config  endif  类似于c 语言的 if else 语句.不同的是他是比较两个值是否相等,来判断是否满足条件.因为在makefile中.很多值是由字符串组成的,所以这个于就十分有用.  还有这样的语句:  ifdef CONFIG_PCI  DRIVERS := $(DRIVERS) drivers/pci/pci.a  endif  这个语句够简单,我多说什么了.  本文只是一个简单的说明.make 的内容很多.有兴趣的可以参考它的man 手册.不过编制好的makefile ,是要在实践中掌握的.
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部