当前位置:首页>Linux>第005讲 Linux Makefile 简明教程:从规则到函数

第005讲 Linux Makefile 简明教程:从规则到函数

  • 2026-09-25 11:37:47
第005讲 Linux Makefile 简明教程:从规则到函数
一、Makefile 文件简介

Makefile 是一个用于自动化构建和编译程序的配置文件,它定义了一系列规则来指定如何编译和链接程序。它主要配合 make工具使用。

核心概念

Makefile 的核心是规则,基本语法为:

makefile目标: 依赖	  命令

目标(target):要生成的文件或要执行的动作名称

依赖(prerequisites):生成目标需要的文件

命令(recipe):如何生成目标的 shell 命令(必须以 Tab 键开头)

简单示例

hello: main.o greet.o	gcc -o hello main.o greet.omain.o: main.c greet.h	gcc -c main.cgreet.o: greet.c greet.h	gcc -c greet.cclean:	rm -f hello *.o

 常用概念

1. 变量

CC = gccCFLAGS = -Wall -gOBJS = main.o greet.ohello: $(OBJS)$(CC)$(CFLAGS) -o $@$^

$@ — 目标文件

$^— 所有依赖文件

`$<— 第一个依赖文件

2. 模式规则

makefile%.o: %.c$(CC)$(CFLAGS) -c $< -o $@

3. 伪目标

makefile.PHONY: cleanclean:	rm -f *.o hello

.PHONY声明伪目标,避免与同名文件冲突。

为什么使用 Makefile

只重新编译修改过的文件,大幅节省构建时间

标准化构建流程,团队成员无需记忆复杂命令

管理项目依赖关系,保证构建顺序正确

Makefile 广泛应用于 C/C++ 项目,也可用于任何需要自动化任务管理的场景。

二、Makefile 中的函数

Makefile 提供了丰富的内置函数,用于处理文本、文件名、条件判断等。函数调用的基本语法是:

makefile $(函数名 参数1,参数2,...)# 或${函数名 参数1,参数2,...}

参数之间用逗号分隔,函数名和第一个参数之间用空格分隔。

文本处理函数

1. subst — 字符串替换

makefile$(subst 被替换的文本,替换后的文本,目标文本)
makefile result = $(subst ee,EE,feet on the street)# 结果: fEEt on the strEEt

2. patsubst — 模式字符串替换

makefile$(patsubst 模式,替换后,目标文本)
makefileobjects = $(patsubst %.c,%.o,main.c greet.c)# 结果: main.o greet.o

 3. strip — 去除首尾空格

makefile$(strip   hello   world  )# 结果: hello world

 4. findstring — 查找字符串

makefile$(findstring 查找内容,被查找文本)# 找到则返回查找内容,否则返回空
makefileifneq ($(findstring linux,$(shell uname -r)),)# 在 Linux 内核下执行endif

5. filter / filter-out — 过滤/反过滤

makefilesources = foo.c bar.c baz.s ugh.hc-files = $(filter %.c %.h, $(sources))# 结果: foo.c bar.c ugh.hnot-c = $(filter-out %.c, $(sources))# 结果: baz.s ugh.h

6. sort — 排序去重

makefile$(sort foo bar lose foo)# 结果: bar foo lose

7. word — 取第 n 个单词

makefile$(word 2, foo bar baz)# 结果: bar$(words foo bar baz)# 单词数: 3$(firstword foo bar baz)# 第一个: foo$(lastword foo bar baz)# 最后一个: baz

文件名处理函数

makefile$(dir src/foo.c hacks)      # 目录部分: src/ ./$(notdir src/foo.c hacks)   # 文件名部分: foo.c hacks$(suffix src/foo.c src-1.0/bar)  # 后缀: .c$(basename src/foo.c src-1.0/bar) # 去掉后缀: src/foo src-1.0/bar$(addsuffix .c,foo bar)     # 加后缀: foo.c bar.c$(addprefix src/,foo.c bar) # 加前缀: src/foo.c src/bar$(join a b, .c .o)          # 逐词拼接: a.c b.o$(wildcard *.c)             # 通配符展开: main.c greet.c$(realpath names...)        # 获取绝对路径$(abspath names...)         # 获取绝对路径(不解析符号链接)

条件与逻辑函数

makefile$(if 条件,true分支,false分支)   # false 分支可选$(or 条件1,条件2)               # 第一个非空值$(and 条件1,条件2)              # 全部非空才返回最后值

示例:

makefileFOO = $(if $(filter linux,$(shell uname)),linux-specific,macos-specific)

特殊功能函数

1. foreach — 循环处理

makefile$(foreach 变量,列表,表达式)
makefiledirs = a b c dfiles = $(foreachdir,$(dirs),$(dir)/*.c)# 结果: a/*.c b/*.c c/*.c d/*.c

 2. call — 自定义函数

makefiledefine 函数名# 函数体,用 $(0) 代表函数名,$(1) $(2)... 代表参数endef
makefiledefine make-obj$(patsubst %.c,%.o,$(1))endefobjects = $(call make-obj,main.c greet.c)# 结果: main.o greet.o

3. eval — 动态生成 Makefile 内容

makefiledefine PROGRAM_template$(1): $(1).o$(CC) $(CFLAGS) -o$$@$$^endef$(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))

这会为 PROGRAMS 中的每个程序生成独立的构建规则。

4. shell — 执行 shell 命令

CURRENT_TIME = $(shell date +%Y-%m-%d)GIT_HASH = $(shell git rev-parse --short HEAD)

5. value — 取未展开的值

makefileFOO = $PATH$(value FOO)# 返回 $PATH 字符串本身

实用函数组合示例

获取某目录下所有 .c 对应的 .o 文件:

makefileSRCS = $(wildcard src/*.c)OBJS = $(patsubst %.c,%.o,$(SRCS))# 或简写为OBJS = $(SRCS:.c=.o)

生成依赖文件:

makefileDEPS = $(patsubst %.o,%.d,$(OBJS))-include$(DEPS)%.d: %.c	@$(CC) -MM $< | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' > $@

常用速查表

Makefile 的函数体系使其具备了强大的元编程能力,掌握了它们就能写出优雅、可维护的构建系统。

最新文章

随机文章