企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[TOC] > [参考网站](http://www.ruanyifeng.com/blog/2015/02/make.html) ## 语法 ### Makefile文件的格式 ``` <target> : <prerequisites> [tab] <commands> target : 目标,可以是文件或者伪文件(必须) prerequisites: 前置条件 tab :第二行 tab 起首 commands: 需要执行的命令 ``` ### 目标(target) 目标可以是一个文件名,也可以是多个文件名,之间用空格分隔 也可以是伪文件,为了被检测到有文件生成,PHONY ``` .PHONY: clean clean: rm *.o ``` Make命令运行时没有指定目标,默认会执行Makefile文件的第一个目标 ### 前置条件(prerequisites) * 前置条件通常是一组文件名,之间用空格分隔 * 只要有一个前置文件不存在,或者有过更新(前置文件的last-modification时间戳比目标的时间戳新),"目标"就需要重新构建 ``` result.txt: source.txt cp source.txt result.txt ``` 如果 source.txt 不存在,则需要先创建source.txt ### 命令(commands) 命令(commands)表示如何更新目标文件,由一行或多行的Shell命令组成。 它是构建"目标"的具体指令,它的运行结果通常就是生成目标文件 tab键可以`.RECIPEPREFIX`替换 ``` .RECIPEPREFIX = > all: > echo Hello, world ``` 每行命令在一个单独的shell中执行,这些Shell之间没有继承关系 如: ``` var-lost: export foo=bar echo "foo=[$$foo]" //make var-lost,取不到foo的值 ``` 可以有三个方法取得 foo 方法一: ``` var-kept: export foo=bar; echo "foo=[$$foo]" ``` 方法二: ``` var-kept: export foo=bar; \ echo "foo=[$$foo]" ``` 方法三: ``` .ONESHELL: var-kept: export foo=bar; echo "foo=[$$foo]" ``` ### Makefile文件的语法 #### 注释使用`#` #### 回声(echoing) ``` test: # 这是测试 ``` 执行 ``` $ make test # 这是测试 ``` 在命令的前面加上@,就可以关闭回声。 ``` test: @# 这是测试 ``` 现在再执行`make test`,就不会有任何输出 #### 通配符 Makefile 的通配符与 Bash 一致. 主要有星号(*)、问号(?)和 [...] 。比如, `*.o` 表示所有后缀名为o的文件 ``` clean: rm -f *.o ``` #### 模式匹配 主要用到的匹配符是% `%.o: %.c` 等同于下面的写法。 ``` f1.o: f1.c f2.o: f2.c ``` #### 变量和赋值符 Makefile 允许使用等号自定义变量。 设置 makefile 的变量 ``` txt = Hello World test: @echo $(txt) ``` 获取 bash 的变量需要 两个 `$$` ``` test: @echo $$HOME ``` ``` make test /home/ant ``` 变量赋值 ``` VARIABLE = value # 在执行时扩展,允许递归扩展。 VARIABLE := value # 在定义时扩展。 VARIABLE ?= value # 只有在该变量为空时才设置值。 VARIABLE += value # 将值追加到变量的尾端。 ``` #### 内置变量(Implicit Variables) Make命令提供一系列内置变量 比如,`$(CC)` 指向当前使用的编译器,`$(MAKE)` 指向当前使用的Make工具 ``` output: $(CC) -o output input.c ``` #### 自动变量(Automatic Variables) 1. `$@` 指代当前目标,可指代多个目标 ``` a.txt b.txt: touch $@ ``` 等于 ``` a.txt: touch a.txt b.txt: touch b.txt ``` 2. `$<` 指代第一个前置条件 3. `$?` 指代比目标更新的所有前置条件,之间以空格分隔。比如,规则为 t: p1 p2,其中 p2 的时间戳比 t 新,$?就指代p2。 4. `$^` 指代所有前置条件,之间以空格分隔。比如,规则为 t: p1 p2,那么 $^ 就指代 p1 p2 。 5. `$*`指代匹配符 % 匹配的部分, 比如% 匹配 f1.txt 中的f1 ,$* 就表示 f1。 6. `$(@D)` 和 `$(@F)` $(@D) 和 $(@F) 分别指向 $@ 的目录名和文件名。比如,$@是 src/input.c,那么$(@D) 的值为 src ,$(@F) 的值为 input.c。 7. `$(<D)` 和 `$(<F)`分别指向 $< 的目录名和文件名。 #### 判断和循环 使用 Bash 语法,完成判断和循环 ``` ifeq ($(CC),gcc) libs=$(libs_for_gcc) else libs=$(normal_libs) endif ``` ##### 函数 ``` $(function arguments) # 或者 ${function arguments} ``` 几个常用的内置函数 1. shell 函数用来执行 shell 命令 `srcfiles := $(shell echo src/{00..99}.txt)` 2. wildcard 函数用来在 Makefile 中,替换 Bash 的通配符。 `srcfiles := $(wildcard src/*.txt)` 3. subst 函数用来文本替换 `$(subst from,to,text)` eg: `$(subst ee,EE,feet on the street) // fEEt on the strEEt` 4. 替换后缀名 变量名 + 冒号 + 后缀名替换规则。它实际上patsubst函数的一种简写形式。 `min: $(OUTPUT:.js=.min.js)` ## Makefile 的实例 #### 执行多个目标 ``` .PHONY: cleanall cleanobj cleandiff cleanall : cleanobj cleandiff rm program cleanobj : rm *.o cleandiff : rm *.diff ``` 上面代码可以调用不同目标,删除不同后缀名的文件,也可以调用一个目标(cleanall),删除所有指定类型的文件 #### 编译C语言项目 ``` edit : main.o kbd.o command.o display.o cc -o edit main.o kbd.o command.o display.o main.o : main.c defs.h cc -c main.c kbd.o : kbd.c defs.h command.h cc -c kbd.c command.o : command.c defs.h command.h cc -c command.c display.o : display.c defs.h cc -c display.c clean : rm edit main.o kbd.o command.o display.o .PHONY: edit clean ```