-
规则
-
前景
-
场景分析
leader上传了代码,svn,git下载了代码,然后重新编译生成可执行文件.- 过程简单,但是为什么会更新呢,更新哪些呢?
-
三个要素
- 目标:编译更新或生成的最终产物,
exe,lib,so,dll都可能. - 依赖:用于生成
exe,lib,so,dll的文件或文件夹. - 指令:需要执行什么指令来生成目标.
- 目标:编译更新或生成的最终产物,
-
开发
- 变量:尽量少的编辑,一改全改.
- 函数:重复使用的代码抽象成函数,功能简单.
-
make的编译三要素target:表示最终要生成更新的.prerequisite:target依赖的文件或文件夹,在生成前,需要准备好这些是最新的.recipe:生成target需要的指令.
-
make与开发- 变量:有变量引用和函数引用.
- 函数:
rule规则.
-
-
默认
target -
语法解析
-
常见格式
targets : prerequisites recipe targets : prerequisites ; recipe recipe -
targets -
recipe -
prerequisite-
说明
target的依赖文件或文件夹.用于判断target是否需要更新.
-
$符号- 常规扩张用
$$表示. - 二次扩张用
$$$$表示. - 参考
- 常规扩张用
-
逻辑行
- 可以用行尾添加
\的方式将一个很长的行拆分成多行. - 但是意义不变.
- 可以用行尾添加
-
作用
- 挨个和
target比较,任何一个比target新,就说明target需要重新生成. - 但是在处理
target之前需要处理每一个prerequisite,这些也要保证最新. - 也要执行同样的
rule处理,每一个prerequisite都会进行rule处理. - 可能
makefile中没有定义对应规则,但是还有内置隐式规则.
- 挨个和
-
比较方式
- 时间戳
last modify time.
- 时间戳
-
-
模型
class Target: def __init__(self,name,prerequisite,recipe): self.name = name self.ltime = ltime(self.name) self.prerequisites = prerequisite; self.recipe = recipe def update(target) newer=False if not exists(target): target.ltime = 0 else: target.ltime = fileinfo(target.name).ltime for file in target.prerequisites: if update(file) < target.ltime: newer = True if newer: target.recipe() return timestamp() else: return 0- 伪代码
-
-
-
两类
prerequisite-
前言
-
使用
-
包含
order-only的处理模型class Target: def __init__(self,name,prerequisite,order_only,recipe): self.name = name self.ltime = ltime(self.name) self.prerequisites = prerequisite; self.order_only = order_only self.recipe = recipe def update(target) newer=False if not exists(target): target.ltime = 0 else: target.ltime = fileinfo(target.name).ltime for file in target.prerequisites: if update(file) < target.ltime: newer = True for file in target.order_only: update(file) if newer: target.recipe() return timestamp() else: return 0 -
order-only使用- 这类
prerequisite一般都是用来保证生成前的某些东西是存在的,或者生成前执行某些操作. - 比如生成前
Bin目录要存在,不存在就创建.
- 这类
-
格式
targets : normal-prerequisites | order-only-prerequisites -
格式说明
- 左边是普通的,右边是
order-only的. - 两边都有,则以左边为准,左边的已经包含了更新和存在检测,是
order-only的超集. - 两个分别在不同的处理集合中.
- 处理顺序是:先处理
normal再处理order-only.order-only与normal交叉出现也是normal先处理.
- 左边是普通的,右边是
-
-
-
通配符
-
prerequisite搜索-
前景
-
VPATH -
vpath-
说明
- 和
VPATH类似,但是这个更加的灵活. - 按照匹配规则进行搜索,文件夹也更加灵活.
- 和
-
格式
vpath pattern directories vpath pattern vpath -
格式说明
- 第一个是定义,路径格式和
VPATH相同. - 第二个是取消定义.
- 第三个是取消所有定义.
pattern用%当通配符,匹配零或多个字符.pattern原字符表示\%.- 定义了多个同样的
pattern则路径值是拼接在一起的.而不是替换.
- 第一个是定义,路径格式和
-
搜索
- 当前路径不存在,就搜索
vpath. vpath按照定义的匹配规则进行匹配,然后用定义的路径进行搜索.- 如果多个规则可以匹配,则按照先后顺序进行依此搜索.
- 当前路径不存在,就搜索
-
案例分析
vpath %.c foo vpath % blish vpath %.c bar%.c重复,%.c的路径有foo bar%表示所有.- 搜索
xx.c则是按照foo,bar,blish依此搜索.
-
-
搜索处理
-
处理算法
prerequisite先在当前目录为工作目录下搜索.搜不到再进行目录搜索.- 搜到了,搜索路径暂时存放,作一个为
target. - 然后保存的路径作为
target的prerequisite以同样的方式进行处理. - 执行完了搜索并处理更新,就需要判断是否需要执行
recipe. - 如果
prerequisite要执行更新,仅仅保留原样,不保存完整路径. - 如果
prerequisite不用执行更新,源recipe中的prerequisite使用搜索后的路径.
-
特殊
- 使用
GPATH=xxx声明可以保留完整路径,不管是否是需要更新,但是可能有的make不支持.
- 使用
-
说明
- 对
prerequisite的处理步骤是. - 先进行当前文件夹搜索文件.
- 搜不到再搜索显式或隐式规则进行生成.
- 再进行
vpath进行搜索,尝试其他文件夹. - 再搜索
VPATH.
- 对
-
-
总结
-
recipe怎么处理 -
lib,so库搜索
-
-
PHONY -
没有
prerequisite,recipe的rule -
特殊的
target-
.PHONYprerequisite是特殊的target,这类型的target总是执行prerequisite.- 这类通常可以看作是指令.
-
.DEFAULT- 任何没有匹配的
rule(隐式和显式规则),就总是执行这个的recipe.
- 任何没有匹配的
-
.PRECIOUS- 这个的
prerequisite作为target编译的时候被打断不会被删除. - 中间文件也不会被删除.
- 隐式规则相关
.INTERMEDIATE,.SECONDARY.
- 这个的
-
.SECONDEXPANSION- 后面的所有
rule的prerequisite还会进行第二次解析.
- 后面的所有
-
.DELETE_ON_ERROR- 声明了,这个
make执行的时候,如果recipe的返回值有错误,则进行删除操作. - 就像是被信号中断一样.
- 声明了,这个
-
.EXPORT_ALL_VARIABLES- 将所有的变量都传递给子
make。 - 即所有的变量都
export.
- 将所有的变量都传递给子
-
.NOTPARALLEL- 当前的
make是线性. - 不影响子
make.
- 当前的
-
.ONESHELL- 指令不再是一行行的传递.
- 而是所有的一起传递.这种有时候更友好,效率更高.
-
.POSIX- 执行
recipe时,遇到错误返回值,就立即停止执行.
- 执行
-
-
一个规则多个
target -
一个
target多个rule-
说明
-
效果
- 多次定义
target,相当于将target的多个prerequisite按照顺序拼接在一起. - 有点类似用
\分成了多行,只是多地方定义更加的灵活.
- 多次定义
-
prerequisite处理- 拼接的方式有点类似二位数组.为什么说时二维而不是一维呢?
- 因为自变量处理的时候会不一样.
-
模型
def expandAuto(target): ... plen = len(target.prerequisite) for i in range(plen): temp = [] for file in target.prerequisite[i]: if file.name == "$+": temp.append(target.prerequisite[:i]) else: temp.append(file) target.prerequisite[i] = temp ... -
多
rule处理- 多个
target的rule定义只能有一个recipe. - 如果有多个以最后一个为准,同时输出错误信息.
- 多个
-
特殊
.开头的特殊target可以有多个recipetarget::格式的则是多个独立的定义处理.可以存在多个recipe.
-
-
使用
-
总结
- 使得对
target的prerequisite更加的灵活. - 和指令
include,ifeq,define等结合使用很有效果.
- 使得对
-
-
静态匹配规则
-
自动生成
rule-
说明
-
gcc选项-
注意
- 不要和其他的混用,比如编译混用.
- 这个指令选项专门用来做依赖查看的.
-
-M -
-MM- 和上面一样,但是不包含系统级别的头文件.
- 也就是说全是用户自定义的头文件.
include "self/defined/headers"
-
-MF file- 和
-MM,-M一起使用,将结果写入指定位置file处.没有这个选项,-MM,-M和与处理结果一起输出. - 和
-MD,-MMD一起使用,修改默认输出位置. file如果是-,则输出到标准输出stdout.
- 和
-
-MP- 为除了输入文件以外的输入文件的依赖文件都声明一个
rule - 比如
test.o: test.c test.h;和test.h:;两个rule. - 这种有时候友好,但是这种会带来问题.
- 为除了输入文件以外的输入文件的依赖文件都声明一个
-
-MT target- 修改
rule中的target. - 默认是只保留文件名并修改后缀为
.o.这种就可以修改target. - 一般是添加路径前缀或者是添加自身的
.mk适用同样的规则.因为依赖的文件变了很可能导致主文件的依赖发生改变. - 即
xx.o xx.mk:prerequisite,然后在主makefile中声明隐式规则处理. .mk的内容和prerequisite也息息相关.
- 修改
-
-MQ target- 和
-MT一样,不过是原样输出,即保留字符串. - 比如
-MQ '$(obj)xx.o'得到的target就是$$(obj)xx.o - 即
Q就是quotes的意思.
- 和
-
-MD- 等价于
-MF -MF file. - 但是输出文件名需要用
-o声明输出文件. - 默认是输入文件保留文件名后替换后缀为
.d.
- 等价于
-
-MMD-MD的无系统文件版本.
-
注意
- 输出比如
c,cpp,rule.target可能和源文件一样.
- 输出比如
-
-
依赖规则定义
最新推荐文章于 2021-08-22 23:23:12 发布
本文详细解析了Makefile的工作流程,包括规则定义、目标、依赖、指令、通配符、变量、搜索路径、隐式规则、静态匹配规则等方面。重点介绍了如何编译更新目标文件,如.exe、.lib、.so、.dll,并探讨了make工具的灵活性,如自定义目标、默认目标选择、通配符展开及prerequisite的搜索策略。同时,文章还涉及了GCC的编译选项用于自动生成依赖文件,以及隐式规则和静态匹配规则在项目构建中的应用。
470

被折叠的 条评论
为什么被折叠?



