Makefile的引入及规则
- 使用keil, mdk, avr等工具开发程序时点点鼠标就可以编译了,
它的内部机制是什么?它怎么组织管理程序?怎么决定编译哪一个文件?
其组织管理和内部机制也是Makefile - 对于gcc -o test a.c b.c看似简单的命令,其过程经历了预处理,编译,汇编和链接的过程,如果其中一个文件改变了,就会对所有文件都处理一次,文件多的时候如果只修改其中一个文件会导致效率低
- Makefile的核心—规则 :
目标 : 依赖1 依赖2 …
[TAB]命令 - 当"目标文件"不存在, 或某个依赖文件比目标文件"新",则: 执行"命令"
Makefile基本语法
- 通配符: %.o
$@ 表示目标
$< 表示第1个依赖文件
$^ 表示所有依赖文件
DEMO
test:a.o b.o c.o
gcc -o test $^
%.o:%.c
gcc -c -o $@ $<
- test依赖于a.o b.o c.o $ ^就代表了a.o b.o c.o,就会去下面检查有无新的变动,遇到通配符,把a代进去,若a.c比a.o新则重新执行,$ @为a.o,$<为a.c,而b和c同理
- 假想目标:.PHONY
DEMO
test:a.o b.o c.o
gcc -o test $^
%.o:%.c
gcc -c -o $@ $<
clean:
rm *.o test
.PHONY: clean
- 如果在目录中有clean文件的话,对于Makefile来说执行的条件是当"目标文件"不存在, 或某个依赖文件比目标文件"新",则: 执行"命令",如果没有".PHONY: clean"将clean认定的假想目标,则会显示clean为最新,不会执行clean命令
变量
- := #即时变量 在定义时即确定
- = #延时变量 使用到时才确定
- ?= #延时变量,如果第1次定义才奇效,如果在前面该变量已定义则忽略这句
- += #附加,它是即时变量还是延时变量取决于前面的定义
- 使用变量用格式:$(变量) 来访问
DEMO
A := $(C)
B = $(C)
C = abc
all:
@echo A = $(A) //@隐藏命令
@echo B = $(B)
C += 123
打印结果
A
B = abc 123
A := $(C)
B = $(C)
C = abc
#D = xiaoma
D ?= NB
all:
@echo A = $(A)
@echo B = $(B)
@echo C = $(C)
@echo D = $(D)
C += 123
打印结果
A =
B = abc 123
C = abc 123
D = NB
如果执行命令make D=xiaoma
打印结果
A =
B = abc 123
C = abc 123
D = xiaoma
Makefile函数
- a. $(foreach var,list, text)
- b. $(filter pattern. . ., text) #在text 中取出符合patten格式的值
$(filter-out pattern…, text) #在text中取出不符合patten格式的值 - C. $(wildcard pattern) #pattern定义了文件名的格式,
#wildcard取出其中存在的文件 - d. $ (patsubst pattern, replacement,$(var)) #从列表中取出每一个值
#如果符合pattern
#则替换为replacement
DEMO
A = a b c
B = $(foreach f, $(A), $(f).o)
C = a b c d/
D = $(filter %/, $(C))
E = $(filter-out %/, $(C))
files = $(wildcard *.c)
files2 = a.c b.c c.c d.c e.c abc
files3 = $(wildcard $(files2))
dep_files = $(patsubst %.c,%.d,$(files2))
all:
@echo B = $(B)
@echo D = $(D)
@echo E = $(E)
@echo files = $(files)
@echo files3 = $(files3)
@echo dep_files = $(dep_files)
打印效果
B = a.o b.o c.o
D = d/
E = a b c
files = a.c c.c demo1.c b.c
files3 = a.c b.c c.c
dep_files = a.d b.d c.d d.d e.d abc
对于.h的情况
test:a.o b.o c.o
gcc -o test $^
c.o : c.c c.h //对于.h文件 如果没有这一句 改变.h文件我们并不知道
//这里不能加入tab健不然相比会实现空命令,这里面c.o会在下面去找然后重新去生成
%.o:%.c
gcc -c -o $@ $<
clean:
rm *.o test
.PHONY: clean
- 在上述代码中 如果.o没有去依赖.h,当我们去改变.h的时候就需要去clean再make
- gcc -M c.c 查看依赖文件
guest-kpkiwy@book-virtual-machine:~/xiaoma$ 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
- gcc -M -MF c.d c.c 把这些依赖写入c.d
guest-kpkiwy@book-virtual-machine:~/xiaoma$ gcc -M -MF c.d c.c
guest-kpkiwy@book-virtual-machine:~/xiaoma$ cat c.d
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
- gcc -c -o c.o c.c -MD -MF c.d 即去编译c.c为c.o 又去把依赖写入文件c.d
DEMO
objs = a.o b.o c.o
dep_files := $(patsubst %,.%.d, $(objs))
dep_files := $(wildcard $(dep_files))
CFLAGS = -Werror -Iinclude //将警告转换为错误,有些警告包含错误 -I指定文件去查找
test:$(objs)
gcc -o test $^
# @echo dep_files = $(dep_files)
ifneq ($(dep_files),) //如果变量dep_files不为空的话 include就把变量包含进来
include $(dep_filesa)
endif
%.o:%.c
gcc $(CFLAGS) -c -o $@ $< -MD -MF .$@.d
clean:
rm *.o test
distclean:
rm $(dep_files)
.PHONY: clean