目录
一、需求引出:
- 在使用编译器编译代码时,无论我们在一个项目中写了多少个文件(包括头文件、源文件),我们都可以一键完成编译,编译器会自动处理各个文件之间的包含,调用关系。
- 但是在Linux中,我们在一个目录下写一个项目,如果这个项目包含多个头文件和多个源文件,我们需要将他们手动一个个编译成 ".o" 文件,然后链接生成可执行程序。虽然不会耗费很多时间,但是依旧没有使用编译器那样方便。
- 而且,如果我们修改了项目中的一部分文件,我们就需要重新编译这些修改的文件。换而言之,我们需要记住每一个被修改过的文件。这未免成本过高,远不如直接使用编译器划算。
- 所谓自动化构建代码,就是为了解决以上的问题。使得在Linux下也可以像编译器一样,一键将项目编译生成可执行程序。
二、需要的文件和工具:
- 需要的文件为Makefile文件,直接建立在项目所在目录下。需要注意的是该文件的名称一定要为Makefile或者makefile,不能是其他。
- 需要的工具是make,它是用来调用makefile文件的。
- 我们可以简单理解:makefile是一个脚本文件,make是一个脚本解释器。
三、makefile实现简单的自动化构建可执行程序:
3.1代码详细解析:
- 第一行:要形成的可执行程序的名称 :需要编译的文件的名称
- 第二行:tab键开头(不能使用空格替代) 要执行的命令
- 第一行称为依赖关系,第二行称为依赖方法。通过依赖关系调用依赖方法即可完成自动化调用。
mycode:code.c
gcc code.c -o mycode
3.2实例分析:
- 首先创建一个code.c文件,功能是打印mycode字符串。
- 当前目录下没有可执行程序mycode
- 使用make,自动调用makefile文件中的第一个目标文件。
- 查看当前目录,发现生成了可执行程序mycode,并且运行发现可以正常运行。
四、makefile实现清理可执行文件、临时文件:
4.1代码详细解析:
- 第一行:.PHONY:clean ,使用.PHONY修饰clean,表示clean是一个伪目标文件,将一个目标文件设置为伪目标,就可以省略他的依赖关系或者依赖方法。
- 第二行:“clean:”,表示clean目标文件。
- 第三行:tab开头 要执行的指令。
.PHONY:clean
clean:
rm -f mycode
4.2实例分析:
- 当前目录存在可执行程序mycode
- 调用makefile文件的clean命令
- 查看目录,发现可执行程序mycode被清理
五、如何规范的使用make解释器:
5.1规范使用及细节:
- 使用make解释器调用makefile文件时,语法为:“make+目标文件”
- 可以直接make不加目标文件,这样使用会直接调用makefile文件的第一个命令,上面第三点构建可执行程序时,就是直接make,可以回顾一下。
- 一般将清理工作的clean目标文件,放在makefile文件的结尾。
5.2make解释器自动判断代码新旧:
- makefile自动化生成可执行程序时,会自动识别代码的新旧,如果在上一次自动化生成可执行程序之后未对代码做出修改,make解释器会拒绝再次自动化构建可执行程序,这样做的原因是:在只修改项目部分文件的情况下,只对这些修改的文件重新编译链接,提高效率。
六、.PHONY修饰的伪目标文件:
6.1目标文件未被.PHONY修饰的情况解析:
- 如果一个目标文件未被.PHONY修饰,除了在特殊情况下,该目标文件只会被执行一次。比如make生成可执行程序。
6.2被.PHONY修饰的目标文件,变为“总是被执行的”:
- 被.PHONY修饰的目标文件,每次被调用到都会被强制执行,不再受限于文件和可执行程序之间Modify time的牵连。
七、make解释器自动判断代码新旧的原理:
- 我们知道,“文件=文件内容+文件属性” 。所以修改文件的内容,文件的属性就会被改变。那么我们猜想一下,make判断文件的新旧,可能是基于文件的某些属性被改变。
- 通过对比文件更改内容前后,我们发现文件的某些属性有所变化。其中文件的Modify time发生了改变。
- 我们知道先有源文件,源文件经过编译之后才会产生可执行文件。第一次编译源文件生成可执行文件后,可执行文件的Modify time一定是小于源文件的Modify time的。
- 当源文件再次被修改时,源文件的Modify time会被修改。此时的源文件的Modify time就会大于可执行文件的Modify time。如此,make编译器才会重新编译源文件生成可执行程序。
- 部分情况下,只修改项目中单个文件,重新编译后发现程序跑不了。有可能是被修改的文件关联其他文件,就需要clean后make重新生成可执行程序。
八、文件的ACM时间:
8.1ACM时间是什么?
- Access:文件最近的访问时间
- Modify:文件内容上一次修改的时间
- Change:文件属性上一次改变的时间
8.2ACM时间改变的本质和改变的受限:
- 文件在磁盘中被访问,文件的ACM时间就会发生改变。
- 在Linux中,充满了I/O操作。如果每一个I/O操作都会访问磁盘,无疑会大大拉低系统的效率,因此对文件ACM时间的改变添加了限制,在距离上一次访问文件后的某个限定次数或者时间周期内访问该文件,不会改变文件的ACM时间。
8.3更新ACM时间:
- 需要使用到的命令是touch命令
- -a选项,可以更新文件的Access时间,但是由于更新文件Access时间相当于修改了文件的属性,他的Change时间也会被修改。
- -m选项,会更新文件的Modify时间,同时修改文件的Change时间。
8.4修改文件Modify时间后可以重新编译:
- 根据上面的叙述,我们知道一个文件被再次编译形成可执行文件和他的Modify时间有关,所以使用touch -m更新文件的Modify时间之后,就可以重新对文件进行编译了。
九、make语法:
9.1取消make使用成功后的回显:
- 我们使用make调用目标文件后,都会回显被调用的依赖方法。如何使得这句回显消失呢?
- 答案是:在依赖方法前面加上@。
9.2使用echo+字符串,可以打印指定的字符串到显示器:
9.3使用#注释makefile文件中的目标文件:
9.4makefile支持变量替换:
- 在makefile文件中,可以使用变量替换,可以理解为宏替换。具体如下:
- 变量名要使用$开头,使用圆括号包裹。
9.5使用$^和$@可以替换依赖关系,简化依赖方法:
- $^:代表依赖关系冒号右侧所有内容。
- $@:代表依赖关系冒号左侧所有内容。