make/Makefile使用介绍
make
是一个命令makefile
是一个在当前目录下存在的一个具有特定格式的文本文件
下面我们设计一个场景,实现make
命令对我们code.c
文件进行编译和删除。
1 #include<stdio.h>
2
3 int main()
4 {
5 printf("hello,world!\n");
6 return 0;
7 }
以下是makefile
的内容:
1 myexe:code.c //依赖关系
2 gcc code.c -o myexe //依赖方法
3 .PHONY:clean //clean是伪目标
4 clean: //可不写依赖目标
5 rm -f myexe //依赖方法
.PHONY
修饰的是伪目标,意思是总是被执行的,依赖方法总是会被执行,不会被任何情况拦截,想执行就执行。我们在命令行输入make
就可以对code.c
文件进行编译,生成myexe
可执行文件,make clean
就可以删除生成的可执行文件myexe
。现实中,有了依赖关系和依赖方法就可以描述清楚一件事情的原因和做法,达到我们的目标。
make
后面跟着目标,只有make
就会执行第一个扫描到的目标的依赖方法。如果我们连续两次make
就会发现报错。
原因是我们对code.c
编译过一次后并没有对原文件进行修改,重新编译也是浪费时间和资源,所以就不会再帮我们重新编译了。但如果我们对myexe
加上.PHONY
修饰的话,就可以无视拦截。
这种拦截可以提高编译效率,对于大型项目如果我们只修改了一个小文件就要把整个项目重新编译一遍就有点浪费时间了,这种情况下只需要重新编译修改了的文件即可。大部分情况下没问题,问题的产生不仅仅是修改新文件就能解决的,有些历史问题需要重新清理项目才能解决。
那么问题来了,编译器怎么知道我们有没有修改文件呢?
本质是对比源文件和可执行文件的修改时间,因为一定是现有源文件才有可执行文件,当源文件的修改时间 < 可执行文件的修改时间就说明没有更改,反之则说明更改了源文件内容
文件的ACM时间
一个文件有三种时间(文件=内容+属性)
- Access:最近一次读取文件的时间
- Modify:最近一次修改文件内容的时间
- Change:最近一次修改文件属性的时间
关于ACM时间变化的细节:
一般情况下Modify更改会带动Change一起更改,因为Modify更改会发生文件大小的改变,就相当于更改了文件属性。更改文件的权限此时Change也会变化,因为这些都是对文件属性的更改。
Access时间理论上只要是我读取/打开了文件就会发生变化,但实际并不如此,这里有两种情况:
- 读取/打开好几次文件Access才会发生变化
- 只有修改了文件内容,再读取/打开Access才会发生变化
造成这种现象的原因是一个文件被查看的频率非常高,每次查看都要更改Access,本质就是访问磁盘,如果是这样那么Linux系统就会充满大量访问磁盘的IO操作,变相降低系统效率,所以就对文件的Access时间的更改进行了一些限制
touch [文件名]
可以在不更改内容的情况让文件的时间变成最新的。
make/Makefile拓展
推导性
make/makefile具有推导能力,如果当前目标依赖的文件不存在则会向下搜索去找以依赖文件为目标文件的依赖文件(一直套娃),直到某一个目标文件的依赖文件存在,就逐步往回执行依赖方法,如果搜索完了也没有找到就会退出并报错。
变量
makefile里可以设置变量,也可以对变量重新赋值
1 src=code.c //定义变量
2 target=myexe
3 cc=gcc
4
5
6 $(target):$(src) //&(变量名)
7 $(cc) $(src) -o $(target)
8 .PHONY:clean
9 clean:
10 rm -f myexe
其他
makefile对于目标文件和依赖目标可以用特定符号表示
1 myexe:code.c
2 gcc $^ -o $@ //$^代表冒号右边所有文件,$@代表冒号左边所有文件
3 .PHONY:clean
4 clean:
5 rm -f myexe
make
和make clean
的时候每次都会有打印出指令比较显眼,在依赖方法前加上@即可不显示指令,以及可以写多条依赖方法
1 myexe:code.c
2 @gcc $^ -o $@
3 @echo "编译文件"
4 .PHONY:clean
5 clean:
6 @rm -f myexe
7 @echo "清理文件"
以上语法拓展也可以组合使用。