Makefile 是一种用于自动化构建和管理项目的文件,它可以指导构建系统根据源代码、依赖关系和规则来生成可执行文件、库文件或其他构建产物。通常与 make 命令一起使用。它使用一种特定的语法来定义目标、依赖关系和构建规则,使得开发者能够自动化构建过程。
make
是一个命令行工具,用于执行 Makefile 文件中定义的规则,从而自动化项目的构建过程。
makefile默认文件名是Makefile
或 makefile,
通过使用 make
的 -f
选项,你可以指定除了当前目录中默认之外的其他 makefile。这样可以为项目中的不同目标或配置拥有多个 makefile。
例如,如果你的当前目录中有一个名为 myMakefile
的 makefile,你可以使用 make -f myMakefile
来执行该 makefile 中指定的构建指令
为什么要用makefile
我们用gcc编译c项目文件,需要使用的命令如下
gcc -c foo.c -o foo.o
gcc -c bar.c -o bar.o
gcc -c main.c -o main.o
gcc main.o foo.o bar.o -o app
如果项目中有几十上百个文件如果这样一个一个编译不仅费时费力还容易出错,对于大型、复杂的项目来说,使用 Makefile 可以通过定义规则和命令来管理复杂的构建逻辑,确保所有的依赖关系得到满足,并且在不同的环境中始终能够正确地构建项目。
一个简单的 Makefile 由一系列规则组成,每个规则包含了目标(target)、依赖关系(dependency)和构建命令(command)。当运行 make 命令时,它会解析 Makefile 并根据规则的定义来决定是否需要重新构建目标。如果目标不存在、依赖关系已更新或者需要重新构建目标,make 工具将执行规则中定义的命令来生成目标。
makefile的基本结构
TARGET... : PREREQUISITES...
COMMAND
TARGET:规则的目标,最终生成文件的名字或者是中间过程文件名,也可以是make执行的动作的名称。
PREREQUISITES:规则的依赖,生成目标所必须的文件名列表。
COMMAND:规则的命令。规则需要执行的动作,前面要加tab缩进
例如:
main.o : main.c
gcc -c main.c -o main.o
关键字
wildcard:
$(wildcard <PATTERN...>)
wildcard函数是针对通配符在函数或变量定义中展开无效情况下使用的,用于获取匹配该模式下的所有文件列表,<PATTERN...>
参数若有多个则用空格分隔。若没有找到指定的匹配模式则返回为空。
如果要展开工作目录下的所有c文件列表,用法如下:
$(wildcard *.c)
patsubst:
$(patsubst <pattern>,<replacement>,<text>)
patsubst函数返回被替换过后的字符串,若字符串中含有%
则可以用反斜杠\
来转义,即\%
来表示真实含义的%
字符。
比如OBJ = $(patsubst %.o %.c $(SRC))。意思是在SRC中找到所有.c 结尾的文件,然后把所有的.c换成.o。
dir:
从文件名序列中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前的部分。如果没有反斜杠,那么返回“./”。返回:返回文件名序列的目录部分。示例: $(dir src/foo.c hacks)返回值是“src/ ./”
notdir:去除路径 将文件的路径去除,只留下文件名。
addprefix
给每个string添加前缀,string之间用空格隔开。
$@
表示规则中的目标文件集。在模式规则中,如果有多个目标,那么, $@ 就是匹配于目标中模式定义的集合。
$%
仅当目标是函数库文件时,表示规则中的目标成员名。例如,如果一个目标是 foo.a(bar.o),那么, $% 就是 bar.o , $@ 就是 foo.a 。如果目标不是函数库文件(Unix 下是 .a , Windows下是 .lib ),那么,其值为空
$<
依赖目标中的第一个目标名字。如果依赖目标是以模式(即 % )定义的,那么 $< 将是符合模式的一系列的文件集。注意,其是一个一个取出来的
$?
所有比目标新的依赖目标的集合。以空格分隔。
$^
所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
$+
这个变量很像 $^ ,也是所有依赖目标的集合。只是它不去除重复的依赖目标。
Makefile模版文件
# 编译器设置
CC = gcc
# 编译选项设置
CFLAGS = -Wall -Wextra -g
# 目标文件设置
TARGET = your_program
# 源文件列表
SRCS = main.c file1.c file2.c
# 对象文件列表(根据源文件生成)
OBJS = $(SRCS:.c=.o)
# 默认目标
all: $(TARGET)
# 生成可执行程序
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) $^ -o $@
# 生成对象文件
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
# 清除编译生成的文件
clean:
rm -f $(OBJS) $(TARGET)