简单易懂的makefile

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 = ( o b j ) m a k e f i l e C P P F L A G S C C @ 规则中的目标
- < ^ 规则中的所有的依赖
只能在规则的命令中使用

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

当然也可以按照上面的一些简便一下,就按照那个实现也可以的。

猜你喜欢

转载自blog.csdn.net/Travelerwz/article/details/81254922