一.欢迎来到我的酒馆
在本章节介绍Makefile。
目录
- 一.欢迎来到我的酒馆
- 二.GNU make 预览
- 三.一个简单的Makefile
- 四.make程序如何处理Makefile文件
二.GNU make 预览
2.1 GNU make工具会自动决定哪些程序需要被重新编译,并且执行相应的命令来重新编译程序。在本系列博客中,我们会介绍GNU make。GNU make是由Richard Stallman和Roland McGrath开发的,在3.76版本后由Paul D. Smith开发。
在本系列博客中,所有的例子都用c语言,c语言是使用最广泛的编程语言之一。但是,你可以使用make来构建任何编程语言的程序,只要是编译器可以运行在shell命令行上。make不仅限于构建应用程序,你还可以用make来描述某些文件必须自动更新的任何任务,无论何时有文件变动了,就需要自动更新某些文件。
2.2 准备和运行make
在使用make工具之前,你必须写一个名为makefile的文件,这个makefile文件描述了文件之间的关系,并提供用于更新每个文件的命令。在一个应用程序中,通常,可执行文件从object文件(.o文件)上更新,而这些object文件又是通过编译源文件生成的。
一旦有一个合适的makefile文件,每当你更改了一些源文件,你可以使用一条如下的简单命令:
make
来执行必要的重新编译。应用程序使用makefile数据为基础并且确定需要更新哪些文件。对于其中的每一个文件,它都会发布一个记录在以makefile数据为基础的配方。你可以提供命令行参数去控制哪些文件需要被更新。
2.3 一个简单的Makefile介绍
你需要写一个文件名为makefile的文件来告诉make程序要执行哪些操作。大部分情况下,makefile文件表明如何编译和链接一个应用程序。当有明确的要求时(如,删除一个文件来执行清理操作)makefile文件还可以告诉make程序如何执行复杂的命令。
当重新编译可执行文件的时候,每个更新过的c源文件必须重新编译。如果一个头文件已经更新了,为了安全起见,每一个包含了这个头文件的c源文件也必须重新编译。每次编译源文件都会生成一个对应的object文件(.o文件)。最后,如果任何的源文件已经被重新编译了,则所有的object文件,无论是新生成的还是以前编译中保存的,都必须一起链接来生成一个新的可执行文件。
2.4 一个执行单元长啥样
一个简单的makefile文件包含了一个执行单元(rule),如下:
target ... : prerequisite ...
recipe 1
recipe 2
recipe 3
...
- target(目标), 通常是一个文件的名字,target也可以是一个可执行文件或object文件。target也可以是要执行操作的名称,例如:clean。
- prereauisite (先决条件), 是用作输入的文件,用于创建target。一个target通常依赖多个文件。
- recipe(配方),是执行的操作。recipe可以有多个命令,要么在同一行上,要么在自己所在的行上。这里要记住的是:在写每个recipe之前都要敲一个tab键。如果你偏爱某个字符而不是tab字符加在recipe之前,你可以设置一个变量来替代字符。
通常,配方是一条命令且需要用到先决条件,如果任何的先决条件发生更改,将会生成一个target。但是一个有配方和target的执行单元(rule),可以不写先决条件。例如:一个执行删除操作的target可以不写先决条件,如clean。
一个执行单元,说明了如何且何时执行重新编译,在先决条件上执行一个配方来创建和更新一个target。一个执行单元同样可以说明如何执行一个操作。
一个makefile文件可以包含除执行单元外的其他文本。但是一个简单的makefile仅仅只需要包含执行单元。相比较于展示的例子,执行单元可能看起来更复杂一些,但是所有的执行单元或多或少都适应这种模式。
三.一个简单的Makefile
下面是一个简单的makefile例子,cJSON是c语言编写的JSON解码器,代码非常简洁,只有750行代码。点击这里下载cJSON
使用命令解压:
tar -zxvf cJSON.tar
解压之后,进入cJSON目录,文件像下面这样:
在项目cJSON目录下我已经写好了一个Makefile文件,这个例子描述了一个可执行文件test依赖于1个cJSON.o object文件,这个object文件又依赖于一个c源文件。
all: test
test: cJSON.o test.c
cc -W -Wall -o test test.c cJSON.o -lm
cJSON.o: cJSON.c cJSON.h
cc -W -Wall -c -o cJSON.o cJSON.c
clean:
rm -rf *.o test
要使用这个Makefile生成一个可执行文件,输入命令:
make
删除目录下的可执行文件和object文件,输入命令:
make clean
在本例中,target是all,它依赖test,而test又依赖于cJSON.o,test.c,cJSON.h文件。配方是两个gcc编译指令。clean没有先决条件,它不依赖于任何文件,因此,它默认情况下是不执行的,除非指定命令(如:make clean)才会执行。
当target是一个文件时,如果任何的prerequisite发生了更改,target需要被重新编译或重新链接。此外,任何prerequisite应首先更新自己自动生成的内容。在上面的例子中,cJSON.o依赖于cJSON.c源文件和cJSON.h头文件。
一个配方会紧跟着一个target和prerequisite,这些配方表示了如何更新target文件。在makefile文件里,每行配方前必须敲一个tab键,以此来区分不同的配方。这里要记住的是:makefile并不知道配方是如何工作的,这取决于你提供各种配方来更新target文件。当一个target需要被更新的时候,所有提供的配方都会被执行。
这里clean是一个target,但不是一个文件,它是一个操作的名称。在这个执行单元中,因为默认不会执行这个操作,clean不是任何其他执行单元的先决条件。因此,不要用它做任何事情,除非你告诉它要执行哪些操作。这里要记住的是:clean这个执行单元不仅不是一个先决条件,而且它没有任何的先决条件,因此这个执行单元的目的是运行特定的配方。target不是一个文件,但是是一个操作称之为phony target。
四.make程序如何处理Makefile文件
默认的,make程序从上到下执行,它会找到第一个target。第一个target称为默认目标。
在上一小节的简单Makefile例子中,默认目标为test,因此,test这个执行单元会首先执行。当你下命令:
make
make程序会在当前的目录下读取makefile文件,并且开始处理第一个执行单元。在这个例子中