Lazy loaded image
学习笔记
📑Makefile 学习笔记
字数 2891阅读时长 8 分钟
2021-7-2
2026-1-7
type
status
date
slug
summary
tags
category
icon
password
😀
前言: 这是一篇我学习Makefile时记录的学习笔记
 

一、语法规则

一个 Makefile 由一组规则组成,规则通常如下所示:
  • 目标 target 是文件名(或伪目标),以空格分隔。通常每条规则只有一条。
  • 命令 command 是生成目标的一系列步骤。以制表符开头,不能用空格开头
  • 先决条件(依赖)prerequisites 是文件名(或伪目标),以空格分隔。这些文件需要在执行命令之前存在
上述其实是描述了一个文件依赖关系,即生成一个或多个 target 依赖于 prerequisites ,生成规则定义在 command中。
示例:
# 开头的为注释
执行:
再次执行:

二、all

如果 Makefile 中定义了多个目标,通常定义一个 all 目标来生成所有目标, 而且通常我们还习惯将 all 目标放在 Makefile 文件的第一个目标,或者设置 .DEFAULT_GOAL, 这样我们使用 make 就会默认执行 all 目标。
Makefile 中第一个目标会作为其默认目标,直接使用 make 即可,无需制定target。当然你也可以通过 .DEFAULT_GOAL 指定某个 target 为默认的 target

2.1 伪目标

上述的 clean 并不会真的生成一个 clean 文件,如果恰巧你的目录下面刚好有一个 clean 文件,make 就会提示:
为了避免和文件重名的情况,我们可以使用一个特殊的标记 .PHONY 来显式指明一个目标是“伪目标”,向 make 说明,不管是否有这个文件,这个目标都是“伪目标”。
目标可以成为依赖,伪目标同样可以成为依赖

2.2 多行

当命令太长,反斜杆 \ 字符使我们能够使用多行(和shell类似)

三、变量

变量是把一个名字和任意长的字符串关联起来。基本语法如下:
使用 ${}$()来引用变量
示例:

3.1 变量定义

  • = 仅在使用命名时解析变量值
  • :=在定义时立即解析变量值
示例:
B 最后的值为 c b,而不是 a b。也就是说,在用变量给变量赋值时,右边变量的取值,取的是最终的变量值。
  • ?=如果该变量没有被赋值,则赋值等号后面的值
B 最后的值为 a b。通过 := 的赋值方式,可以避免 = 赋值带来的潜在的不一致。
追加:
  • +=表示将等号后面的值添加到前面的变量上。
Makefile 还支持多行变量。可以通过 define 关键字设置多行变量,变量中允许换行。定义方式为:

3.2 环境变量

Makefile 还支持环境变量。在 Makefile 中,有两种环境变量,分别是 Makefile 预定义的环境变量和自定义的环境变量。
其中,自定义的环境变量可以覆盖 Makefile 预定义的环境变量。默认情况下,Makefile 中定义的环境变量只在当前 Makefile 有效,如果想向下层传递(Makefile 中调用另一个 Makefile),需要使用 export 关键字来声明。

3.3 空格

行尾的空格不会被删除,但开头的空格会被删除
示例:
未定义的变量时机上是一个空字符串

3.4 自动变量

makefile定义了一些自动变量,用于自动获取一些值,比如:
  • $@规则目标的文件名
  • $<第一个先决条件的名称
  • $?比目标新的所有先决条件的名称,它们之间有空格
  • $^所有先决条件的名称,它们之间有空格
示例:

四、通配符

  • 成为通配符
  • 可以在目标、先决条件或 wildcard 函数(查找指定目录下指定类型的文件)中使用
  • 不能在变量定义中直接使用
  • 当没有匹配到文件时,就会直接输出(保持原样),所以我们一般都是配合 wildcard函数使用
示例:

五、静态模式规则

静态模式规则可以更容易地定义多目标的规则,可以让我们的规则变得更加有弹性和灵活。
静态模式规则的语法:
匹配 target-pattern 生成 target, 匹配 prereq-patterns 生成 target-pattern
示例:
使用静态规则后:

5.1 filter

filter函数可用于静态模式规则匹配正确的文件
%匹配任何非空字符串

六、双冒号

双冒号规则很少使用,它允许为同一个目标定义多个规则
示例:
如果这些是单冒号,则会打印一条警告,并且只会运行第二条命令

七、命令

7.1 显示与隐藏

在命令之前添加 @ 以阻止它被打印
也可以运行 make 时使用 -s参数,这会为每一行命令添加一个 @

7.2 执行

每个命令都在一个新的 shell 中执行(至少效果是这样的)
比如:

7.3 默认 shell

默认 shell 是 /bin/sh,也可以通过更改变量 SHELL 来改变它:

7.4 递归使用make

要递归调用makefile, 需要使用 $(MAKE)变量代替 make
它会为你传递 make 标志并本身不会受到它们的影响

7.5 创建多个目标

make clean run test运行clean目标,然后run,然后test

7.6 define

define实际上就是一个命令列表
示例:

7.7 局部变量

八、条件

8.1 ifelse

值相等:
值不相等:
判空:
判断变量是否被定义:

九、函数

函数主要用于文本处理。使用$(fn, argument)调用函数

9.1 subst

用法是$(subst FROM, TO, TEXT), 将TEXT中的内容由FROM变味TO
示例:
打印:I am totally superman
打印: a,b,c

9.2 pathsubst

模式字符串替换函数
格式:$(pathsubst <pattern>,<replacement>,<text>)
查找<text>中的单词是否符合模式<pattern>, 如果匹配的话,则以<replacement>替换。
替换引用$(test:pattern=replacement)是对此的简写
示例:
输出:
echo
echo a.c b.c 1.a c.c a.c b.c 1.a c.c echo a.c b.c 1.a c.c a.c b.c 1.a c.c

9.3 foreach

$(foreach var,list,text): 将一个单词列表(由空格分隔)转换为另一单词列表。
list代表单词列表,var设置列表中的每个单词,text针对每个单词进行扩展
示例:
输出:who! are! you!

9.4 if

if检测第一个参数是否为空,如果是,则运行第二个参数,否则运行第三个。
输出:
then! else!

9.5 call

有点相当于我们自定义函数,$(call variable, param, param, ...): 在执行时,将它的参数 param 依次赋给 variable 中的临时变量 ${1}, ${2}
${0}可以获取variable变量名称
示例:
输出:variable name: sweet_new_fn first: go second: git empty variable:

9.6 shell

shell 函数就是调用 shell

十、包含

include 指令告诉 make 读取一个或多个其他 makefile

十一、vpath

使用 vpath 指定某些先决条件存在的位置
格式:vpath <pattern> <directories, spcase/colon separated>
<pattern>可以有一个%,用于匹配零个或多个字符
比如:
代表要求 make 在 ../headers目录下搜索所有以.h结尾的文件,前提是当前目录没有找到
示例:
 
 
上一篇
Git 使用指北
下一篇
Git 使用指北