makefile入门

什么是makefile ?

在一个项目中,会有大量的 .c 文件,.h文件.让我们手动的编译不仅麻烦,而且效率低.
makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译.
然后使用 make 工具,用来解释makefile 中的规则.

现在有 3 个文件,分别是 main.c ,hello.h ,hello.c

main.c

#include<stdio.h>                                                                                                                                             
#include"hello.h"

int main()
{
        hello();
        return 0;
}

hello.h

void hello(void);

hello.c

#include"hello.h"
#include<stdio.h>

void hello(void)
{
	printf("hello world\n");
}

最直接的编译方式: gcc main.c hello.c

使用 makefile 时,要在 makeflie(Makefile) 文件中编写.

makefile 的 编写由易到难.

makefile 的基本单元是规则.
一个规则的格式如下:
目标文件列表 分隔符 依赖文件列表 [; 命令]
(table)[命令]

最简单的makefile就生成了

main: main.o hello.o
        gcc  main.c hello.c -o main

makefile解析:
main 为 目标文件, : 为分隔符,main.o 和 hello.o 为 依赖文件
第二行 则为一个命令

这个简单的 makefile 解决了麻烦这个问题 ,但没有解决 低效 的 问题.因为每一次都要编译 main.o,hello.o. 即使没有改变hello.o.

main: main.o hello.o
        gcc  main.o hello.o -o main

main.o:main.c
        gcc -c  main.c

hello.o:hello.c
        gcc -c hello.c

为什么说它能解决低效呢 ?

makefile 每次只执行一个目标文件,即 第一个 目标文件.然后检查这个规则是否存在依赖,如果依赖存在,则执行命令,若依赖不存在则向下查找依赖.
找到依赖后 首先判断是否要更新, 如果依赖的时间 比 目标时间 晚,则说明 依赖文件在 目标文件后修改过,需要更新,否则就跳过.所以提高了效率.

makefile 解析:
为了生成main ,则需要main.o,hello.o ,向下查找,首先找到 main.o ,对比时间,判断是否更新,然后查找第二个依赖并判断,
如果所有依赖都检查完毕,则执行 第一个规则中的命令.

但是,这又引出了一个问题,如果要修改一个makefile 的中使用的 编译器,原来为 gcc ,想变为 g++,这时候,就要一个个 的修改.
为了解决这个问题, 就引入了 变量.修改时,只要修改 变量就行了.
除此之外,makefile 中还定义了一组变量,它们的值在make 运行过程中可以动态的改变,称为 自动变量
例:

  1. $@: 表示规则中的目标文件名
  2. $<: 表示规则中的第一个依赖文件名
  3. $?: 所有比目标文件新的依赖文件列表
  4. $^: 表示规则中的所有依赖

还有一个 : makefile 中的匹配符 %

obj = main.o hello.o
CC = gcc 
target = main

$(target): $(obj)
        gcc $(obj) -o $(target)

%.o:%.c                                                                                                                                                       
        gcc -c $< -o $@

这次的makefile 使用了 变量替换,和自动变量,还有一个 匹配符 %

解释一下 :

%.o:%.c

在这个makefile 中 相当于

main.o : main.c
hello.o : hello.c

makefile 的解析:

前三行就是简单的变量替换, 在makefile 中 ,用 $() 对变量的引用. 可以将 变量替换 看成 字符串 替换.

第二个规则的命令中, 每次在 第一个规则中 检查一个依赖, 就到第二个 规则中执行.
相当于 :

检查 main.o 依赖时 , 第二个规则 执行

main.o : main.c
	gcc -c main.c -o main.o

检查 hello.o 依赖时,第二个规则执行

hello.o : hello.c 
	gcc -c hello.c -o hello.o

当然也可以将 第一个规则 命令 中的 变量 用自动变量替换

obj = main.o hello.o
CC = gcc 
target = main

$(target): $(obj)
        gcc $^ -o $@

%.o:%.c                                                                                                                                                       
        gcc -c $< -o $@

此时 你会发现多了 hello.o,main.o文件, 想一哈,如果 有特别多的 文件,就会生成 特别多的 .o文件,而且还可能会在不同的目录里,
这时,删除他们可不是一个容易的事清.
但我们可以 用makefile 删除

obj = main.o hello.o
CC = gcc 
target = main
                                                                                
$(target): $(obj)
        gcc $^ -o $@

%.o:%.c
        gcc -c $< -o $@
clean:
        rm *.o $(target)

上面提到过,makefile 只执行第一个 目标文件,其余的是不执行的. 这时,我们只能通过自己指定 执行哪一个目标文件.

make clean

它就会执行 clean 这个规则;

除此之外,makefile 中也带有函数.(过几天 在补更)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章