Makefile简介
背景
程序设计通常有一个固定的流程:编辑源代码文件、将源代码文件编译成可执行文件以及对成果进行调试。make程序可以让将一个项目中的源文件编译成可执行文件之类的工作自动化。make这个词的意思是“制作”,你想制作什么后面就加什么参数,制作的方法也就是配方需要你指定,也就是makefile中的规则。
如果你会shell编程的话,你会发现上述功能写个脚本也能做到。相对于脚本,make的优点是:它可以根据文件之间的依赖关系和时间戳判断应该重新执行那些步骤,以产生需要的程序。有了这个信息,make可以优化编译的过程,跳过非必要的步骤。这样是Make的核心优势。
现在有许多自动构建工具,用来产生makefile,比如cmake,qmake等。大部分人都不用手写makefile,但是读懂makefile的能力还是要有的。
基本构成
基本上,makefile包含了一组用来编译应用程序的规则,其它的元素都是为了更好的描述规则。第一条规则被认为是默认规则。
一项规则可以分为三个部分:工作目标(target),它的必要条件(prerequisite),以及所要执行的命令(command):
target:<prereq1> <prereq2> ...
<commands>
- 工作目标是make命令行可以指定的参数,它可以是一个需要创建的文件或者某个动作。
- 必要条件可以有多个,用空白隔开
- 命令是将被放到subshell中执行的命令,可以有多行多条命令。每行必须以tab开头。
make的工作机制很简单。它首先将来自命令行的参数作为工作目标,如果没有指定,则取第一个规则中的目标,称为为默认工作目标。然后按顺序查找所有该目标依赖的文件,并依次把依赖文件作为目标在makefile中查找相应的规则...按此递归下去形成依赖树。树的叶子节点在makefile中没有相应的规则更新他们,所以他们必须是已经存在的,否则make报错:所需文件不存在而且没有更新他们的规则。(产生也视为更新操作。)make的规则树的搜索建立是先序遍历过程,而规则的执行是后序遍历过程。
规则的执行:如果某个必要条件比目标“新”,则将此规则的命令交给shell执行。而如果工作目标最“新”,则什么也不做。命令只是一些shell程序,它并不一定需要产生一个叫做"target"
的文件。target
和prerequisites
也并不一定要求是文件名。
这种要更新目标先更新必要条件的思想是Make的精髓所在。它保证工作步骤合理并且高效的执行。当某个文件发生改变时,只有依赖它的目标才会被更新,也只有相应的命令会被执行。
例子
假设有一个简单的程序,包括两个源文件main.c和lib.c,他们都包含了头文件header1.h和header2.h,把编译后形成的可执行程序命名为prog,那么makefile可以写为:
all: prog
prog: main.o lib.o
gcc -o prog main.o lib.o
main.o : main.c header1.h header2.h
gcc -c main.c
lib.o : lib.c header1.h header2.h
gcc -c lib.c
现在你只要执行make就会自动执行相应的shell命令把程序编译好了。
当然这只是个说明makefile工作方式的简单例子,并不比直接输入编译命令快多少。但是makefile可以借助变量、函数等工具完成非常复杂的规则描述,对于要反复调试的程序显然非常方便快捷。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。