当前文件目录如下
├── 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
评论区