Makefile 是一种用于描述项目编译规则、依赖关系和构建过程的文件,广泛应用于C/C++项目的自动化构建。它基于make工具,通过解析Makefile中的规则,确定哪些源文件需要重新编译,哪些目标文件需要重新链接,从而实现高效、精确的项目构建。
目标(Target):Makefile 中的目标通常对应于项目中的可执行文件、库文件或中间文件。每个目标由一个或多个依赖项(Prerequisites)和一个或多个命令(Commands)组成。
依赖项(Prerequisites):依赖项是构建目标所必需的文件,通常为源文件、头文件或其它目标文件。当依赖项比目标更新时,目标需要重新构建。
命令(Commands):命令是构建目标的具体操作,如编译源文件、链接目标文件等。命令以Tab键开始,多条命令可以放在同一行,也可以分行书写。
Makefile 规则的基本格式如下:
例如,一个简单的C程序Makefile可能包含如下规则:
变量:Makefile 支持定义变量,用于存储重复使用的值。变量定义格式为
variable = value或variable := value。使用变量时,需在其前加$符号,如$variable或${variable}。
示例:
宏:Makefile 提供了一些内置宏,如
$@(代表规则的目标)、$^(代表规则的所有依赖项)、$<(代表规则的第一个依赖项)。这些宏在命令部分使用,可以简化命令编写。
示例:
模式规则允许为一类文件定义通用的编译规则,通过 % 符号匹配文件名中的通配符。这极大地简化了对大量同类型文件的编译规则定义。
这条规则表示,任何形如 foo.o 的目标都可以通过编译对应的 foo.c 和 foo.h 来生成。
条件判断
Makefile 支持使用条件语句进行条件判断,以便根据不同的环境或需求选择不同的构建行为。
ifeq / ifneq
ifeq 和 ifneq 分别用于检查两个字符串是否相等或不相等。它们的语法如下:
示例:
ifdef / ifndef
ifdef 和 ifndef 用于检查某个变量是否已定义或未定义。它们的语法如下:
示例:
函数
Makefile 提供了一系列内置函数,用于处理文件名、字符串、列表等。常用的函数包括:
wildcard
wildcard 函数返回与给定模式匹配的所有文件名。这对于动态列举源文件或依赖文件非常有用。
示例:
patsubst
patsubst 函数用于模式替换,将列表中符合模式的字符串替换为指定的新字符串。
示例:
foreach
foreach 函数用于遍历列表中的元素,并对每个元素执行指定的操作。
示例:
多目标
一个规则可以有多个目标,共享相同的依赖项和命令。这在多个目标文件具有相同编译选项或依赖于相同库文件时非常有用。
递归 Makefile
对于多级目录结构的项目,可以使用递归 Makefile 在子目录中调用 make。通常在顶层 Makefile 中定义一个目标,如 subdirs,然后在子目录中各自编写 Makefile。
顶层 Makefile 示例:
子目录 Makefile 示例: