编写Makefile文件

来源:互联网 发布:sql按年月统计count 编辑:程序博客网 时间:2024/05/01 09:18
编写Makefile文件 来源: 作者:articleman 发布时间:2007-05-07
   
<script type="text/javascript"><!--google_ad_client = "pub-8876982994034985";google_ad_width = 336;google_ad_height = 280;google_ad_format = "336x280_as";google_ad_type = "text_image";//2007-08-10: article_336_280google_ad_channel = "3323035408";google_color_border = "FFFFFF";google_color_bg = "FFFFFF";google_color_link = "000000";google_color_text = "000000";google_color_url = "000000";google_ui_features = "rc:0";//--></script> <script src="编写Makefile文件%20-%20Linux伊甸园----Linuxeden_com-LinuxUnix新闻下载技术文档论坛人才_files/show_ads.js" type="text/javascript"></script>

编写Makefile文件

引自:http://blog.chinaunix.net/u/21948/showart_292182.html 

1、make是通过比较对应文件(规则的目标和依赖)的最后修改时间,来决定哪些文件需要更新、那些文件不需要更新。对需要更新的文件, make就执行数据库中所记录的相应命令(在make读取Makefile后会建立一个编译过程的描述数据库。此数据库中记录了所有各个文件之间的相互关系,以及它们的关系描述)来重建它,对于不需要重建的文件make什么也不做。

2、在书写时,一个较长行可以使用反斜线(/)分解为多行,这样做可以使Makefile清晰、容易阅读。注意:反斜线之后不能有空格!

3、在实际工作中大家比较认同的方法是,使用一个变量“objects”、“OBJECTS”、“objs”、“OBJS”来作为所有的.o文件的列表的替代。在使用到这些文件列表的地方,使用此变量来代替。比如说定义了变量“OBJS”,那么就可以在需要的地方使用“$(OBJS)” 来表示它。
 
4、自动推导规则:make能够自动完成对.c文件的编译并生成对应的.o文件。这是make的隐含规则。

5、书写规则建议的方式是:单目标,多依赖。就是说尽量做到一个规则中只存在一个目标文件,可有多个依赖文件。尽量避免多目标,单依赖的方式。这样后期维护也会非常方便,而且Makefile会更加清晰明了。

6、在一个完整的Makefile中,包含了5个部分:显示规则、隐含规则、变量的定义、指示符和注释。

7、一个Makefile中可以包含其它的Makefile文件,利用关键字include实现,这和c语言对头文件的包含方式一致。 include指示符告诉make暂停读取当前的Makefile,而转去读取include指定的一个或多个文件,完成以后再继续当前Makefile 的读取。Makefile指示符include书写在独立的一行,其形式如下:

include FILENAMES

FILENAMES是shell所支持的文件名(可以使用通配符)。指示符include所在的行可以以一个或者多个空格(make在处理时将忽略这些空格)开始,但是切记不能以【TAB】字符开始。

8、make执行一个规则的过程:对于一个存在的规则(明确规则和隐含规则),首先,make程序将比较目标文件和所有的依赖文件的时间戳。如果目标的时间戳比所有依赖文件的时间戳更新,那么就什么也不做。否则,依赖文件中的某一个或者全部在上一次执行make后已经被修改过,规则所定义的重建目标的命令将会被执行。这是make工作的基础,也是其执行规则所定义命令的依据。

9、在规则中,通配符会被自动展开,但是在变量定义和使用函数时,通配符不会被自动展开。如果Makefile中有这么一句: “objects=*.o”,那么变量objects的值就是“*.o”,而不是使用空格分开的所有.o文件列表。如果需要变量“objects”代表所有的.o文件,则需要使用函数wildcard来实现bjects=$(wildcar *.o)。函数wildcard的用法是:$(wildcard PATTERN...)。在Makefile中,它被展开为已经存在的、空格分割的、匹配此模式的所有文件列表。如果不存在符合此模式的文件,那么函数会忽略模式并返回空。

10、Makefile中,如果在一个目录下如果需要创建多个可执行程序,我们可以将所有程序的重建规则在一个Makefile中描述。因为Makefile中第一个目标是“终极目标”,约定的做法是使用一个称为“all”的伪目标来作为终极目标,它的依赖文件就是那些需要创建的程序。

#sample Makefile
all: prog1 prog2 prog3
.PHONY: all
prog1: prog1.o utils.o
 $(CC) $(CFLAGS) $^ -o $@
prog2: prog2.o
 $(CC) $(CFLAGS) $^ -o $@
prog3: prog3.o sort.o utils.o
 $(CC) $(CFLAGS) $^ -o $@

当需要单独更新某一个程序时,我们可以通过make的命令行选项来明确指定需要重建的程序。

11、make存在一个内嵌隐含变量“RM”,它被定义为:“RM=rm -f”,因此在书写clean规则时的命令行可以使用$(RM)来代替rm,这样可以避免出现一个不必要的麻烦。这是推荐使用的做法。

12、如果要执行的命令以字符“@”开始,则make在执行时这个命令就不会被回显。典型的用法是我们在使用echo命令时输出一些信息时,如:
@echo "starting"
所以可以在书写Makefile时,使用@来控制命令的回显。

