Makefile规则以及函数

本文详细介绍了Makefile在软件开发中的作用,如何通过规则组织编译流程,依赖管理以及使用变量、函数和通配符提高效率。重点讲解了预处理、编译、汇编和链接过程,以及如何处理.h文件的更新和依赖文件的检测。
摘要由CSDN通过智能技术生成

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
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值