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

  
是在 Linux 是在 Unix 境中, make 都是一个非常重要的 编译 命令。不管是自己 开发还 是安装 件,我 常要用到 make make install 。利用 make 工具,我 可以将大型的 开发项 目分解成 多个更易于管理的模 于一个包括几百个源文件的 用程序,使用 make makefile 工具就可以 简洁 明快地理 各个源文件之 间纷 复杂 的相互 系。而且如此多的源文件,如果 次都要 gcc 命令 编译 ,那 程序 说简 直就是一 。而 make 工具 可自 完成 编译 工作,并且可以只 程序 在上次 编译 后修改 的部分 编译 。因此,有效的利用 make makefile 工具可以大大提高 开发 的效率。同 掌握 make makefile 之后,您也不会再面 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.c fileb.c filec.c 以及 文件 LS 编译 生成, 三个文件 包含自己的 文件 a.h b.h c.h 。通常情况下, C 编译 器将会 出三个目 文件 filea.o fileb.o filec.o 。假 filea.c fileb.c 都要声明用到一个名 defs 的文件,但 filec.c 不用。即在 filea.c fileb.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.o fileb.o filec.o 接生成。第三行描述了如何从 prog 所依 的文件建立可 行文件。接下来的 4 6 8 行分 指定三个目 文件,以及它 所依 .c .h 文件以及 defs 文件。而 5 7 9 指定了如何从目 所依 的文件建立目

  当 filea.c a.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 命令将 接三个目 文件以及两个 文件 LS LL

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

   STRINGNAME=

   Make 命令

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

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

  方括号中 的部分表示可 选项 Targets dependents 当中可以包含字符、数字、句点和 "/" 符号。除了引用, 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 工具在当前工作目 中按照 GNUmakefile makefile Makefile 序搜索 makefile 文件。
   -i   忽略命令 行返回的出 信息。
   -s   沉默模式,在 行之前不 出相 的命令行信息。
   -r   禁止使用 build-in 规则
   -n   非 行模式, 出所有 行命令,但并不 行。
   -t   更新目 文件。
   -q    make 操作将根据目 文件是否已 更新返回 "0" 或非 "0" 的状 信息。
   -p    出所有宏定 和目 文件描述。
   -d    Debug 模式, 出有 文件和 检测时间 详细 信息。

   Linux make 志位的常用 选项 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" 命令后所有改 动过 的文件名称。系 使用一个名 print 0 文件来确定 print 命令的具体 时间 ,而宏 $? 指向那些在 print 文件改 动过 之后 行修改的文件的文件名。如果想要指定 print 命令后,将 果送入某个指定的文件,那 就可修改 P 的宏定

   make print "P= cat>zap"

  在 Linux 中大多数 件提供的是源代 ,而不是 成的可 行文件, 就要求用 根据自己系 实际 情况和自身的需要来配置、 编译 源程序后, 件才能使用。只有掌握了 make 工具,才能 真正享受到到 Linux 个自由 件世界的 带给 穷乐 趣。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值