在前面的文章中,我们已经介绍了 Makefile 的基本规则、目标与依赖关系,以及变量的定义方式。本篇将重点讲解 Makefile 中最核心、最实用的一部分——常用函数与自动变量
        这些函数在 Linux 内核、Bootloader 以及大型应用工程的 Makefile 中被大量使用,是阅读和编写复杂 Makefile 的基础。

1 Makefile 常用函数

        GNU Make 提供了大量内置函数,用于字符串处理、文件名操作以及流程控制。在实际工程中,Makefile 的“灵活性”和“可扩展性”很大程度上依赖这些函数

1.1 函数调用格式

        Makefile 中函数的统一调用格式为:

$(function arguments)

说明如下:

  • function:函数名
  • arguments:函数参数
  • 函数名与参数之间使用空格或 Tab分隔
  • 如果有多个参数,参数之间用逗号 , 分隔
  • 空格和逗号不属于参数值的一部分

        在 Linux 内核的 Makefile 体系中,函数的使用极其频繁,理解这些函数是阅读内核 Makefile 的关键前提。


2 字符串替换与分析函数

(1)subst —— 字符串替换函数

$(subst from,to,text)

功能:

在字符串 text 中,将所有的 from 替换为 to

示例:

$(subst ee,EE,feet on the street)

结果为:

该函数通常用于简单的字符串整体替换

(2)patsubst —— 模式替换函数(极其常用)

$(patsubst pattern,replacement,text)

功能:

  • text 中查找符合 pattern 的单词,并用 replacement 替换
  • patternreplacement 中可以使用通配符 %

示例:

$(patsubst %.c,%.o,x.c.c bar.c)

结果为:

📌 说明
patsubst 是 Makefile 中最常用的函数之一,大量用于从 .c 文件列表生成 .o 文件列表

(3)strip —— 去除多余空格

$(strip string)

功能:

  • 去除前导和结尾空格
  • 将中间连续的多个空格压缩为一个

示例:

$(strip a   b c )

结果为:

(4)findstring —— 字符串查找

$(findstring find,in)

功能:

  • 若在 in 中找到 find,返回 find
  • 否则返回空字符串

示例:

$(findstring a,a b c)   # 返回 a
$(findstring a,b c)     # 返回空

(5)filter —— 条件过滤

$(filter pattern...,text)

功能:

  • text 中筛选出符合 pattern 的单词
  • 其余单词会被去除

示例:

$(filter %.c %.s,foo.c bar.c baz.s ugh.h)

结果为:

(6)filter-out —— 反向过滤

$(filter-out pattern...,text)

功能:

  • text 中删除符合 pattern 的单词
  • 返回剩余内容

示例:

$(filter-out %.c %.s,foo.c bar.c baz.s ugh.h)

结果为:

(7)sort —— 排序并去重

$(sort list)

功能:

  • 对单词按字母顺序排序

  • 去掉重复项

示例:

$(sort foo bar lose)

结果为:

3 文件名处理函数

(1)dir —— 获取路径部分

$(dir names...)

示例:

$(dir Makefile)

结果:

(2)notdir —— 获取文件名

$(notdir names...)

示例:

$(notdir Makefile)

结果:

(3)suffix —— 获取后缀名

示例:

$(suffix test.txt)

结果:

(4)basename —— 去除后缀

示例:

$(basename test.txt)

结果:

(5)addsuffix / addprefix —— 批量添加后缀与前缀

