栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Makefile编写基础

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Makefile编写基础

1.Makefile总述

在一个完整的 Makefile 中,包含了 5 个东西:显式规则、隐含规则、变量定义、指示符和注释。关于“规则”、“变量”和“ Makefile 指示符”将在后续的章节进行详细的讨论。本章讨论的是一些基本概念。

• 显式规则:它描述了在何种情况下如何更新一个或者多个被称为目标的文件( Makefile 的目标文件)。书写 Makefile 时需要明确地给出目标文件、目标的依赖文件列表以及更新目标文件所需要的命令(有些规则没有命令,这样的规则只是纯粹的描述了文件之间的依赖关系)。

• 隐含规则:它是 make 根据一类目标文件(典型的是根据文件名的后缀)而自动推导出来的规则。 make 根据目标文件的名,自动产生目标的依赖文件并使用默认的命令来对目标进行更新(建立一个规则)。

• 变量定义:使用一个字符或字符串代表一段文本串,当定义了一个变量以后, Makefile 后续在需要使用此文本串的地方,通过引用这个变量来实现对文本串的使用。

• Makefile 指示符:指示符指明在 make 程序读取 makefile 文件过程中所要执行的一个动作。其中包括:

– 读取一个文件,读取给定文件名的文件,将其内容作为 makefile 文件的一部分。

– 决定(通常是根据一个变量的得值)处理或者忽略 Makefile 中的某一特定部分。

– 定义一个多行变量。

• 注释: Makefile 中“ # ”字符后的内容被作为是注释内容(和 shell 脚本一样)处理。如果此行的第一个非空字符为“ # ”,那么此行为注释行。注释行的结尾如果存在反斜线(),那么下一行也被作为注释行。一般在书写 Makefile 时推荐将注释作为一个独立的行,而不要和 Makefile的有效行放在一行中书写。当在 Makefile 中需要使用字符“ # ”时,可以使用反斜线加“ # ”( # )来实现(对特殊字符“ # ”的转义),其表示将“ # ”作为一字符而不是注释的开始标志。

2.make与Makefile的关系

make是linux下的二进制程序,用来处理Makefile这种文本文件。在linux的Shell命令行键入make的时候,将自动寻找名称为“Makefile”的文件作为make的时候,如果没有名称为“Makefile”的文件,将继续查找名称为“makefile”的文件。找到编译文件后,make工具将根据Makefile中的第一个目标自动寻找依赖关系,找出这个目标所需要的其它目标。如果所需要的目标也需要依赖其它的目标,make工具将一层层寻找直到找到最后一个目标为止。

  1. make工具的使用格式为:
  2. make [options] [target] …
  3. options为make工具的参数选项,target为Makefile中指定目标。

表1给出了make工具的参数选项。

表1 make工具的参数选项

3.Makefile的书写规则
  1. 任何一种编程语言都有自己的语法规则,Makefile的语法格式如下:

targets : prerequisites

command

  1. 或者是:

targets : prerequisites ; command

       command

  1. targets是目标文件名称,多个文件以空格分开,可以使用通配符。一般来说,Makefile的目标是一个文件,但也有可能是多个文件。
  2. prerequisites是目标所依赖的文件(或依赖目标)。
  3. command是命令行,如果它不与“targets : prerequisites”在一行,那么,必须以Tab键开头,如果和prerequisites在一行,那么可以使用分号作为分隔。如果命令太长,可以使用反斜杠“”作为换行符。make对一行上有多少字符没有限制。规格告诉make两件事,文件的依赖关系和如何生成目标文件。
  4. 一般来说,make会以UNIX的标准Shell,也就是/bin/sh来执行命令。

举例:

4.在makefile规则中使用通配符
  1. 如果想定义一系列比较类似的文件,我们很自然地就想起使用通配符。Make支持三种通配符:“*”(任意长度的字符串)、“?”(单个任意长度的字符)、“[…]”,这个UNIX和BShell是相同的。
  2. 通配符代替了一系列的文件,如“*.c”表示了所有以后缀名为.c的文件。如果文件名中含有通配符,如“*”,那么可以用转义字符斜杠“”,如“*”来表示真实的“*”字符,而不是任意长度的字符串。
  3. 下面是一个在命令中使用通配符的例子:

clean :

       rm -f *.o

例子的含义是删除所有以.o为后缀名的文件,这是由操作系统的shell所支持的通配符。

  1. 通配符也可以使用在Makefile的规格中,比如:

print : *.c

lpr -p $?

touch print

目标print依赖于所有的.c文件。其中“$?”是一个自动化变量,表示所有比目标新的依赖文件的集合。

  1. 通配符还可以使用在变量中,比如:

objects = *.o

需要注意的是,这个上面的两种情况不同,这里的*.o不会展开!objects变量的值就是“*.o”。

Makefile中的变量其实就是C/C++中的宏。如果要让通配符在变量中展开,也就是让objects的值是所有.o的文件名的集合,那么,可以这样:

objects :=$(wildcard *.o)

这种用法是通过Makefile 的关键字“wildcard”在指示的。

5.伪目标
  1. “clean”目标,这是一个伪目标。伪目标并不是一个文件,而只是一个标签,Makefile并不生成“clean”这个文件。
  2. 由于伪目标不是文件,所以make无法生成它的依赖关系和决定它是否要执行,只有通过显示地指明这个“目标”才能让其生效。需要注意的是,伪目标的取名不能和文件名重名,不然其就失去其伪目标的意义了。

