📝前言:
这篇文章我们来讲讲Linux开发工具——make/makefile:
🎬个人简介:努力学习ing
📋个人专栏:Linux
🎀CSDN主页 愚润求学
🌄其他专栏:C++学习笔记,C语言入门基础,python入门基础,C++刷题专栏
目录
一,make/makefile基础介绍
make/Makefile
用于自动化构建和管理项目。
make
- 功能:make是一个命令工具,它根据
Makefile
中定义的规则来自动构建和管理项目。它可以自动检测源文件的修改情况,并仅重新编译那些需要更新的目标文件,从而大大提高了编译效率。 - 工作原理:
make
通过读取Makefile
中的规则,分析目标文件和依赖文件之间的关系(简称依赖关系)。然后,它根据文件的时间戳(modify
时间)来判断哪些文件需要重新编译。如果一个依赖文件的修改时间晚于目标文件,或者目标文件不存在,make
就会执行相应的命令来更新目标文件。 - 使用方法:在项目目录中,只需在命令行中输入
make
命令,它就会自动查找当前目录下的Makefile
,并按照其中的规则进行构建。如果Makefile
中有多个目标,make
默认构建第一个规则,后面的要指定要构建的特定目标,例如make target_name
。
Makefile
- 作用:Makefile是一个文本文件,它包含了一系列规则,用于告诉
make
工具如何构建项目。它定义了项目中的目标文件、依赖文件以及构建目标所需的命令(方法)。 - 基本结构:
Makefile
由一系列规则组成,每个规则通常包含以下部分:- 目标:通常是要构建的文件,如可执行文件、目标文件或库文件。也可以是一个抽象的目标,如
clean
用于清理生成的文件。 - 依赖:目标所依赖的文件列表。
- 命令:用于构建目标的命令。命令必须以
Tab
键开头。
- 目标:通常是要构建的文件,如可执行文件、目标文件或库文件。也可以是一个抽象的目标,如
(也可以认为:规则 = 依赖关系 + 依赖方法)
二,具体示例
1. 基础示例
先对前面介绍到的基础的概念和用法做演示。
步骤:
- 现在当前目录下创建
Makefile
文件:touch ./Makefile
- 根据需求,编写
Makefile
解释:
code.exe
是目标文件,code.c
是源文件(这是一组依赖关系,code.exe
依赖code.c
)Tab
开头,后面写依赖方法(构造目标用的命令)- 一个抽象的目标
clean
,可以没有所依赖的文件列表 - 依赖方法
调用示例:
make
默认调用第一个规则,即code.exe:code.c
这一个make clean
,调用clean
对应的规则- 为什么连续调用
make
会失败呢?
因为:make
根据文件modify
的时间戳来判断哪些文件需要重新编译。
1.1 时间戳
那什么是modify
时间戳,?
stat
查看文件时间属性
Access
:访问时间,当文件被查看,如cat
的时候会被修改(但有一些系统会优化,即:多次查看后才修改,为了减少磁盘I/O操作)Modify
:修改时间,代表文件最后一次被修改的时间,即内容有所改动,Modify
就会改变Change
:变更时间,当文件属性有变化的时候会改变Birth
:诞生时间,创建时的时间
1.2 是否重新编译判断
当源文件的modify
时间相比目标文件“旧”,代表没有源文件没有修改,则不重新编译
当源文件的modify
时间相比目标文件“新”,代表源文件修改了,则重新编译
如图:我们在没有执行make
之前,只有源文件1
,执行完后,有了目标文件1
,时间关系如上。此时再执行make
就不会再重新编译
如果我们更改了源文件:
这时候,代表有新内容,目标文件就需要重新编译
那有没有办法让make
无视时间戳,让依赖方法总是被执行呢?
有的兄弟,有的。那就是特殊目标声明:.PHONY
,将目标标记为伪目标。
此时,make
不用去检查伪目标对应的文件是否存在、是否更新,而是直接执行命令
2. 进阶1——依赖链
依赖链的结构就像一个栈:
- 检查其依赖
code.o
,发现code.o
不存在,则依赖方法入栈 - 检查
code.o
的依赖code.s
,发现code.s
不存在,则依赖方法也入栈 - …
- 检查
code.i
的依赖code.c
,发现code.c
存在,则执行code.i
的依赖方法 - 将栈中依赖方法依次执行
3. 进阶2——变量替换
定义变量:
=
:递归展开变量(不会在定义变量时立即对右侧的表达式进行求值,而是在使用该变量时才进行求值。这意味着变量的值可能会因为其他变量的改变而改变)
:=
:简单展开变量(在定义变量时就对右侧的表达式进行求值,变量的值在定义时就已经确定,后续不会因为其他变量的改变而改变)
引用变量:
$(变量名)
示例:
$@
和 $^
:
$@
指代目标文件,$^
指代依赖文件列表
即上面的内容可以改成:
这里$^
会自动对应这个方法的依赖关系中的$(SRC)
,$@
对应$(BIN)
4. 进阶3——多文件
4.1 获取当前目录下的所有文件
在Makefile中执行命令:$(shell 命令)
使用函数:$(函数名 参数1,参数2…)
获取当前目录下所有.c
文件后缀的方法:
$(shell ls *.c)
,回顾:ls
这个命令只列出名称$(wildcard *.c)
输入
make
运行结果:
执行的命令不回显
在命令前加:@
效果:
4.2 %<
当有多个源文件需要编译成目标文件,且每个源文件的编译命令基本相同时,使用 $<
能避免重复书写源文件名称。
$<
会被自动替换为当前规则中列出的第一个依赖文件的名称。例如,对于规则 target: dep1 dep2 dep3
,在其对应的命令里使用 $<
,它就代表 dep1
4.3 模式规则
%
:通配符,如%.c
:所有以.c
结尾的文件
%.o: %.c
:这个规则中,%
所匹配的内容在目标和依赖中是相同的。(同名)
当 make工具处理这个规则时,会针对每个 .o
文件的构建分别执行一次规则里的命令
错误写法:
报错:
make: *** No targets. Stop.
因为:%.o: %.c
只是一个模式规则,并没有具体构建目标。具体的构建目标是指在 Makefile 中明确指定要构建的文件,文件名需要是完整且能明确指向一个具体文件的。
正确使用示例:
额外语法:
- 命令可以多行,但是也要
Tab
开头 - 注释用
#
符号
理解执行过程:
- 具体构建目标:
code.exe
,依赖所有.o
文件,没有.o
文件,于是到下一个规则%.o:%.c
%.o:%.c
规则中,make会针对每个.o
文件分别执行一次命令,此时,每个.o
文件变成了这个规则里的具体构建目标
运行结果:
🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!