http://c.biancheng.net/makefile/

1.简介

  1. makefile的作用是在工程化开发中对工程项目定义编译规则。使用make命令,整个工程就会自动编译。make命令是一个命令工具,是一个解释makefile中指令的命令工具。
  2. 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中使用“#”字符,可以用反斜框进行转义,如:“#”。

2.Makefile中的通配符

  1. *:匹配零个或者任意多个字符
  2. ?:匹配任意一个字符
  3. []:可以将指定匹配的字符放在[]中
test:*.c
    gcc -o test *.c

3.Makefile中的变量

  1. 定义变量的基本语法
变量名 = 值列表
  1. 变量的使用
# 定义一个变量
var = main.c
# 变量的使用
$(var) 或者${var}

var = main.c
result:${var}
        gcc  -o result main.c
  1. Makefile中的四种变量的赋值方式
1.简单赋值::=
x:=foo
y:=$(x)b
x:=new
test:
      @echo "y=>$(y)"
      @echo "x=>$(x)"
# shell命令行中执行make test输出如下结果
#y=>foob
#x=>new

2.递归赋值
x=foo
y=$(x)b
x=new
test:
      @echo "y=>$(y)"
      @echo "x=>$(x)"
3.条件赋值:?=,如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。
4.追加赋值:+=,原变量用空格隔开的方式追加一个新值。

4.Makefile中自动化变量

参考

5.makefile编写的三要素

在学习编写makefile文件以前,我们先来看makefile编写的三要素。

1.makefile编写的三要素:
  1. 目标
  2. 依赖
  3. 规则命令
2.示例
  1. 编写一个简单的makefile文件:
    1. 源文件hello.c如下所示,位于/root/practice目录下;head.h位于/root/practice/include目录下:
    #include <stdio.h>
    #include <head.h>
    
    int returnMess(int val)
    {
        return val;
    }
    
    int main()
    {
        int a;
    #ifdef DEBUG
        printf("HelloWorld");
    #endif
        printf("%d\n",returnMess(100));
        return 0;
    }
    
    1. 在makefile文件下编辑如下内容:
    app: hello.o
        gcc -o app hello.o
    hello.o: hello.c
        gcc -c -I ./include hello.c
    
    1. 然后执行make命令进行编译,生成可执行程序。
  2. 我们借用上诉示例来解释一下三要素:
    makefile文件编写的三要素.png

注意: makefile的隐含规则:

  1. make时默认处理第一个目标。比如在上诉makefile中目标有两个。

6.变量的使用和常用函数的使用

我们发现,当改变源程序比如增加.c文件或者删除某个.c文件,上诉的makefile文件就需要做出大的改动。所以呢我们有必要学习变量的使用和常用函数的使用来对makefile做出改进。

1.变量的使用
  1. 为了简述变量的使用,我还是以上面的示例来说明。现在我们来举例说明使用变量的例子:
#自定义变量,变量名为var
var = hello.o
#变量名的使用:$(变量名)
app:$(var)
    gcc -o app hello.o
hello.o: hello.c
    gcc -c -I ./include hello.c
  1. 规则中使用的变量:下面这些变量只能在规则命令中使用,并且用于模式匹配规则。关于使用例子在后文中的makefile编写中有介绍。
    1. $@:代表目标
    2. $^:代表全部依赖
    3. $<:代表第一个依赖
    4. $?:代表第一个变化的依赖
2.函数的使用
  1. wildcard函数:可以进行文件匹配,比如匹配makefile当前所在目录下的所有后缀名为.c的源文件。语法规则是:$(wildcard pattern),在makefile中他被展开为已经存在的、使用空格分开的、匹配此模式的所有文件列表。例如:
# 产生一个所有以.c、.cpp结尾的文件的列表,然后存入变量中
SOURCE = $(wildcard *.c *.cpp)
  1. patsubst函数:用于匹配替换。包含三个参数,第一个表示需要匹配的文件,第二个表示用什么替换他,第三个是一个需要被处理的由空格分隔的列表。

  2. 为了简述wildcard函数的用法,我们举个例子。项目目录如下所示:

    1. makefile编写如下:
    #获取与makefile文件同级目录下的所有后缀名为.c的文件
    sourceFile = $(wildcard *.c)
    #获取所有的后缀名为.o的文件
    objFiles1 = $(patsubst %.c, %.o ,$(sourceFile))
    result:$(objFiles1)
    	gcc -o result -I ./include $(objFiles1)
    %.o:%.c
    #变量的使用,$^,$@
    	gcc -c $^ -o $@ -I ./include
    test:
    #输出变量sourceFile和objFiles1的值
    	echo $(sourceFile)
    	echo $(objFiles1)
    
     #定义伪目标,防止当前makefile文件所在目录下有与此目标名相同的文件造成歧义
    .PHONY:clean
    clean:
    	@rm -f *.o  
    	@rm -f result
    # 符号@表示在控制台不会打印rm -f *.o这样的信息
    
    1. 在上诉makefile文件中,为了验证wildcard函数和patsubst函数的使用是否成功,我们输出sourceFile和objFiles1的值。期间新增了一个目标test。
    # 输出结果
    make test
    echo add.c main.c sub.c
    add.c main.c sub.c
    echo  add.o   main.o   sub.o 
    add.o main.o sub.o
    
    1. make的结果如下:
    make
    gcc -c add.c -o add.o -I ./include
    gcc -c main.c -o main.o -I ./include
    gcc -c sub.c -o sub.o -I ./include
    gcc -o result -I ./include  add.o   main.o   sub.o