当前文件目录如下
├── includes
│   ├── a.h
│   └── b.h
├── lib
├── Makefile
└── src
    ├── a.c
    └── b.c
基本语法规则
目标:依赖
[tab]命令
目标:要生成的目标文件名
依赖:生成目标文件所依赖的文件名
[tab]键不能少,且必须为[tab],不能是空格
命令:生成目标文件要执行的命令
main:main.c
    gcc main.c -o main
上面的Makefile就等价于gcc main.c -o main,只需要执行make命令就可以。
赋值
=:使用赋值符“=”设置的变量,它的值在运行时才能确定,这称为“延时变量”。
PARA = 100
CURPARA = $(PARA)
PARA = ask
print:
    @echo $(CURPARA)
输出为:ask
:=:使用“:=”设置的变量被称为“即时变量”,在赋值时就确定了它的值。
PARA = 100
CURPARA := $(PARA)
PARA = ask
print:
    @echo $(CURPARA)
输出为:100
?=:使用“?=”给变量设置值时,如果这个变量之前没有被设置过,那么“?=”才会起效果;如果曾经设置过这个变量,那么“?=”不会起效果。
+=:需要给前面已经定义好的变量添加一些字符串进去,此时就要使用到符号“+=”
系统自带变量
- 
CC: C 编译器的名称,默认为 “cc”。
- 
CXX: C++ 编译器的名称,默认为 “g++”。
- 
CPP: C 预处理器的名称,默认为 “cc -E”。
- 
LD: 链接器的名称,默认为 “cc”。
- 
AR: 静态库归档工具的名称,默认为 “ar”。
- 
AS: 汇编器的名称,默认为 “as”。
- 
RM: 删除文件的命令,默认为 “rm -f”。
- 
CFLAGS: C 编译器的选项。优化选项: 通过设置 -O(或-O1、-O2、-O3等级)来控制代码的优化级别。更高的优化级别可能会使生成的可执行文件更高效,但也可能增加编译时间。警告选项: 使用 -Wall开启更多的警告信息,帮助发现潜在的代码问题。你也可以使用-Werror将警告视为错误。调试信息: 使用 -g选项添加调试信息,以便在调试时能够更容易地跟踪代码。宏定义: 使用 -D选项定义预处理宏。这对于在编译时为代码中插入条件编译非常有用。其他选项: 你可以根据需要添加其他编译选项,如指定头文件搜索路径 -I,链接库路径-L,链接库-l等。
- 
CXXFLAGS: C++ 编译器的选项。可选和CFLAGS类似C++ 标准: 使用 -std选项指定要使用的 C++ 标准版本。例如,-std=c++11表示使用 C++11 标准。
- 
LDFLAGS: 链接器的选项。库搜索路径: 使用 -L选项指定链接器搜索库文件的路径。这对于链接需要的库文件位于非标准路径的情况非常有用。库链接: 使用 -l选项指定要链接的库。例如,-lmylibrary将链接名为libmylibrary.so(或libmylibrary.a)的库。其他库链接选项: 你可以添加其他与库链接相关的选项,如 -static(静态链接)或-shared(共享库)。输出文件名: 使用 -o选项指定生成的可执行文件的名称。其他链接选项: 你可以添加其他与链接器相关的选项,如 -Wl,--export-dynamic。
- 
CPPFLAGS: C 预处理器的选项。头文件搜索路径: 使用 -I选项指定预处理器搜索头文件的路径。这对于包含不在标准路径中的头文件非常有用。宏定义: 使用 -D选项定义预处理宏。这对于在编译时为代码中插入条件编译非常有用。其他预处理器选项: 你可以添加其他与预处理器相关的选项,如 -E(只运行预处理器)。
- 
LIBS: 需要链接的库。链接标准库: 使用 -l选项指定要链接的标准库。例如,链接数学库可以使用-lm。链接自定义库: 使用 -l选项指定要链接的自定义库。指定库文件路径: 使用 -L选项指定链接器搜索库文件的路径。LIBS = -L/path/to/lib -lmylibrary
- 
SHELL: Shell 的名称,默认为 “/bin/sh”。
自动变量
- $@:规则中的目标
- $<:规则中的第一个依赖文件
- $^:规则中的所有依赖文件
规则模式
模式规则是在目标及依赖中使用%来匹配对应的文件
CC = gcc
OBJ = main.o add.o sub.o
output: $(OBJ)
    $(CC) -o $@ $^
%.o: %.c
    $(CC) -c $<
