什么是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 运行过程中可以动态的改变,称为 自动变量
例:
- $@: 表示规则中的目标文件名
- $<: 表示规则中的第一个依赖文件名
- $?: 所有比目标文件新的依赖文件列表
- $^: 表示规则中的所有依赖
还有一个 : 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 中也带有函数.(过几天 在补更)