在实际工程中,我们经常需要对一组文件名进行统一处理,例如:

  • 给一批源文件名加上后缀 .c.o

  • 给一批文件名前统一加上目录路径(如 src/obj/

为此,GNU Make 提供了两个非常实用的函数:addsuffixaddprefix

addsuffix 函数原型:

$(addsuffix suffix,names...)

参数说明:

  • suffix:要添加的后缀字符串
  • names...:由空格分隔的一组文件名(可以是变量)

功能说明:

suffix 依次附加到 names... 中的每一个独立单词后面,并以空格形式拼接返回。

示例:

$(addsuffix .c,foo bar)

执行过程等价于:

  • foofoo.c
  • barbar.c

最终结果为:

foo.c bar.c

📌 典型应用场景:

SRC := main sub util
CFILES := $(addsuffix .c,$(SRC))

展开后:

main.c sub.c util.c

该方式常用于从不带后缀的模块名生成源文件列表

addprefix函数原型:

$(addprefix prefix,names...)

参数说明:

  • prefix:要添加的前缀字符串(通常是路径)
  • names...:由空格分隔的一组文件名

功能说明:

prefix 依次添加到 names... 中每一个文件名前面,并返回新的文件名列表。

示例:

$(addprefix src/,foo bar)

执行过程等价于:

  • foosrc/foo
  • barsrc/bar

最终结果为:

src/foo src/bar

📌 典型应用场景:

OBJS := main.o sub.o
OBJ_FILES := $(addprefix obj/,$(OBJS))

展开后:

obj/main.o obj/sub.o

该用法在多目录工程、分离源码目录和目标目录时极其常见。

addprefix + addsuffix 组合使用(重点)

在真实工程中,这两个函数经常组合使用,用于快速构造完整路径文件名。

示例:

FILES := main sub
SRCS := $(addsuffix .c,$(FILES))
FULL_SRCS := $(addprefix src/,$(SRCS))

最终结果为:

src/main.c src/sub.c

等价于一行写法:

FULL_SRCS := $(addprefix src/,$(addsuffix .c,$(FILES)))

4️⃣ 与 wildcardpatsubst 的区别

函数 作用特点
addsuffix 只做字符串拼接,不检查文件是否存在
addprefix 只做字符串拼接
wildcard 获取真实存在的文件
patsubst 按模式进行替换

📌 重要提示:

addsuffixaddprefix 不关心文件是否真实存在,只是对字符串进行处理。

5️⃣ 小结(工程经验)

  • addsuffix:适合 统一生成后缀

  • addprefix:适合 统一添加路径

  • 两者组合使用,可快速构建源文件和目标文件列表

  • 大型 Makefile 中的高频函数

(6)wildcard —— 获取真实存在的文件

示例:

$(wildcard *.txt)

结果:

⚠️ 与 shell 中的通配符类似,但只返回真实存在的文件

4 其他常用函数

(1)foreach —— 循环展开

$(foreach var,list,text)

执行过程:

  1. 先展开 list
  2. 将 list 中的每个值依次赋给 var
  3. text 进行多次展开
  4. 最终结果以空格拼接

示例:

dirs := a b c d
files := $(foreach dir,$(dirs),$(wildcard $(dir)/*))

等价于:

files := $(wildcard a/* b/* c/* d/*)

(2)if —— 条件判断

$(if condition,then-part,else-part)

注意事项:

  • 只会执行 then-partelse-part 中的一个
  • 不会同时执行,避免副作用(如 shell

(3)origin —— 判断变量来源

$(origin variable)

常见返回值:

  • undefined:变量var从来没有定义;
  • file:变量var在Makefile中定义;
  • environment:变量var作为环境变量定义,选项-e没有打开;
  • command line:变量var在命令行中定义;
  • automatic:变量var为自动变量

该函数在调试复杂 Makefile时非常有用。

(4)shell —— 调用外部命令

$(shell command arguments)

示例:

c_src := $(shell ls *.c)

📌 返回值说明:

  • 换行符会被转换为空格
  • 结尾的换行符会被自动去除

5 综合示例:options 程序 Makefile 解析

示例 Makefile

src  := $(shell ls *.c)
objs := $(patsubst %.c,%.o,$(src))

test: $(objs)
	gcc -o $@ $^

%.o: %.c
	gcc -c -o $@ $<

clean:
	rm -f test *.o

自动变量说明

变量 含义
$@ 当前目标
$^ 所有依赖
$< 第一个依赖

编译流程分析

目录内容:

main.c
sub.c
sub.h
Makefile

首次执行:

make

输出:

gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
gcc -o test main.o sub.o

修改 sub.c 后再次执行:

gcc -c -o sub.o sub.c
gcc -o test main.o sub.o

只重新编译发生变化的源文件,提高了编译效率

6 总结

  • Makefile 函数是工程 Makefile 的“灵魂”
  • patsubstwildcardforeach 使用最为频繁
  • 自动变量使规则更加通用、简洁
  • 理解这些内容后,可轻松阅读内核和大型项目的 Makefile
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