当然,为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是伪目标,向make说明,不管是否有这个文件,这个目标都是伪目标。

  1. .PHONY:clean

只要这个声明,不管是否有“clean”文件,要运行“clean”这个目标,只要在命令提示符下输入命令“make clean”即可。

6.多目标
  1. Makefile规则中的目标可以不止一个,其支持多目标,当Makefile中的多个目标同时依赖于同一个文件,并且其生成的命令大体类似,就能把它们合并起来。
  2. 当然,多个目标的生成规则的执行命令是同一个,这可能会给我们带来麻烦,不过好在我们可使用一个自动化变量“$@”,这个变量意味着目前规则中所有的目标的集合。
  3. 对于多个具有类似重建命令的目标。重建这些目标的命令并不需要是完全相同,因为可以在命
  4. 令行中使用自动环变量“$@”来引用具体的目标,完成对它的重建。例如规则:

bigoutput  littleoutput  :  text.g

generate  text.g  -$(subst  output,,$@)  >  $@

其等价于:

bigoutput  :  text.g

generate  text.g  -big  >  bigoutput

littleoutput  :  text.g

generate  text.g  -little  >  littleoutput

例子中的“ generate ”根据命令行参数来决定输出文件的类型。使用了 make 的字符串处理函数“ subst ”来根据目标产生对应的命令行选项。

7.Makefile的命令

Makefile中,make会按顺序一条一条地执行命令,每条命令必须以“Tab”键开头,除非命令是紧跟在依赖规则后面的分号后的。

8.Makefile的变量
  1. Makefile的变量就像是C/C++语言中的宏,代表了一个文本子串,在Makefile执行的时候会自动地展开在所使用的地方。与C/C++的宏所不同的是,Makefile变量的值是可以改变的。在Makefile中,变量可以使用在目标、依赖目标、命令或是Makefile的其它部分中。
  2. 变量在声明时需要给予初值,而在使用时,需要在变量名前加上“$”符号,但最好用小括号“( )”或是大括号“{ }”把变量给包括起来。如果要使用真实的“$”字符,那么需要用“$$”来表示。

9.函数

10.隐式规则
  1. 隐式规则即Makefile预先约定好了的,不用再写出来的规则。比如把.c文件编译成.o文件这一规则,不用写出来,make便会自动推导,并生成我们需要的.o文件。隐式规则会使用一些系统变量,可以改变这些系统变量的值来定制隐式规则运行时的参数。如系统变量“CFLAGS”可以控制编译时的编译器参数。还可以通过模式规则的方式自定义隐式规则。
  2. 如果要使用隐式规则来生成目标,就不需要写出这个目标的规则,make会试图去自动推导产生这个目标的规则和命令,如果make可以自动推导生成这个目标的规则和命令,那么这个行为就是隐式规则的自动推导。隐式规则是make事先约定好的一些东西。

使用 make 内嵌的隐含规则,在 Makefile 中就不需要明确给出重建某一个目标的命令,甚至可

以不需要规则。 make 会自动根据已存在(或者可以被创建)的源文件类型来启动相应的隐含规则。

例如:

foo  :  foo.o  bar.o

cc  -o  foo  foo.o  bar.o  $(CFLAGS)  $(LDFLAGS)

可以看到,这个Makefile中并没有写下如何生成foo.o和bar.o这两个目标的规则和命令。因为make的隐式规则功能会自动去推导这两个目标的依赖目标和生成命令。也就是说,完全没有必要写出下面的两条规则:

foo.o:foo.c

       cc -c foo.c $(CFLAGS)

bar.o:bar.c

       cc -c bar.c $(CFLAGS)

make使用约定好的C编译器“CC”生成.o文件,这就是隐式规则。

11.隐式规则中的变量
  1. 内嵌隐含规则的命令中,所使用的变量都是预定义的变量。我们将这些变量称为“隐含变量”。这些变量允许对它进行修改:在 Makefile 中、通过命令行参数或者设置系统环境变量的方式来对它进行重定义。无论是用那种方式,只要 make 在运行时它的定义有效, make 的隐含规则都会使用这些变量。当然,也可以使用“ -R ”或“ –no–builtin-variables ”选项来取消所有的隐含变量(同时将取消了所有的隐含规则)。
  2. 例如,编译 .c 源文件的隐含规则为:“ $(CC) -c $(CFLAGS) $(CPPFLAGS) ”。默认的编译命令是“ cc ”,执行的命令是:“ cc –c ”。我们可以同上述的任何一种方式将变量“ CC ”定义为“ ncc ”,那么编译 .c 源文件所执行的命令将是“ ncc -c ”。同样我们可以对变量“ CFLAGS ”进行重定义。对这些变量重定义后如果需要整个工程的各个子目录有效,同样需要使用关键字“ export ”将他们导出;否则目录间编译命令可能出现不一致。编译 .c 源文件时,隐含规则使用“ $(CC) ”来引用编译器;“ $(CFLAGS) ”引用编译选项。
  3. 隐含规则中所使用的变量(隐含变量)分为两类: 1. 代表一个程序的名字(例如:“ CC ”代表了编译器这个可执行程序)。 2. 代表执行这个程序使用的参数(例如:变量“ CFLAGS ”),多个参数使用空格分开。当然也允许在程序的名字中包含参数。但是这种方式建议不要使用。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/883886.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号