Skip to content

Makefile-初探

1. 常用预定义变量

$* 不包含扩展名的目标文件名称
$+ 所有的依赖文件,以空格分开,以出现的先后为序
$< 第一个依赖文件的名称
$? 所有的依赖文件,以空格分开,修改日期比目标的创建日期晚
$@ 目标的完整名称
$^ 所有的依赖文件,以空格分开,不包含重复的依赖文件
$% 如果目标是归档成员,则该变量表示目标的归档成员名称

2. 预备知识

  • 链接:将多.o文件,或者.o文件喝库文件链接成为可被操作系统执行的可执行程序
  • 静态库:文档文件,多个.o的文件集合;linux中后缀为.a;使用ar工具维护和管理
  • 共享库:多个.o文件的集合,由编译器按照特殊方式生成,linux中通常为可执行;动态加载到内存;多个可执行程序可共享库文件的代码段

3. Makefile规则

    TARGET…:PREREQUISITES…  
    COMMAND  
- TARGET:规则的目标,最终文件名&中间过程文件名;可以是make执行的动作名称 - PREREQUISTIES:规则的依赖,生成规则目标需要的文件名列表 - COMMAND:规则的命令行;每个命令必须以[Tab]开始,但不是所有以[Tab]开头的都是命令;make会将第一条规则之哦胡的所有以[Tab]开头的行作为命令行处理

4. make执行

  • 默认执行Make file的第一个规则,此规则的第一个目标成为“最终目的”
  • Makefile只会执行终极目标所需要的依赖的编译

5. 书写规则

(1). 尽量写为单目标、多依赖

(2). Makefile包含的5个内容

a. 显示规则

  • 在何种情况下,如何更新一个或多个目标文件

b. 隐含规则

  • 根据一类目标文件自动推导出来的规则,根据文件的后缀命,自动产生依赖文件并用默认命令对目标更新

c. 变量定义

d. 指示符

  • 指明在make程序读取makefile文件过程中所需要执行的动作,包括:

  • 读取指定文件作为makefile的一部分

  • 决定处理或者忽略Makefile中的某一特定部分

  • 定义一个多行变量

e. 注释

  • 字符后的内容作为注释

(3). makefile文件的命名

  • make会按照以下顺序寻找
  • GNUmakfile->makefile->Makefile
  • 当不是以上文件名时,可通过"-f"或者“--file”指定make读取的makefile文件;多个makefile文件会按照指定的顺序

(4). 包含其他makefile文件

  • 使用include:
    Include FILENAMES
    
  • FILENAMES是shell支持的文件名,可以使用通配符;
  • 一定不能用[Tab]开头
  • 找不到文件是的默认搜索路径:“. /usr/gnu/include /usr/local/include /usr/include”;make将使用规则创建通过指示符inlcude指定但未找到的文件

(5). makefile文件解析

  • 第一阶段:读取所有的makefile文件,并简历所有目标和依赖之间的依赖关系结构链表
  • 第二阶段:根据第一阶段的关系结构链表,决定那些目标需要更新,并重建

6. 变量取值

(1). 变量定义解析规则:

IMMEDIATE = DEFERRED
IMMEDIATE ?= DEFERRED
IMMEDIATE := IMMEDIATE
IMMEDIATE += DEFERRED or IMMEDIATE
Define IMMEDIATE

DEFERRED  
Endef
- 条件语句:make将预设条件正确的分支展开 - 规则的定义:所有的规则在make执行时,按照如下模式展开:

规则中目标和依赖如果引用其他的变量,则立即被展开;而规则命令行中的变量则延后展开

7. Makefile规则语法

(1). 语法格式:

(2). TARGETS可以是空格分开的多个文件名,可以使用通配符

(3). A(M)表示档案文件的成员M;

(4). 通常目标只有一个目标文件

(5). 书写规则

  • 命令可以和命令在同一行,使用“;”隔开
  • 命令在依赖描述的下一行,作为独立命令行是必须以[Tab]开始
  • Makefile中\(具有特殊含义(表示变量或者函数的引用),在规则中需要使用符号\),需要书写连续的$$
  • 对于较长的行,可以使用\进行分行

(6). 依赖类型

a. 常规依赖

  • 重建目标需要执行规则的顺序
  • 按照什么顺序和命令重建依赖文件

b. order-only依赖

  • 用于更新依赖的依赖
  • 使用管道符号"|"开始,作为目标的一个依赖文件:
     TARGETS:NORMAL-PREREQUISITES|ORDER-ONLY-PREREQUISITES
    
  • 常规依赖文件可以是空;同一个依赖同时出现在常规和order-only会被当做常规的处理

(7). 文件名使用通配符

a. 通配符与linux shell的通配符完全相同

b. 使用场合

  • 规则的目标、依赖中
  • 出现在规则的命令中,是在shell中执行完成的