clean:
    rm $(OBJ) output
在上述例子之中,output依赖于$(OBJ),$(OBJ)又代表了main.o add.o sub.o,系统发现没有main.o add.o sub.o这三个.o文件,发现了Makefile中的%.o: %.c命令,执行了对应文件的编译。
伪目标
.PHONY: clean
clean:
    rm -f *.o my_program
.PHONY 是一个在 Makefile 中常见的用法,用于定义伪目标,防止与实际文件冲突。
常用函数
wildcard:用于查找指定目录下指定类型的文件
patsubst:用于匹配替换
foreach:用于遍历
subst:用于文本匹配替换
strip:去掉前导和结尾空格,并将中间的多个空格压缩为单个空格
findstring:用于字符串查找
filter:用于过滤出格式匹配的项
filter-out:函数 filter 的反函数,过滤出格式不匹配的项
sort:将输入列表按字母顺序排序,并去掉重复的项
dir:获取输入中每一个文件名的路径部分,文件名的路径部分包括从文件名的首字符到最后一个斜杠(含斜杠)之前的一切字符
notdir:获取输入列表中每一个文件名中除路径部分外一切字符(真正的文件名)
suffix:获取输入列表中每一个文件名的后缀
basename:获取输入列表中每一个文件名中除后缀外一切字符
addsuffix:为输入列表中的每个项添加后缀
addprefix:为输入列表中的每个项添加前缀
测试makefile
SRC = $(wildcard ./src/*.c)  
OBJ = $(patsubst %.c, %.o, $(SRC))
dirs := includes src
files := $(foreach dir,$(dirs),$(wildcard $(dir)/*))
print:
    @echo "SRC = $(SRC)"
    @echo "OBJ = $(OBJ)"
    @echo "files = $(files)"
    @echo "$(subst ee,EE,feet on the street)"
    @echo "$(strip  a   b   c  )"
    @echo "$(findstring a,a b c)"
    @echo "$(findstring a,b c)"
    @echo "$(filter %.c %.s,foo.c bar.c baz.s ugh.h)"
    @echo "$(filter-out %.c %.s,foo.c bar.c baz.s ugh.h)"
    @echo "$(sort foo bar lose baa)"
    @echo "$(dir $(SRC))"
    @echo "$(notdir $(SRC))"
    @echo "$(suffix src/foo.c src-1.0/bar.c hacks)"
    @echo "$(basename src/foo.c src-1.0/bar.c hacks)"
    @echo "$(addsuffix .c,foo bar)"
    @echo "$(addprefix src/,foo bar)"
输出
SRC = ./src/a.c ./src/b.c  
OBJ =  ./src/a.o  ./src/b.o
files = includes/a.h includes/b.h src/a.c src/b.c
fEEt on the strEEt
a b c
a
foo.c bar.c baz.s
ugh.h
baa bar foo lose
./src/ ./src/
a.c b.c
.c .c
src/foo src-1.0/bar hacks
foo.c bar.c
src/foo src/bar
makefile模板
VERSION = 1.0.0
SOURCE = $(wildcard ./src/*.c)
OBJECT = $(patsubst %.c, %.o, $(SOURCE))
INCLUEDS = -I ./includes
TARGET = test
CC = gcc
CFLAGS = -Wall -g
$(TARGET): $(OBJECT)
    @mkdir -p output/
    $(CC) $^ $(CFLAGES) -o output/$(TARGET)_$(VERSION)
%.o: %.c
    $(CC) $(INCLUEDS) $(CFLAGES) -c $< -o $@
.PHONY:clean
clean:
    @rm -rf $(OBJECT) output/
补充
gcc -M c.c            // 打印出依赖
gcc -M -MF c.d c.c            // 把依赖写入c.d
gcc -c -o c.o c.c -MD -MF c.d           // 编译c.o,把依赖写入c.d
-M: 只生成包含头文件依赖关系的 Makefile 规则,而不生成目标文件
-MD: 让 GCC 生成一个 Makefile 依赖关系文件
-MF c.d: 指定生成的依赖关系文件的名称为 c.d。
一般来说,-MD 和 -MF不是 CFLAGS 的一部分,而是作为额外的选项传递给编译器。在 Makefile 中,你可以将它们添加到相应的规则中,
CFLAGS = -Wall -O2
CC = gcc
%.o: %.c
    $(CC) -c -o $@ $< $(CFLAGS) -MD -MF $*.d
 
             
           
             
           
                        
评论区