Linux/Unix环境下的Make和Makefile详解

来源:互联网 发布:mac下载的软件不见了 编辑:程序博客网 时间:2024/03/28 18:31
  
是在Linux是在Unix境中,make都是一个非常重要的编译命令。不管是自己开发还是安装件,我常要用到makemake install。利用make工具,我可以将大型的开发项目分解成多个更易于管理的模于一个包括几百个源文件的用程序,使用makemakefile工具就可以简洁明快地理各个源文件之间纷复杂的相互系。而且如此多的源文件,如果次都要gcc命令编译,那程序说简直就是一。而make工具可自完成编译工作,并且可以只程序在上次编译后修改的部分编译。因此,有效的利用makemakefile工具可以大大提高开发的效率。同掌握makemakefile之后,您也不会再面Linux下的件手足无措了。

  但令人憾的是,在Linux用的籍上都没有详细绍这个功能大但又非常复杂编译工具。在里我就向大家详细一下make及其描述文件makefile

  Makefile文件

  Make工具最主要也是最基本的功能就是通makefile文件来描述源程序之的相互系并自动维护编译工作。而makefile 文件需要按照某种语写,文件中需要明如何编译各个源文件并接生成可行文件,并要求定源文件之的依赖关系。makefile 文件是编译--包括 Windows NT 下的编译--维护编译信息的常用方法,只是在集成开发环境中,用友好的界面修改 makefile 文件而已。

  在 UNIX 中,习惯使用 Makefile makfile 文件。如果要使用其他文件作 makefile可利用似下面的 make 命令选项指定 makefile 文件:

  $ make -f Makefile.debug

  例如,一个名prog的程序由三个C源文件filea.cfileb.cfilec.c以及文件LS编译生成,三个文件包含自己的文件a.h b.hc.h。通常情况下,C编译器将会出三个目文件filea.ofileb.ofilec.o。假filea.cfileb.c都要声明用到一个名defs的文件,但filec.c不用。即在filea.cfileb.c里都有这样的声明:

  #include "defs"

  那下面的文档就描述了些文件之的相互:

  ---------------------------------------------------------
  #It is a example for describing makefile
  prog : filea.o fileb.o filec.o
  cc filea.o fileb.o filec.o -LS -o prog
  filea.o : filea.c a.h defs
  cc -c filea.c
  fileb.o : fileb.c b.h defs
  cc -c fileb.c
  filec.o : filec.c c.h
  cc -c filec.c
  ----------------------------------------------------------

  个描述文档就是一个简单makefile文件。

  从上面的例子注意到,第一个字符 # 的行行。第一个非注行指定prog由三个目文件filea.ofileb.ofilec.o接生成。第三行描述了如何从prog所依的文件建立可行文件。接下来的468行分指定三个目文件,以及它所依.c.h文件以及defs文件。而579指定了如何从目所依的文件建立目

  当filea.ca.h文件在编译之后又被修改, make 工具可自重新编译filea.o,如果在前后两次编译filea.C a.h 均没有被修改,而且test.o存在的,就没有必要重新编译这种赖关系在多源文件的程序编译中尤其重要。通过这种赖关系的定make 工具可避免多不必要的编译工作。当然,利用Shell脚本也可以达到自动编译的效果,但是,Shell 脚本将全部编译任何源文件,包括哪些不必要重新编译的源文件,而 make 工具可根据目上一次编译时间和目所依的源文件的更新时间而自判断编译哪个源文件。

  Makefile文件作描述文档一般需要包含以下内容:

  宏定
  源文件之的相互依赖关
  行的命令

  Makefile中允使用简单的宏指代源文件及其相关编译信息,在Linux中也称宏为变量。在引用宏只需在量前加$符号,但得注意的是,如果量名的度超一个字符,在引用就必括号()。

  下面都是有效的宏引用:

  $(CFLAGS)
  $2
  $Z
  $(Z)

  其中最后两个引用是完全一致的。

  需要注意的是一些宏的义变量,在Unix中,$*$@$?$<四个特殊宏的行命令的程中会生相化,而在GNU make了更多的义变量。义变量的详细内容,宏定的使用可以使我脱离那些冗乏味的编译选项为编makefile文件来很大的方便。

  ---------------------------------------------------------
  # Define a macro for the object files
  OBJECTS= filea.o fileb.o filec.o
  # Define a macro for the library file
  LIBES= -LS
  # use macros rewrite makefile
  prog: $(OBJECTS)
  cc $(OBJECTS) $(LIBES) -o prog
  ……
  ---------------------------------------------------------

  此如果行不参数的make命令,将接三个目文件和文件LS;但是如果在make命令后有新的宏定

  make "LIBES= -LL -LS"

  命令行后面的宏定将覆盖makefile文件中的宏定。若LL也是文件,此make命令将接三个目文件以及两个文件LSLL

  在Unix中没有常量NULL作出明确的定,因此我要定NULL字符串要使用下述宏定

  STRINGNAME=

  Make命令

  在make命令后不可以出宏定可以跟其他命令行参数,些参数指定了需要编译的目文件。其准形式

  target1 [target2 …]:[:][dependent1 …][;commands][#…]
  [(tab) commands][#…]

  方括号中的部分表示可选项Targetsdependents当中可以包含字符、数字、句点和"/"符号。除了引用,commands中不能含有"#",也不允许换行。

  在通常的情况下命令行参数中只含有一个":",此command序列通常和makefile文件中某些定文件赖关系的描述行有。如果与目关连的那些描述行指定了相command序列,那些相command命令,即使在分号和(tab)后面的aommand字段甚至有可能是NULL。如果那些与目关连的行没有指定command,那用系的目文件生成规则

  如果命令行参数中含有两个冒号"::"command序列也会和makefile中所有描述文件依赖关系的行有。此行那些与目关连的描述行所指向的相命令。同时还build-in规则

  如果在command命令返回了一个"0"的出信号,例如makefile文件中出错误的目文件名或者出了以字符打的命令字符串,make操作一般会就此止,但如果make"-i"参数,make将忽略此信号。

  Make命本身可有四参数:志、宏定、描述文件名和目文件名。其准形式

  Make [flags] [macro definitions] [targets]

  Unix志位flags选项及其含义为

  -f file  指定file文件描述文件,如果file参数"-"符,那描述文件指向入。如果没有"-f"参数,将默当前目下名makefile或者名Makefile的文件描述文件。在Linux中, GNU make 工具在当前工作目中按照GNUmakefilemakefileMakefile序搜索 makefile文件。
  -i   忽略命令行返回的出信息。
  -s   沉默模式,在行之前不出相的命令行信息。
  -r   禁止使用build-in规则
  -n   非行模式,出所有行命令,但并不行。
  -t   更新目文件。
  -q   make操作将根据目文件是否已更新返回"0"或非"0"的状信息。
  -p  出所有宏定和目文件描述。
  -d   Debug模式,出有文件和检测时间详细信息。

  Linuxmake志位的常用选项Unix中稍有不同,下面我只列出了不同部分:

  -c dir   makefile 之前改到指定的目dir
  -I dir   当包含其他 makefile文件,利用该选项指定搜索目
  -h   help示所有的make选项
  -w   在 makefile 之前和之后,都示工作目

  通命令行参数中的target ,可指定make编译的目,并且允义编译多个目,操作按照从左向右的序依次编译target选项中指定的目文件。如果命令行中没有指定目target指向描述文件中第一个目文件。

  通常,makefile clean ,可用来清除编译过程中的中文件,例如:

  clean:
  rm -f *.o

  运行 make clean ,将 rm -f *.o 命令,最终删除所有编译过程中生的所有中文件。

  规则

  在make 工具中包含有一些内置的或含的规则规则了如何从不同的依文件建立特定型的目Unix通常支持一基于文件展名即文件名后规则这种缀规则了如何将一个具有特定文件名后的文件(例如.c文件),转换具有另一文件名后的文件(例如.o文件):

  .c:.o
  $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
  系中默的常用文件展名及其含义为
  .o  目文件
  .c  C源文件
  .f  FORTRAN源文件
  .s  汇编源文件
  .y  Yacc-C
  .l  Lex

  在早期的Unix支持Yacc-C法和Lex法。在编译过程中,系会首先在makefile文件中找与目文件相.C文件,如果有与之相依.y.l文件,首先将其转换为.c文件后再编译生成相.o文件;如果没有与目.c文件而只有相.y文件,将直接编译.y文件。

  而GNU make 除了支持后缀规则支持另一种类型的规则--模式规则这种规则更加通用,因可以利用模式规则更加复杂的依规则。模式规则看起来非常似于正则规则,但在目名称的前面多了一个 % 号,同可用来定和依文件之系,例如下面的模式规则了如何将任意一个 file.c 文件转换为 file.o 文件:

  %.c:%.o
  $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
  #EXAMPLE#

  下面将出一个较为全面的示例来makefile文件和make命令的明,其中make命令不仅涉及到了C源文件包括了Yacc法。本例"Unix Programmer's Manual 7th Edition, Volume 2A" Page 283-284

 
下面是描述文件的具体内容:

  ---------------------------------------------------------
  #Description file for the Make command
  #Send to print
  P=und -3 | opr -r2
  #The source files that are needed by object files
  FILES= Makefile version.c defs main.c donamc.c misc.c file.c /
  dosys.c gram.y lex.c gcos.c
  #The definitions of object files
  OBJECTS= vesion.o main.o donamc.o misc.o file.o dosys.o gram.o
  LIBES= -LS
  LINT= lnit -p
  CFLAGS= -O
  make: $(OBJECTS)
  cc $(CFLAGS) $(OBJECTS) $(LIBES) -o make
  size make
  $(OBJECTS): defs
  gram.o: lex.c
  cleanup:
  -rm *.o gram.c
  install:
  @size make /usr/bin/make
  cp make /usr/bin/make ; rm make
  #print recently changed files
  print: $(FILES)
  pr $? | $P
  touch print
  test:
  make -dp | grep -v TIME>1zap
  /usr/bin/make -dp | grep -v TIME>2zap
  diff 1zap 2zap
  rm 1zap 2zap
  lint: dosys.c donamc.c file.c main.c misc.c version.c gram.c
  $(LINT) dosys.c donamc.c file.c main.c misc.c version.c /
  gram.c
  rm gram.c
  arch:
  ar uv /sys/source/s2/make.a $(FILES)
  ----------------------------------------------------------

  通常在描述文件中象上面一要求出将要行的命令。在行了make命令之后,
 
  $ make
  cc -c version.c
  cc -c main.c
  cc -c donamc.c
  cc -c misc.c
  cc -c file.c
  cc -c dosys.c
  yacc gram.y
  mv y.tab.c gram.c
  cc -c gram.c
  cc version.o main.o donamc.o misc.o file.o dosys.o gram.o /
  -LS -o make
  13188+3348+3044=19580b=046174b
  最后的数字信息是"@size make"命令的果。之所以只有果而没有相的命令行,是因"@size make"命令以"@"起始,个符号禁止打印出它所在的命令行。

  描述文件中的最后几条命令行在维护编译信息方面非常有用。其中"print"命令行的作用是打印出在上次"make print"命令后所有改动过的文件名称。系使用一个名print0文件来确定print命令的具体时间,而宏$?指向那些在print文件改动过之后行修改的文件的文件名。如果想要指定print命令后,将果送入某个指定的文件,那就可修改P的宏定

  make print "P= cat>zap"

  在Linux中大多数件提供的是源代,而不是成的可行文件,就要求用根据自己系实际情况和自身的需要来配置、编译源程序后,件才能使用。只有掌握了make工具,才能真正享受到到Linux个自由件世界的带给穷乐趣。
原创粉丝点击