Makefile备忘

本文摘自 : 跟我一起写 Makefile     

makefile文件一般保存名称为makefile或者Makefile,没有后缀。

make 会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。 

在 Makefile 中,规则的顺序是很重要的,因为,Makefile 中只应该有一个最终目标,其它的目标都是被这个目标所连带出来的,所以一定要让 make 知道你的最终目标是什么。一般来说,定义在 Makefile 中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标。如果第一条规则中的目标有很多个,那么,第一个目标会成为最终的目标。make 所完成的也就是这个目标。

 


 Makefile 里主要包含了五个东西:  显式规则隐晦规则变量定义文件指示    和   注释

1. 显式规则。显式规则说明了,如何生成一个或多个目标文件。这是由 Makefile 的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。

2. 隐晦规则。由于我们的 make 有自动推导的功能,所以隐晦的规则可以让我们比较简略地书写 Makefile,这是由 make 所支持的。

3. 变量的定义。在 Makefile 中我们要定义一系列的变量,变量一般都是字符串,这个有点像你 C 语言中的宏,当 Makefile 被执行时,其中的变量都会被扩展到相应的引用位置上。

4. 文件指示。其包括了三个部分,一个是在一个 Makefile 中引用另一个 Makefile,就像C 语言中的 include 一样;另一个是指根据某些情况指定 Makefile 中的有效部分,就像 C 语言中的预编译 #if 一样;还有就是定义一个多行的命令。

5. 注释。Makefile 中只有行注释,和 UNIX 的 Shell 脚本一样,其注释是用“#”字符。这个就像 C/C++ 中的“//”一样。如果你要在你的 Makefile 中使用“#”字符,可以用反斜框进行转义,如:\# 。

    最后,还值得一提的是,在 Makefile 中的命令,必须要以 Tab 键开始。

 

make的执行过程:

1. 读入所有的 Makefile。

2. 读入被 include 的其它 Makefile。

3. 初始化文件中的变量。

4. 推导隐晦规则,并分析所有规则。

5. 为所有的目标文件创建依赖关系链。

6. 根据依赖关系,决定哪些目标要重新生成。

7. 执行生成命令。

 


makefile的语法规则(注意在makefile中指令必须以tab键开头,在vim中设定:set tabstop=4):  

在 Makefile 使用 include 关键字可以把别的 Makefile 包含进来,这很像 C 语言的#include,被包含的文件会原模原样的放在当前文件的包含位置。 

在 include 前面可以有一些空字符,但是绝不能是 Tab 键开始。include是make保留的关键字不是shell中可执行的指令:include foo.make a.mk b.mk c.mk e.mk f.mk 

环境变量 MAKEFILES,尽量不用这个特性。当 Makefile 出现了怪事,可以看看当前环境中有没有定义这个变量。

 

一般来说,makefile的目标基本上是一个文件,但也有可能是多个文件:

targets : prerequisites ; command          #冒号前是需要生成的文件,冒号后面是生成这个文件所需要的文件(文件依赖) 。只有在冒号后面的文件比冒号前的文件新,指令command才会被执行。
  command
...

targets 是文件名,以空格分开,可以使用通配符。command 是命令行,如果其不与“target:prerequisites”在一行,那么,必须以 [Tab键] 开头,如果和 prerequisites 在一行,那么可以用分号做为分隔。           

targets 可以是一个 object file(目标文件),也可以是一个执行文件,还可以是一个标签(label)。make 会比较 targets 文件和 prerequisites 文件的修改日期,如果 prerequisites 文件的日期要比 targets 文件的日期要新,或者 targets 不存在的话,那么,make 就会执行后续定义的命令。 

在makefile 中我们可以使用变量。makefile 的变量也就是一个字符串,理解成 C 语言中的宏可能会更好。 

例1: 

edit : main.o kbd.o command.o display.o insert.o search.o files.o utils.o 

  cc -o edit main.o kbd.o command.o display.o\             //反斜杠(\)是换行符的意思。指令必须以tab键开头。

                  insert.o search.o files.o utils.o

    ... ...

clean :
  rm edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o 

上面的edit (target)就是由冒号后面的.o文件(prerequisites)生成。

第二行中的cc是编译指令,只有在.o文件中有比edit新的文件存在或在edit这个文件不存在,第二行的指令行才会被执行,这样可以减少重复。

因为clean后面没有文件,所以make不会主动的执行其后面的指令,但可以显示的调用这条指令:make clean 

 

例2:(这段代码的作用和例1是一样的)

objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o

edit : $(objects)
  cc -o edit $(objects)

clean :
  rm edit $(objects)     

make可以自动推导文件以及文件依赖关系后面的命令,只要 make 看到一个.o 文件,它就会自动的把.c 文件加在依赖关系中。

objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o
edit : $(objects)
  cc -o edit $(objects)
main.o : defs.h    #自动的将main.cpp当作依赖文件。

  ... ...

.PHONY : clean
  clean :
-rm edit $(objects)

PHONY 意思表示 clean 是一个“伪目标”。而在 rm 命令前面加了一个小减号的意思不要管可能出现的某些错误,继续做后面的事。 


 

 

 

 

 

posted @ 2015-06-08 09:41  jiahu  阅读(211)  评论(0编辑  收藏  举报