乐趣区

韦东山一期视频学习笔记Makefile学习

一、最简单的 Makefile

test : a.o b.o
    gcc -o test a.o b.o

a.o : a.c
    gcc -c -o a.o a.c

b.o : b.c
    gcc -c -o b.o b.c
  1. 要生成 test 依赖 a.o b.o
  2. a.o 生成依赖于 a.c

gcc -c -o a.o a.c

  1. b.o 生成依赖于 b.c

gcc -c -o b.o b.c

二、简单的 Makefile 语法

使用通配符

  • 可以匹配任意个 c 文件

$@:表示目标文件
$<:表示第一个依赖文件
$^:表示 所有的 依赖文件

test : a.o b.o
    gcc -o test $^

%.o : %.c
    gcc -c -o $@ $<

清除文件

test : a.o b.o
    gcc -o test $^

%.o : %.c
    gcc -c -o $@ $<

clean:
    rm *.o test
.PHONY: clean

make clean:指定执行 clean,不指定默认执行第一个目标
.PHONY:不加的话如果有同名目标文件就无法执行

变量

A := xxx:A 的值即可确定
B = xxx:B 的值使用到时才确定
?=:延时变量,如果是第一次定义才有效,如果之前定义过则忽略
+=:附加,延时变量还是即时变量取决于前面
@:不显示命令本身
make D=1234:给变量传递值

A := $(C)
B = $(C)
#C = abc
D = first
D ?= Second

all:
    @echo $(A)
    @echo $(B)
    @echo $(D)
C = abc
输出
root@ubuntu_armv4:~/mini2440_v2/makefile# make
root@ubuntu_armv4:~/mini2440_v2/makefile# make

abc
first
  • 可以看出 A 为空,B 为 abc
  • C 的前后顺序没有影响
  • ?= 第一次定义才有效

函数

$(foreach var,list,text):遍历 list,每个值为 var

A = a b c
B = $(foreach f, $(A), $(f).o)

all:
    @echo B = $(B)

输出:B = a.o b.o c.o


$(filter pattern...,text):在 text 中选出匹配 pattern 的项
$(filter-out pattern...,text):在 text 中选出除了匹配 pattern 的项

C = a b c d/
D = $(filter %/, $(C))
E = $(filter-out %/, $(C))

all:
    @echo $(D)
    @echo $(E)
root@ubuntu_armv4:~/mini2440_v2/makefile# make
d/
a b c

$(wildcard pattern...):寻找当前目录下符合 pattern 的文件

files = $(wildcard *.c)

files2 = a.c b.c e.c g.c
files3 = $(wildcard $(files2))
all:
    @echo files = $(files)
    @echo files3 = $(files3)
输出
files = a.c b.c
files3 = a.c b.c

file3= 从 file2 中选出当前目录存在的文件


$(patsubst pattern,replacement,text):在 text 中符合 pattern 的值替换成 replacement

files = a.c b.c e.c g.c
dep_files = $(patsubst %.c, %.d, $(files))

all:
    @echo dep_files = $(dep_files)

输出dep_files = a.d b.d e.d g.d

三、Makefile 实例分析

gcc -M c.c:可以看到 c.c 的依赖

# 输出
root@ubuntu_armv4:~/mini2440_v2/makefile# gcc -M c.c
c.o: c.c /usr/include/stdc-predef.h /usr/include/stdio.h \
 /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \
 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
 /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h \
 /usr/include/x86_64-linux-gnu/bits/types.h \
 /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \
 /usr/include/_G_config.h /usr/include/wchar.h \
 /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \
 /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
 /usr/include/x86_64-linux-gnu/bits/sys_errlist.h c.h

gcc -M -MF c.d c.c:把 c.c 的依赖写入 c.d
gcc -c -o c.o c.c -MD -MF c.d:把 c.c 的依赖写入 c.d 同时编译 c.c
CFLAGS = -Werror:编译选项,把所有警告当作错误
CFLAGS = -Iinclude:指定当前目录 include 文件夹为编译器默认头文件目录
代码

objs = a.o b.o c.o

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

dep_files := $(wildcard $(dep_files))

CFLAGS = -Werror -Iinclude

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

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

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

clean:
    rm *.o test

distclean:
    rm $(dep_files)

.PHONY: clean
退出移动版