### 跟我一起写Makefile #### 第一部分:概述 **Makefile**是一种用于自动化构建过程的脚本文件,在软件开发过程中极为常见。通过编写Makefile,开发者可以定义一系列规则来描述如何编译和链接源代码文件,从而构建出最终的可执行文件或其他输出。Makefile通常与`make`工具结合使用,该工具负责解析Makefile中的规则,并根据这些规则执行相应的编译或构建任务。 #### 第二部分:关于程序的编译和链接 在软件开发中,源代码文件需要经过**编译**(将源代码转换为机器语言)和**链接**(将多个目标文件连接成单一可执行文件)两个步骤才能形成可执行的程序。Makefile通过定义清晰的规则来管理这个过程,确保每次构建时都能得到正确的结果。 #### 第三部分:Makefile介绍 ##### 一、Makefile的规则 - **规则**定义了如何生成特定的目标文件。 - 规则通常包括一个或多个目标、对应的依赖项以及用于构建目标的命令。 ##### 二、一个示例 假设有一个简单的项目,包含两个源文件`main.c`和`helper.c`,它们分别被编译成`main.o`和`helper.o`,然后链接成最终的可执行文件`app`。一个简单的Makefile可能如下所示: ```make CC=gcc CFLAGS=-Wall app: main.o helper.o $(CC) -o app main.o helper.o main.o: main.c $(CC) $(CFLAGS) -c main.c helper.o: helper.c $(CC) $(CFLAGS) -c helper.c ``` 这段Makefile定义了三个规则:一个是生成`app`的规则,另外两个是生成`.o`文件的规则。 ##### 三、make是如何工作的 当运行`make`命令时,它会读取Makefile文件,分析其中的规则,并根据目标文件的最后修改时间决定哪些文件需要重新编译或链接。 ##### 四、makefile中使用变量 Makefile支持使用**变量**来存储常用的路径、编译选项等信息,这样可以使Makefile更易于维护。 ##### 五、让make自动推导 通过使用隐含规则(也称为内置规则),make可以自动识别文件类型并应用适当的编译命令。例如,如果Makefile中没有明确地定义`.c`到`.o`的规则,make将自动使用默认的编译命令。 ##### 六、另类风格的makefile 除了标准的Makefile格式外,还可以使用其他风格,比如使用通配符或者模式规则来简化规则的编写。 ##### 七、清空目标文件的规则 通常还需要定义一个清除规则,如`clean`,以便于清理中间文件或输出文件。例如: ```make clean: rm -f *.o app ``` #### 第四部分:Makefile总述 Makefile通常包含以下元素: 1. **显式规则**:定义具体的目标及其依赖关系。 2. **隐晦规则**:make内置的一系列规则,用于自动编译常见类型的文件。 3. **变量的定义**:存储编译器路径、编译选项等常用信息。 4. **文件指示**:用于包含其他Makefile文件。 5. **注释**:以`#`开始的行被视为注释。 #### 第五部分:书写规则 ##### 一、规则举例 前面的示例已经展示了一个简单的规则。 ##### 二、规则的语法 基本语法如下: ```make target: dependencies command ``` 其中`target`是目标文件,`dependencies`是目标所需的依赖文件,`command`是在构建目标时需要执行的命令。 ##### 三、在规则中使用通配符 可以通过使用通配符(如`*`)来匹配多个文件。例如: ```make %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ ``` 这里`$<`代表依赖文件,`$@`代表目标文件。 ##### 四、文件搜寻 可以通过设置`VPATH`变量来告诉make在哪里查找源文件。 ##### 五、伪目标 某些目标并不是实际的文件,而是用来触发特定操作的标志,称为**伪目标**。例如: ```make .PHONY: clean clean: rm -f *.o app ``` ##### 六、多目标 有时需要定义多个目标,可以使用逗号分隔: ```make app: main.o helper.o ``` ##### 七、静态模式 静态模式规则允许使用更灵活的模式来匹配目标和依赖项,使得Makefile更加通用。 #### 第六部分:书写命令 - **显示命令**:Makefile中的命令可以直接执行。 - **命令执行**:`make`按顺序执行Makefile中的命令。 - **命令出错**:当命令执行失败时,`make`会停止执行。 - **嵌套执行make**:可以在Makefile中调用另一个`make`命令。 - **定义命令包**:通过将相关的命令封装在一起,使Makefile更加模块化。 #### 第七部分:使用变量 变量是Makefile中非常重要的组成部分,可以用来存储各种信息。 ##### 一、变量的基础 ```make CC=gcc CFLAGS=-Wall ``` ##### 二、变量中的变量 可以在变量定义中引用其他变量: ```make CC=gcc CFLAGS=-Wall LDFLAGS=$(CFLAGS) ``` ##### 三、变量高级用法 - **函数调用**:使用内置函数来处理字符串或列表。 - **条件表达式**:根据不同的条件选择不同的值。 ##### 四、追加变量值 可以使用`+=`运算符来追加变量值: ```make CFLAGS=-Wall CFLAGS+=-Wextra ``` ##### 五、override指示符 可以在Makefile中使用`override`指令来改变变量的值: ```make CFLAGS=-Wall override CFLAGS+=-Wextra ``` ##### 六、多行变量 可以定义跨越多行的变量: ```make SOURCES=\ main.c \ helper.c ``` ##### 七、环境变量 可以通过环境变量来传递信息到Makefile: ```make CFLAGS=$(shell gcc -v | grep version) ``` ##### 八、目标变量 为目标文件定义特定的变量: ```make app: LDFLAGS=-lfoo ``` ##### 九、模式变量 可以根据模式匹配来定义变量: ```make %.c: %.h $(CC) $(CFLAGS) -c $< -o $@ ``` #### 第八部分:使用条件判断 ##### 一、示例 使用`ifeq`进行条件判断: ```make ifeq ($(OS),Windows_NT) CFLAGS+=-mwindows endif ``` ##### 二、语法 条件语句的基本语法: ```make ifeq (value1, value2) # commands if true else # commands if false endif ``` #### 第九部分:使用函数 Makefile提供了多种内置函数来处理字符串和文件名。 ##### 一、函数的调用语法 ```make $(function argument) ``` ##### 二、字符串处理函数 - `subst`:替换字符串。 - `patsubst`:模式匹配替换。 - `strip`:去除前后空白字符。 - `findstring`:查找子串。 - `filter`:过滤字符串。 - `filter-out`:排除字符串。 - `sort`:排序字符串。 - `word`:获取字符串中的单词。 - `wordlist`:获取单词列表。 - `words`:计算单词数量。 - `firstword`:获取第一个单词。 ##### 三、文件名操作函数 - `dir`:提取目录名。 - `notdir`:提取非目录部分。 - `suffix`:提取文件扩展名。 - `basename`:提取基本文件名。 - `addsuffix`:添加文件扩展名。 - `addprefix`:添加前缀。 - `join`:连接两个列表。 ##### 四、foreach函数 遍历列表中的元素。 ##### 五、if函数 进行条件判断。 ##### 六、call函数 调用其他函数。 ##### 七、origin函数 获取变量的来源。 - **undefined**:变量未定义。 - **default**:变量有默认值。 - **file**:变量在Makefile中定义。 - **commandline**:变量在命令行中定义。 - **override**:变量被override指令覆盖。 - **automatic**:变量是自动变量。 ##### 八、shell函数 在Makefile中执行shell命令。 ##### 九、控制make的函数 - `error`:显示错误消息并终止`make`。 - `warning`:显示警告消息但继续执行。 #### 第十部分:make的运行 ##### 一、make的退出码 - **0**:成功。 - **1**:失败。 ##### 二、指定Makefile 可以通过`make -f <Makefile>`来指定Makefile文件。 ##### 三、指定目标 可以通过`make target`来指定构建的目标。 ##### 四、检查规则 使用`make -n`来查看将会执行哪些操作,而不实际执行。 ##### 五、make的参数 可以通过`-j`选项来指定并行构建的数量,提高构建速度。 #### 第十一部分:隐含规则 隐含规则是Makefile的一个强大特性,可以大大简化规则的编写。 ##### 一、使用隐含规则 通过定义特定的文件扩展名,make可以自动应用相应的规则。 ##### 二、隐含规则一览 隐含规则支持多种编程语言,例如C、C++、Pascal等。 ##### 三、隐含规则使用的变量 - **关于命令的变量**:如`CC`用于指定编译器。 - **关于命令参数的变量**:如`CFLAGS`用于指定编译选项。 ##### 四、隐含规则链 当一个文件可以由多种规则生成时,make会尝试按照一定的顺序来选择规则。 ##### 五、定义模式规则 模式规则允许使用更复杂的模式匹配来定义规则。 ##### 六、老式风格的"后缀规则" 后缀规则是一种特殊的模式规则,主要用于简单的文件转换。 ##### 七、隐含规则搜索算法 make会按照特定的顺序搜索隐含规则,确保找到合适的规则。 #### 第十二部分:使用make更新函数库文件 ##### 一、函数库文件的成员 函数库文件通常包含多个目标文件,可以通过指定成员名来使用它们。 ##### 二、函数库成员的隐含规则 make支持自动构建和更新函数库文件的成员。 ##### 三、函数库文件 可以使用`ar`命令来创建和管理函数库文件。 通过以上详细介绍,我们可以看到Makefile不仅能够简化构建过程,还能通过使用变量、条件判断和函数等功能来增强灵活性和可维护性。掌握Makefile的基本用法对于任何从事软件开发的人来说都是非常有价值的技能。
剩余77页未读,继续阅读
- 粉丝: 3
- 资源: 22
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助