Makefile

什么是Makefile

Makefile 可以简单的认为是一个工程文件的编译规则,描述了整个工程的编译和链接等规则。其中包含了那些文件需要编译,那些文件不需要编译,那些文件需要先编译,那些文件需要后编译,那些文件需要重建等等。
Makefile 可以使得我们的项目工程的编译变得自动化,不需要每次都手动输入一堆源文件和参数。

这个在windows平台下的IDE大多都内置了Makefile。linux上则需要自己编写。

想一想学会了是不是惬意呢。

Makefile规则

Makefile 描述的是文件编译的相关规则,它的规则主要是两个部分组成,分别是依赖的关系和执行的命令,其结构如下所示:

targets : prerequisites
    command
    
targets:规则的目标,可以是 Object File(一般称它为中间文件),也可以是可执行文件,还可以是一个标签;
prerequisites:是我们的依赖文件,要生成 targets 需要的文件或者是目标。可以是多个,也可以是没有;
command:make 需要执行的命令(任意的 shell 命令)。可以有多条命令,每一条命令占一行。

Makefile所使用的命令是由 shell 命令行组成,他们是一条一条执行的。多个命令之间要使用分号隔开,Makefile 中的任何命令都要以tab键开始。多个命令行之间可以有空行和注释行,在执行规则时空行会被自动忽略。而且命令中出现的字符“#”到行末的内容被认为是注释。 当然了“#”可以不在此行的行首,此时“#”之前的内容不会被作为注释处理。
如以下的一个例子:

test:test.c
    gcc -o test test.c

通配符规则


使用示例:

.PHONY:clean
clean:
    rm -rf *.o test

变量赋值规则

Makefile 文件中定义变量的基本语法如下:

变量的名称=值列表

变量的名称可以由大小写字母、阿拉伯数字和下划线构成。等号左右的空白符没有明确的要求,因为在执行 make 的时候多余的空白符会被自动的删除。至于值列表,既可以是零项,又可以是一项或者是多项。

VALUE_LIST = one two three

调用变量的时候可以用 “(VALUE_LIST)” 或者是 “{VALUE_LIST}” 来替换,这就是变量的引用。

变量赋值的四种方式

简单赋值 ( := ) 编程语言中常规理解的赋值方式,只对当前语句的变量有效。
递归赋值 ( = ) 赋值语句可能影响多个变量,所有目标变量相关的其他变量都受影响。
条件赋值 ( ?= ) 如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。
追加赋值 ( += ) 原变量用空格隔开的方式追加一个新值。

自动化变量规则

关于自动化变量可以理解为由 Makefile 自动产生的变量。 在模式规则中,规则的目标和依赖的文件名代表了一类的文件。

那么模式规则命令中该如何表示文件呢?就需要使用“自动化变量”,自动化变量的取值根据执行的规则来决定,取决于执行规则的目标文件和依赖文件。

看以下实例:

test:test.o test1.o test2.o
     gcc -o $@ $^
test.o:test.c test.h
     gcc -o $@ $<
test1.o:test1.c test1.h
     gcc -o $@ $<
test2.o:test2.c test2.h
     gcc -o $@ $<

这个规则模式中用到了 “ @ " 、 " @" 、" @""<” 和 “ " 这 三 个 自 动 化 变 量 , 对 比 之 前 写 的 M a k e f i l e 中 的 命 令 , 我 们 可 以 发 现 " ^" 这三个自动化变量,对比之前写的 Makefile 中的命令,我们可以发现 " "Makefile"@” 代表的是目标文件test,“ ” 代 表 的 是 依 赖 的 文 件 , “ ^”代表的是依赖的文件,“ <”代表的是依赖文件中的第一个。我们在执行 make 的时候,make 会自动识别命令中的自动化变量,并自动实现自动化变量中的值的替换。

环境变量规则与修改

Makefile中常见的搜索的方法的主要有两种:一般搜索VPATH和选择搜索vpath。乍一看只是大小写的区别,其实两者在本质上也是不同的。

VPATH 和 vpath 的区别

VPATH 是变量,更具体的说是环境变量,Makefile 中的一种特殊变量,使用时需要指定文件的路径;vpath 是关键字,按照模式搜索,也可以说成是选择搜索。搜索的时候不仅需要加上文件的路径,还需要加上相应限制的条件。

VPATH的使用

单个路径:VPATH := 路径
多个路径:VPATH := 路径1:路径2

无论你定义了多少路径,make 执行的时候会先搜索当前路径下的文件,当前目录下没有我们要找的文件,才去 VPATH 的路径中去寻找。 如果当前目录下有我们要使用的文件,那么 make 就会使用我们当前目录下的文件。

vpath因为用的不多在这里就不介绍了。

条件判断规则

条件语句的作用:条件语句可以根据一个变量的值来控制 make 执行或者时忽略 Makefile 的特定部分,条件语句可以是两个不同的变量或者是常量和变量之间的比较。

使用示例:

ifeq (ARG1, ARG2)
ifeq 'ARG1' 'ARG2'
ifeq "ARG1" "ARG2"
ifeq "ARG1" 'ARG2'
ifeq 'ARG1' "ARG2"

libs_for_gcc= -lgnu
normal_libs=
foo:$(objects)
ifeq($(CC),gcc)
    $(CC) -o foo $(objects) $(libs_for_gcc)
else
    $(CC) -o foo $(objects) $(noemal_libs)
endif

包含规则

当 make 读取到 “include” 关键字的时候,会暂停 读取当前的 Makefile,而是去读 “include” 包含的文件,读取结束后再继读取当前的 Makefile 文件。

include <文件名>

大致更新这么多,以后用到再更。
话说我也用不到,VS真香。

参考文献

[1] Makefile教程.C语言中文网.http://c.biancheng.net/makefile/