### 如何书写Makefile #### 概述 Makefile 是一种用于自动化构建过程的脚本文件,被广泛应用于软件开发领域。它可以帮助开发者自动化完成源代码到可执行文件的编译与链接工作,大大提高了软件项目的构建效率。本文将详细介绍如何编写有效的 Makefile 文件。 #### 关于程序的编译与链接 在程序开发过程中,源代码文件通常需要经过编译器处理转换为机器语言(编译),然后将多个目标文件连接起来形成最终的可执行文件(链接)。Makefile 可以根据不同的目标文件自动执行这一系列任务。 #### Makefile介绍 Makefile 的核心功能在于定义一系列规则,这些规则指导 make 工具如何编译源代码、如何链接目标文件等。 1. **Makefile的规则** - 规则由目标文件、依赖文件以及构建命令组成。 - 规则格式:`target: prerequisites \n command` 2. **示例** ```makefile all: prog1 prog2 prog1: prog1.o gcc -o prog1 prog1.o prog2: prog2.o gcc -o prog2 prog2.o ``` 3. **make是如何工作的** - 当运行 `make` 命令时,make 会读取 Makefile 文件并分析其中定义的规则。 - make 会根据文件的修改时间来确定哪些文件需要重新编译。 - make 会按照定义的规则执行相应的命令。 4. **makefile中使用变量** - 变量可以存储文件名、命令或其他值。 - 示例:`CC=gcc` - 使用:`$(CC) -c file.c` 5. **让make自动推导** - make 支持自动推导目标文件的依赖关系。 - 例如,如果目标文件为 `prog.o`,那么 make 会默认查找 `prog.c` 或 `prog.cpp` 等源文件。 6. **另类风格的makefile** - 使用模式规则和通配符可以简化 Makefile 文件。 - 示例: ```makefile %.o: %.c $(CC) -c $< -o $@ ``` 7. **清空目标文件的规则** - 可以定义一个名为 `clean` 的规则来删除所有目标文件。 ```makefile clean: rm -f *.o prog1 prog2 ``` #### Makefile总述 1. **Makefile里有什么?** - 显式规则:明确指定目标文件及其依赖文件。 - 隐晦规则:make 自动识别并处理的规则。 - 变量的定义:用于存储常用的路径、文件名等。 - 文件指示:如包含其他 Makefile 文件。 - 注释:以 `#` 开头的行。 2. **Makefile的文件名** - 默认情况下,make 会寻找名为 `Makefile` 或 `makefile` 的文件。 3. **引用其它的Makefile** - 可以使用 `include` 指令来引入其他 Makefile 文件。 - 示例:`include common.mk` 4. **环境变量MAKEFILES** - MAKEFILES 环境变量可以用来指定额外的 Makefile 文件位置。 5. **make的工作方式** - make 通过分析 Makefile 中定义的目标文件和依赖关系来确定需要执行的操作。 #### 书写规则 1. **规则举例** - 规则可以指定目标文件、依赖文件及构建命令。 ```makefile prog: prog.o gcc -o prog prog.o ``` 2. **规则的语法** - 目标文件后面跟一个冒号,接着是依赖文件列表,最后是制表符后跟随构建命令。 3. **在规则中使用通配符** - 通配符 `%` 和 `*` 可以用于匹配文件名模式。 - 示例: ```makefile %.o: %.c $(CC) -c $< -o $@ ``` 4. **文件搜寻** - make 可以根据指定的目录列表来查找依赖文件。 - 使用 `VPATH` 变量来定义这些目录。 5. **伪目标** - 伪目标没有实际对应的文件,通常用于执行清理操作或启动特定的构建过程。 - 示例:`clean`、`install` 等。 6. **多目标** - 一个规则可以有多个目标文件。 - 示例: ```makefile all: prog1 prog2 ``` 7. **静态模式** - 静态模式规则允许使用通配符 `%` 来匹配一组相似的目标文件。 - 示例: ```makefile %.o: %.c $(CC) -c $< -o $@ ``` 8. **自动生成依赖性** - 使用 `-M` 选项或 `.DEPFILE` 变量可以生成依赖文件。 - 示例: ```makefile .DEPFILE: .d/$(shell basename $@ .o).d ``` #### 书写命令 1. **显示命令** - 使用 `-n` 或 `--just-print` 选项可以让 make 显示将要执行的命令但不实际执行。 2. **命令执行** - make 会依次执行每个规则下的命令。 3. **命令出错** - 如果命令执行失败,make 会停止执行后续的命令,并返回错误码。 4. **嵌套执行make** - 在 Makefile 中调用 `make` 命令可以实现递归构建。 - 示例:`make -C subdir` 5. **定义命令包** - 使用 `$(shell)` 函数可以在 Makefile 中执行 shell 命令并获取其输出。 #### 使用变量 1. **变量的基础** - 变量用于存储文件名、命令或其他值。 - 定义:`VARNAME=value` - 使用:`$(VARNAME)` 2. **变量中的变量** - 变量可以嵌套使用。 - 示例:`CC=$(CC_BASE)gcc` 3. **变量高级用法** - 使用 `$(filter)`、`$(patsubst)` 等函数可以进行更复杂的字符串处理。 4. **追加变量值** - 使用 `+=` 运算符可以追加变量值。 - 示例:`LIBS += -lm` 5. **override指示符** - 使用 `.PHONY` 指示符可以标记一个伪目标。 6. **多行变量** - 变量可以跨越多行定义。 - 示例:`VARNAME = value1\nvalue2` 7. **环境变量** - 使用 `$(ENV_VAR)` 可以引用环境变量。 8. **目标变量** - 目标变量与特定目标文件关联。 - 示例:`.ONESHELL:` - 在 `.ONESHELL` 下定义的命令将在同一 shell 中执行。 9. **模式变量** - 模式变量与模式规则结合使用。 - 示例:`%.o: %.c` #### 使用条件判断 1. **示例** - 使用 `ifeq`、`ifdef` 等条件语句可以基于变量值或存在性执行不同的操作。 - 示例: ```makefile ifeq ($(OS),Windows_NT) SHELL = cmd.exe endif ``` 2. **语法** - 条件判断的语法格式为: ```makefile ifeq (condition, true-block, false-block) ``` #### 使用函数 1. **函数的调用语法** - 函数调用的基本格式为 `$(function arguments)`。 2. **字符串处理函数** - 提供了多种用于字符串操作的函数。 - 示例: ```makefile SUBST := $(subst a,b,$(wildcard a*)) PATSUBST := $(patsubst %.c,%.o,$(wildcard *.c)) STRIP := $(strip hello world) FINDSTRING := $(findstring a,hello world) FILTER := $(filter %.c,$(wildcard *.c)) FILTER_OUT := $(filter-out %.o,$(wildcard *.o)) SORT := $(sort a b c d e f g h i j k l m n o p q r s t u v w x y z) WORD := $(word 3, a b c d e f g) WORDLIST := $(wordlist 2,4, a b c d e f g) WORDS := $(words a b c d e f g) FIRSTWORD := $(firstword a b c d e f g) ``` 3. **文件名操作函数** - `dir`、`notdir`、`suffix` 等函数可以用于处理文件名。 - 示例: ```makefile DIR := $(dir /home/user/project) NOTDIR := $(notdir /home/user/project) SUFFIX := $(suffix filename.txt) BASENAME := $(basename filename.txt) ADDSUFFIX := $(addsuffix .txt, filename) ADDPREFIX := $(addprefix /usr/bin/, $(notdir $(wildcard /usr/bin/*))) JOIN := $(join $(words a b c) $(words 1 2 3)) ``` 4. **foreach函数** - `foreach` 函数可以遍历列表。 - 示例: ```makefile FOREACH := $(foreach item,$(wildcard *.c),$(patsubst %.c,%.o,$(item))) ``` 5. **if函数** - `if` 函数可以基于条件执行不同操作。 - 示例: ```makefile IF := $(if $(filter %.c,$(wildcard *.c)),true,false) ``` 6. **call函数** - `call` 函数可以调用其他函数。 - 示例: ```makefile CALL := $(call $(word 1, $(subst :, , $(VARIABLE)))) ``` 7. **origin函数** - `origin` 函数可以确定变量的来源。 - 示例: ```makefile ORIGIN := $(origin VARS) ``` - `undefined`: 变量未定义。 - `default`: 变量由默认规则定义。 - `file`: 变量由文件定义。 - `commandline`: 变量由命令行参数定义。 - `override`: 变量被 `override` 指令覆盖。 - `automatic`: 变量为自动变量。 8. **shell函数** - `shell` 函数可以在 make 运行时执行 shell 命令。 - 示例: ```makefile SHELL := $(shell echo "Hello, World!") ``` 9. **控制make的函数** - `error` 函数用于输出错误消息并终止 make 运行。 - 示例: ```makefile ERROR := $(error "Error message") ``` - `warning` 函数用于输出警告消息但不会终止 make 运行。 - 示例: ```makefile WARNING := $(warning "Warning message") ``` #### make的运行 1. **make的退出码** - make 会在运行结束后返回一个退出码。 - 成功:0 - 失败:非零值 2. **指定Makefile** - 可以通过 `-f` 或 `--file` 选项指定 Makefile 文件的位置。 3. **指定目标** - 默认情况下,make 会查找名为 `all` 的目标。 - 可以通过命令行参数指定其他目标。 4. **检查规则** - 使用 `-n` 或 `--just-print` 选项可以让 make 显示将要执行的命令但不实际执行。 5. **make的参数** - 除了指定 Makefile 和目标外,还可以传递其他参数。 - 示例:`make VERBOSE=1` #### 隐含规则 1. **使用隐含规则** - make 支持一组预定义的隐含规则,用于处理常见的编译和链接任务。 - 示例:编译 C 程序、链接对象文件等。 2. **隐含规则一览** - make 支持多种类型的隐含规则,包括但不限于: - 编译 C 程序:`*.o` 从 `*.c` 生成。 - 编译 C++ 程序:`*.o` 从 `*.cpp` 生成。 - 编译 Pascal 程序:`*.o` 从 `*.pas` 生成。 - 编译 Fortran/Ratfor 程序:`*.o` 从 `*.f` 生成。 - 预处理 Fortran/Ratfor 程序:`*.f` 从 `*.F` 生成。 - 编译 Modula-2 程序:`*.o` 从 `*.mod` 生成。 - 汇编和汇编预处理:`*.o` 从 `*.s` 或 `*.S` 生成。 - 链接 Object 文件:`a.out` 从多个 `.o` 文件生成。 - Yacc C 程序:`y.tab.c` 从 `y.y` 生成。 - Lex C 程序:`lex.yy.c` 从 `lex.l` 生成。 - Lex Ratfor 程序:`lex.yy.f` 从 `lex.l` 生成。 - 从 C 程序、Yacc 文件或 Lex 文件创建 Lint 库:`lint.a` 从 `*.c`、`y.y` 或 `lex.l` 生成。 3. **隐含规则使用的变量** - 隐含规则支持使用特定变量来定制编译和链接行为。 - 示例:`CFLAGS`、`LDFLAGS` 等。 4. **隐含规则链** - make 会尝试使用多个隐含规则来构建一个目标文件。 - 示例:`a.o` 可能需要先从 `a.s` 构建,再从 `a.S` 构建。 5. **定义模式规则** - 模式规则使用通配符 `%` 来匹配一组文件。 - 示例: ```makefile %.o: %.c $(CC) -c $< -o $@ ``` 6. **老式风格的"后缀规则"** - 后缀规则使用文件扩展名来匹配源文件和目标文件。 - 示例: ```makefile .c.o: $(CC) -c $< -o $@ ``` 7. **隐含规则搜索算法** - make 使用特定的算法来决定何时应用隐含规则。 - 通常,make 会首先尝试找到显式规则,如果没有找到,则尝试使用隐含规则。 #### 使用make更新函数库文件 1. **函数库文件的成员** - 函数库文件通常包含多个目标文件。 - 可以使用 `ar` 工具来管理这些目标文件。 2. **函数库成员的隐含规则** - make 提供了一组隐含规则来处理函数库文件。 - 示例:创建新的函数库文件或更新已有的文件。 3. **函数库文件** - 函数库文件是包含多个目标文件的存档文件。 - 可以使用 `ar` 和 `ranlib` 工具来创建和维护函数库文件。
- 粉丝: 0
- 资源: 2
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- (源码)基于ArcEngine的GIS数据处理系统.zip
- (源码)基于JavaFX和MySQL的医院挂号管理系统.zip
- (源码)基于IdentityServer4和Finbuckle.MultiTenant的多租户身份认证系统.zip
- (源码)基于Spring Boot和Vue3+ElementPlus的后台管理系统.zip
- (源码)基于C++和Qt框架的dearoot配置管理系统.zip
- (源码)基于 .NET 和 EasyHook 的虚拟文件系统.zip
- (源码)基于Python的金融文档智能分析系统.zip
- (源码)基于Java的医药管理系统.zip
- (源码)基于Java和MySQL的学生信息管理系统.zip
- (源码)基于ASP.NET Core的零售供应链管理系统.zip