1. gcc编译器

1.1. 常用选项

选项 说明
-E 预处理,开发过程中想快速确定某个宏可以使用“-E -dM”
-c 把预处理、编译、汇编都做了,但是不链接
-o 指定输出文件
-I 指定头文件目录
-L 指定链接时库文件目录
-l 指定链接哪一个库文件

1.2. 很有用的选项

gcc -E main.c # 查看预处理结果,比如头文件是哪个
gcc -E -dM main.c > 1.txt # 把所有的宏展开,存在 1.txt 里
gcc -Wp,-MD,abc.dep -c -o main.o main.c # 生成依赖文件 abc.dep,后面 Makefile 会用
echo 'main(){}'| gcc -E -v - # 它会列出头文件目录、库目录(LIBRARY_PATH)

2. MakeFile

2.1. 基本格式

目标(target)...: 依赖(prerequiries)...
    <tab>命令(command)

2.2. 常用语法

2.2.1. 通配符

通配符 说明
% 文件名
$@ 表示目标
$< 表示第一个依赖
$^ 表示所有依赖

2.2.2. PHONY 假想目标

假想目标,make时不会去判断目标文件是否存在

eg:

test: a.o b.o c.o
    gcc -o $@ $^
%.o: %.c
    gcc -c -o $<

clean:
    rm *.o test

.PHONY: clean

2.2.3. 变量赋值

语法 说明
:= 即时变量,变量值即可确定
= 延时变量,变量值在试用时确定
?= 延时变量,如果变量值在前面已经定义则不生效
+= 附加,即时or延时取决于前面变量的定义

2.3. 函数

2.3.1. $(foreach var, list, text)

list 中的每一个元素,取出来赋给 var,然后把 var 改为 text 所描述的形式。

eg:

objs:=a.o b.o
dep_files:=$(foreach f, $(objs), .$(f).d) # dep_files = .a.o.d .b.o.d

2.3.2. $(wildcard pattern)

pattern 所列出的文件是否存在,把存在的文件都列出来。

eg:

src_files:=$(wildcard *.c) # src_files为当前目录下所有的c文件

2.3.3. $(filter patten..., text)

返回在text中由空格隔开且匹配格式pattern...的字,去除不符合格式pattern...的字。

$(filter-out patten..., text) 返回不匹配的字

eg:

A = a b c d/
B = $(filter %/, %(A))
C = $(filter-out %/, %(A))
all:
    @echo B = $(B)  # B = d/
    @echo C = $(C)  # C = a b c 

2.3.4. $(patsubst pattern,replacement,text)

寻找text中符合格式pattern的字,用replacement替换它们。patternreplacement中可以使用通配符。

eg:

A = a.c b.c c.h
B = $(patsubst %.c, %.o, $(A))
all:
    @echo B = %(B)  # B = a.o b.o c.h

2.4. 改进

2.4.1. 写入依赖

将c文件依赖的h文件写入makefile,防止h文件更新后make仍是最新版本

gcc -M main.c # 打印出依赖
gcc -M -MF main.d main.c # 把依赖写入文件mian.d
gcc -c -o main.o main.c -MD -MF main.d # 编译main.o,把依赖写入main.d

2.4.2. 添加CFLAGS

增加编译选项

选项 说明
-Werror 把警报转为错误,更严谨
-I[dir] 编译器寻找头文件的路径dir

2.5. 综合案例

要求: 多c文件,多h文件(单独放一个目录),参考文件树

2.5.1. 文件树

├── include
│   ├── a.h
│   └── b.h
├── a.c
├── b.c
├── main.c
└── Makefile

2.5.2. 代码

objs = main.o a.o b.o

dep_files := $(patsubst %, .%.d, $(objs))
dep_files := $(wildcard $(dep_files))

CFLAGS = -Werror -Iinclude

test: $(objs)
        gcc -o $@ $^

ifneq ($(dep_files),)
include $(dep_files)
endif

%.o : %.c
        gcc $(CFLAGS) -c -o $@ $< -MD -MF .$@.d

clean:
        rm *.o test $(dep_files)

.PHONY: clean