c. wildcard函数

  • $(wildcard *.c)获取.c文件列表
  • \((patsubst %.c,%.o,\)(wildcard *.c))--将.c文件列表换为.o

(8). 命令行和搜索目录

  • 使用自动化变量
  • $^ 表示所有通过目录搜索得到的依赖文件的完整路径名

  • $@ 表示规则的目标

  • $< 通过目录搜索得到的依赖文件列表的第一个依赖文件

(9). 库文件和搜索目录

  • 指定依赖文件名“-lNAME”

8. 变量

(1). 变量规则

a. 使用“=”或者“define”定义

b. 可用于代表:

  • 文件名
  • 编译选项
  • 程序运行选项参数
  • 搜索源文件的目录列表
  • 编译输出目录

c. 变量名不包括:“:”、“#”、“=”

d. 变量名大小写敏感

e. 自动化变量

(2). 变量引用

  • 使用“\(()”或者"\){}"
  • 需要表示“\(”应用“\)$”表示

(3). 变量定义

  • 递归展开式变量“=”定义
  • 直接展开式变量“:=”定义
  • 定义空格“space:=$(nullstring)”
  • 条件赋值操作符:“?=”

(4). 高级用法

  • "$(VAR:A,B)"将其中“A”字符结尾的字换成“B”;同patsubst

(5). 追加变量值

  • “objects += another.o”

(6). override指示符

  • “override VARIABLE = VALUE”

(7). 目标指定变量

9. 条件判断

Ifeq($(CC),gcc)
    $(CC) -o foo $(objects) $(lib)
Endif
  • 关键字
  • Ifeq

  • Ifned

  • Ifdef

  • Ifndef

10. make的内联函数

(1). 文本处理函数

1. $(subst FROM,TO,TEXT)把TEXT中的FROM换成TO
2. $(patsubst PATTERN,REPLACEMENT,TEXT)搜索TEXT中空格分开的单词,将符合PATTERN的替换为REPLACEMENT
3. $(strip STRINT)去掉开头结尾空格
4. $(findstring FIND,IN)查找IN中的FIND字符串
5. $(sort LIST)将LIST中的单词按照字母顺序排序
6. $(word N,TEXT)去TEXT中的第N个单词
7. $(wordlist S,E,TEXT)从TEXT中取出S到E的单词串
8. $(words TEXT)统计TEXT中单词数目
9. $(firstword NAMES)取NAMES中的第一个单词

(2). 文件名处理函数

1. $(dir NAMES)取文件名目录部分
2. $(notdir NAMES)取文件名非目录部分
3. $(suffix NAMES)取文件名后缀
4. $(addsuffix SUFFIX,NAMES)为NAMES的每一项添加后缀SUFFIX
5. $(addprefix PREFIX,NAMES)为NAMES添加前缀PREFIX
6. $(join LIST1,LIST2)连接两个字串(没个列表之间对应index连接)
7. $(wildcard PATTERN)列出当前目录下符合PATTERN格式的文件名

(3). foreach函数

1. $(foreach VAR,LIST,TEXT)将LIST中的单词依次赋值给VAR,然后执行TEXT表达式

(4). if函数

1. $(if CONDITION,THEN-PART [,ELSE-PART])

(5). call函数

(6). value函数

(7). eval函数

(8). origin函数

(9). shell函数

(10). make的控制函数

1. $(error TEXT)
2. $(warning TEXT)

11. 执行make

(1). 直接执行make

(2). 指定makefile文件“make -f MAKEFILE”

(3). 指定终极目标

1. 第一个规则的第一个目标
2. 命令行指定makefile中目标名为捉急目标“make TARGET_NAME”
3. 替代命令的执行
4. 防止特定文件重建
5. 替换变量定义
6. 使用make进行编译测试:“make -k”

12. make的隐含规则

1. 隐含规则的使用
    1. make会根据源文件类型启动相应的隐含规则
    2. 隐含规则总存在一个目标模式和依赖模式;
    3. 同一个目标模式可以对应多个依赖模式
2. 模式的匹配
3. 万用规则
4. 重建内嵌隐含规则
5. 缺省规则
6. 后缀规则
7. 隐含规则搜索算法
8. make自动化变量
$@ 规则的目标文件名
$% 静态库的一个成员
$< 规则的第一个依赖文件名
$? 所有比目标文件更新的依赖文件列表
$^ 规则的所有依赖文件列表
$+ 与$^类似,保留重复文件
$(@D) 目标文件的目录部分
$(@F) 目标文件除目录部分
## 13. makefile基本约定
  1. makefile中应该包含“SHELL=/bin/sh”
  2. 明确限定可识别的后缀
    .SUFFIXES:  
    .SUFFIXES: .c .o
    
  3. 小心处理规则中的路径