Makefile
之前转载过一篇makefile的编写教程,但是似乎可读性并不是那么高,所以以自己的总结和学习来谈谈mkfile怎么编写。
1.首先,我们来看一下make
make是linux自带的构建器,构建的规则在makefile中,编译器是使用gcc。
2.makefile的命名规则
- makefile
- Makefile
3.makefile的规则
gcc a.c b.c c.c -o app
- 三部分:目标,依赖,命令
- 目标:依赖
- (tab缩进)命令
接下来,我们就开始编写第一个makefile文件:
head.h:
1 #include<stdio.h>
2
3 int NUM(int a);
4 void Prin();
a.c
1 #include"head.h"
2
3 int NUM(int a)
4 {
5 return a;
6 }
~
b.c
1 #include"head.h"
2
3 void Prin()
4 {
5 printf("hello\n");
6 }
~
1.由于他们是相互依赖的关系,所以第一个makefile的文件是:
1 app:main.c a.c b.c
2 gcc main.c a.c b.c -o app
结果:
wz@wz-machine:~/linux/MK$ make
gcc main.c a.c b.c -o app
wz@wz-machine:~/linux/MK$ ./app
5
hello
2.我们发现第一个效率很低,而且修改一个文件,另外的文件也需要被修改。那么我们来编写第二个文件。
1 app:main.o a.o b.o
2 gcc main.o a.o b.o -o app
3
4 main.o:main.c
5 gcc main.c -c
6 a.o:a.c
7 gcc a.c -c
8 b.o:b.c
9 gcc b.c -c
结果:
wz@wz-machine:~/linux/MK$ make
gcc main.c -c
gcc a.c -c
gcc b.c -c
gcc main.o a.o b.o -o app
wz@wz-machine:~/linux/MK$ ./app
5
hello
说明:
工作原理:
检测依赖是否存在:
1.向下搜索下边的规则,如果有规则是用来生成查找的依赖,执行规则中的命令
2.依赖存在,判断是否需要更新
原则:目标时间>依赖时间,反之,则更新
缺点是太冗余
3.第三个文件
自定义变量:obj = a.o b.o c.o
变量的取值:aa =
@ 规则中的目标
-
^ 规则中的所有的依赖
只能在规则的命令中使用
1 obj = main.o a.o b.o
2 target = app
3
4 $(target):$(obj)
5 gcc $(obj) -o $(target)
6
7 %.o:%.c
8 gcc -c $< -o $@
~
结果:
wz@wz-machine:~/linux/MK$ make
gcc main.o a.o b.o -o app
wz@wz-machine:~/linux/MK$ ./app
5
hello
说明:
模式匹配:
%o:%.c
第一次:main.o
main.o:main.c
gcc -c main.c -o main.o
第二次:add.o
add.o:add.c
gcc -c add.c -o add.o
在 GNU Make 里有一个叫 ‘wildcard’ 的函 数,它有一个参数,功能是展开成一列所有符合由其参数描述的文 件名,文件间以空格间隔。你可以像下面所示使用这个命令:
SOURCES= $(wildcard *.c)
这行会产生一个所有以 ‘.c’ 结尾的文件的列表,然后存入变量 SOURCES 里。当然你不需要一定要把结果存入一个变量。
notdir把展开的文件的路径去掉,只显示文件名而不包含其路径信息,例如:
FILES =$(notdir $(SOURCES))
这行的作用是把上面以'.c'结尾的文件的文件列表中附带的路径去掉,只显示符合条件的文件名。
patsubst( patten substitude, 匹配替换的缩写)函数。它需要3个参数:第一个是一个需要匹配的式样,第二个表示用什么来替换它,第三个是一个需要被处理的由空格分隔的字列。例如,处理那个经过上面定义后的变量,
OBJS = $(patsubst %.c,%.o,$(SOURCES))
这行将处理所有在 SOURCES列个中的字(一列文件名),如果它的 结尾是 ‘.c’ ,就用’.o’ 把 ‘.c’ 取代。注意这里的 % 符号将匹配一个或多个字符,而它每次所匹配的字串叫做一个‘柄’(stem) 。在第二个参数里, % 被解读成用第一参数所匹配的那个柄。
4.我们来编写一下文件:
1 SOURCES = $(wildcard *.c)
2 OBJS = $(patsubst %.c,%.o,$(SOURCES))
3 target = app
4 $(target):$(OBJS)
5 gcc $^ -o $(target)
6
7 %.o:%.c
8 gcc -c $< -o $@
~
结果:
wz@wz-machine:~/linux/MK$ make
gcc a.o b.o main.o -o app
wz@wz-machine:~/linux/MK$ ./app
5
hello
不能清理项目
第五个版本:
1 SOURCES = $(wildcard *.c)
2 OBJS = $(patsubst %.c,%.o,$(SOURCES))
3 target = app
4 $(target):$(OBJS)
5 gcc $^ -o $(target)
6
7 %.o:%.c
8 gcc -c $< -o $@
9
10 clean:
11 rm -f $(OBJS) $(target)
12
声明伪目标:
.PHONY:clean
-f:强制执行
命令前加-
- 忽略执行失败的命令,继续执行向下执行其余的命令
代码:
1 SOURCES = $(wildcard *.c)
2 OBJS = $(patsubst %.c,%.o,$(SOURCES))
3 target = app
4 $(target):$(OBJS)
5 gcc $^ -o $(target)
6
7 %.o:%.c
8 gcc -c $< -o $@
9
10 .PHONY:clean
11 clean:
12 rm -f $(OBJS) $(target)
13
~
结果:
wz@wz-machine:~/linux/MK$ make
gcc -c a.c -o a.o
gcc -c b.c -o b.o
gcc -c main.c -o main.o
gcc a.o b.o main.o -o app
wz@wz-machine:~/linux/MK$ ./app
5
hello
wz@wz-machine:~/linux/MK$ make clean
rm -f a.o b.o main.o app
wz@wz-machine:~/linux/MK$
着我们就介绍完了,但是大家一定会发现一个问题,就是我们上面编译的文件只有一个main函数,那我们怎么痛是编译两个有面函数的文件。大家看一下代码就知道了。
1 all:app1 app2
2
3 app1:a.c
4 gcc a.c -o app1
5 app2:b.c
6 gcc b.c -o app2
7
8 .PHONY:clean
9 clean:
10 rm -f app*
结果:
wz@wz-machine:~/linux/MK2$ make
gcc b.c -o app2
wz@wz-machine:~/linux/MK2$ ./app1
hello
wz@wz-machine:~/linux/MK2$ ./app2
world
wz@wz-machine:~/linux/MK2$ make clean
rm -f app*
wz@wz-machine:~/linux/MK2$ ls
a.c b.c makefile
当然也可以按照上面的一些简便一下,就按照那个实现也可以的。