13、规则中,当目标需要被重建时,此规则定义的命令将会被执行,如果是多行命令,那么make就为每一行命令使用一个独立的子 shell去执行。因此,多行命令之间的执行是相互独立的,相互之间不存在依赖。而在Makefile中书写在同一行的多个命令属于一个完整的shell 命令行,所以需要注意:在一个规则的命令中,命令行cd改变目录并不会对其后的命令的执行产生影响。就是说其后的命令执行的工作目录不会是之前使用cd进入的那个目录。如果要实现这个目的,就不能把cd和其后的命令放在两行来书写。而应该把这两行命令写在一行上,用分号隔开。这样它们才是一个完整的 shell命令行。如果希望把一个完整的shell命令行书写在多行上,需要使用反斜杠来对处于多行的命令进行连接,表示它们是一个完整的shell命令行。

14、make的递归调用
在Makefile中使用“make”作为一个命令来执行本身或者其他makefile文件。递归调用在一个存在多级子目录的项目中非常有用。
subsystem:
 cd subdir && $(MAKE)
等价于
subsystem:
 $(MAKE) -C subdir
意思是进入子目录,然后在子目录下面执行make。

15、make可以定制命令包
在书写Makefile时,可能有多个规则会使用相同的一组命令,就像C语言程序中需要经常使用的函数printf。可以将一组命令进行类似c语言函数的封装,以后在需要的地方可以通过它的名字来对这一组命令中进行引用。这样就可以减少重复工作,提高了效率。在GNU make中,可以使用指示符define来完成这个功能,通常把define定义的一组命令成为一个命令包。定义一个命令包的语法以define开始,以 endef结束。

define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef

这样,run-yacc就是这个命令包的名字。在define和endef之间的命令就是命令包的主体。需要说明的是,使用 define定义的命令包中,命令体中变量和函数的引用不会展开。命令体中所有的内容包括$等都是变量run-yacc的定义,它和C语言中宏的使用方式一样。
使用:
foo.c:foo.y
 $(run-yacc)

16、区分Makefile和shell中对变量应用的不同
Makefile单字符的引用可以为$x $(x) ${x}三种形式。多字符的引用$(xx) ${xx}.
而shell中变量的引用只有两种形式${xx} $xx.

一般在书写Makefile时,各部分变量引用的格式建议如下:
(1)make变量(Makefile中定义的变量或者是make的环境变量)的引用使用$(VAR)的格式,无论VAR是单字符变量名还是多字符变量名。
(2)出现在规则命令行中shell变量(一般为执行命令过程中的临时变量,它不属于Makefile变量,而是一个shell变量)引用使用shell的$tmp格式。
(3)对出现在命令行中的make变量同样使用$(CMDVAR)格式来引用。

17、尽量采用直接展开式变量,而不要用递归展开式变量。

18、作为一名优秀的程序员,在面对一个复杂问题时,应该是寻求一种尽可能简单、直接并且高效的处理方式来解决,而不是将一个简单问题在实现上复杂化。如果想在简单问题上突出自己使用某种语言的熟练程度,是一种非常愚蠢且不成熟的行为。

19、如果实现对一个之前没有定义过的变量进行赋值,可以使用?=。如果想对一个通用变量的值进行追加,使用+=。
 
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 贝亲奶瓶泡沫多怎么办 四个多月的宝宝拉肚子怎么办 宝宝四个月了拉肚子怎么办 四个月宝宝火大怎么办 刚出生的宝宝便秘怎么办 小宝宝破腹产吸了几口羊水怎么办 换奶粉不拉屎了怎么办 婴儿吃奶粉不拉屎怎么办 1岁半突然不喝奶怎么办 6个月宝宝不吃奶粉怎么办 7个月宝宝不吃奶粉怎么办 5个月宝宝不吃奶粉怎么办 一岁两个月宝宝不长肉怎么办 7个月宝宝肚子疼怎么办 奶喝一半凉了怎么办 5个月孩子厌奶怎么办 怀孕后特别不爱吃水果怎么办 宝宝吃了无比滴怎么办 婴儿上火怎么办吃什么可以去火 肚子胀怎么办最快的方法 40天婴儿拉水怎么办 8个月宝宝坐不稳怎么办 宝宝段奶不吃奶粉怎么办 3个月宝宝头睡偏了怎么办 2个月婴儿抱着睡怎么办 两个半月的宝宝睡眠少怎么办 七个月宝宝不愿意坐怎么办 一个多月的宝宝老是哭闹怎么办 宝宝头老往后仰怎么办 8个月宝宝不会爬怎么办 孩子个头长得慢怎么办 宝宝个头长得慢怎么办 婴儿个头长得慢怎么办 11个月宝宝认生怎么办 3个月宝宝认人怎么办 3个月的宝宝认生怎么办 两个月的宝宝睡觉一惊一惊怎么办 六个月宝宝不喜欢喝水怎么办 三岁宝宝尿多怎么办 一岁的宝宝尿少怎么办 一岁宝宝尿黄怎么办