Makefile 1、入门

本文代码点击此处跳转
https://download.csdn.net/download/liangwenhao1108/12256912
https://github.com/WHaoL/study/tree/master/Makefile/Demo01

1. Makefile介绍

简介:
	当你启动make工具对工程进行编译时,make会自动读取Makefile中的编译规则,进行自动化编译
	make:是一个命令工具(是一个解释Makefile中指令的命令工具)-->构建工具
	Makefile:记录了编译规则                            -->构建工具需要加载的文件
学习目标:
	读懂别人写的Makefile
	自己独立写Makefile

2. Makefile中的规则

2.1 文件命名

文件命名--两种书写格式: (首字母大小写都可以)
	Makefile
	makefile
注释使用'#'

2.2 Makefile中的构建规则

# make的构建规则
目标 ... : 依赖 ... 
	命令		# 需要有一个tab缩进//规则中的命令
	...
//整体又可看作一个规则

# 目标: 最终要生成的文件, 一个或多个     -->通过命令生成
# 依赖: 生成目标需要使用的文件,一个或多个 -->在命令中被使用 
# 命令: 一个或多个gcc命令, 通过对依赖进行编译生成目标

2.3 make的工作原理

Makefile文件中有多个规则
	1、直接执行:make
		执行make命令,生成的是第一条规则的目标,其他规则都是辅助性的
	2、输入:make 子目标名字
		生成的是子目标

1、命令在执行之前会检测依赖是否存在
	1、如果依赖不存在: 
   		make会向下检测其他的规则, 看有没有一条规则是用来生成这个依赖的
    	如果找到了这个规则, 执行规则中的命令, 得到了需要的依赖
	2、依赖存在就不向下检测了

2、关于文件更新 -> 不适用于伪目标
执行make命令时, 规则中的依赖和目标,这些文件会进行一个文件时间早晚的比较
    1、如果目标文件不存在
	    目标文件被生成 -> 执行对应的命令
	2、目标存在时
    	1.如果依赖时间早, 目标时间晚 -> 正常
      		目标不需要重写更新, 不需要生成, 使用旧的就可以
    	2.依赖时间晚, 目标的时间早 -> 不正常
      		说明依赖被重新修改  -> 目标需要重新生成
        	对应的命令就被执行了

2.4 Makefile中的变量(提高Makefile的编写效率)

# 没有类型,默认按照字符串处理

1、自定义变量,变量名小写
	# 规则: 变量名=变量值
	# 举例:var=a.c b.c c.c
	# 取变量的值: $(变量名)
		
2、默认的自带变量,内部变量, 变量名大写
		如: CC等价于gcc
	# 取值: var=$(CC)
	
	CC = gcc #arm-linux-gcc
	CPPFLAGS : C预处理的选项如:-I
	CFLAGS: C编译器的选项–Wall –g -c
	LDFLAGS : 链接器选项–L –l
		%.o:%.c
		$(CC) –c $(CFLAGS) $(CPPFLAGS) $< -o $@



	
3、自动变量,只能在'规则中的命令中'使用
		$@: 规则中的目标
		$<: 规则中的第一个依赖
		$^: 规则中的所有的依赖
		
	# 例子
		app:a.o b.o c.o
			gcc a.o b.o c.o -o app
	# 改进
		app:a.o b.o c.o
			gcc $^ -o $@

2.5 Makefile中的模式匹配

# 语法
%.o:%.c
	gcc -c $< -o $@
%: 通配符, 前后对应的是同一字符串

2.6 Makefile中的函数

makefile中所有的函数都是有返回值的, 因此所有函数的样式:
'$(函数名 参数1, 参数2, 参数3, ...)'

1、wildcard:获取指定目录下指定类型的文件列表
	'$(wildcard PATTERN...)'
	功能:
		PATTERN 指的是某个或多个目录下的对应的某种类型的文件
		如果有多个目录,一般使用空格间隔
	返回值:
	  	得到的若干个文件的文件列表, 文件名之间以空格间隔
	示例:
		'$(wildcard  *.c , ./sub/*.c)'
		* :代表的是任意字符串
	  	返回值格式: a.c b.c c.c d.c e.c f.c ./sub/aa.c ./sub/bb.c

2、patsubst:模式字符串替换函数
	$(patsubst <pattern>,<replacement>,<text>)
		pattern:当前的字符串类型
		replacement:替换后的字符串类型
		text:src字符串
	功能:
 	 	查找<text>中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式<pattern>,如果匹配的话,则以<replacement>替换。
  		这里,<pattern>可以包括通配符`%`,表示任意长度的字串。如果<replacement>中也包含`%`,那么,<replacement>中的这个`%`将是<pattern>中的那个`%`所代表的字串。(可以用“\”来转义,以`\%`来表示真实含义的`%`字符)
	返回值:
  		函数返回被替换过后的字符串。
	示例: `$(patsubst %.c, %.o, x.c.c bar.c)` 
  		把字串“x.c.c bar.c”符合模式[%.c]的单词替换成[%.o]
  		返回结果是“x.c.o bar.o”
	
	举例: 
		第一参数的% 通配符 和第二个参数的 % 对应, 代表的是同一个字符串
		(patsubst %.c, %.o, a.c b.c d.c e.c)
	# 得到的返回值:
		a.o b.o d.o e.o

2.7 伪目标

语法:
	.PHONY:伪目标文件的名字
	
#声明为伪目标时,这个目标在磁盘上不生成实体,
#也就不会进行 目标依赖存在与否、目标依赖时间对比 等一些操作了,
#因此也就不会和磁盘上已经存在文件产生冲突
#在命令前加'-',如果碰到错误会继续执行下面的指令,并不会中断执行
#'-f' 强制执行命令,不会提示
.PHONY:clean
clean:
	-rm $(obj) $(target) -f

clean命令中的特殊符号:
	'-'此条命令出错,make也会继续执行后续的命令。如:-rm main.o”

2.8 make命令的使用

make 默认执行第一个出现的目标,可通过make dest指定要执行的目标
make -C 指定目录: 进入指定目录,调用里面的Makefile
make -n :只打印要执行的命令,不会真正执行命令
make -p :显示隐含规则数据库中的信息
make -f :-f执行一个makefile文件名称,使用make -f 强制执行指定的makefile

3 Makefile例子

$ gcc a.c b.c c.c -o app
# 改成一个规则

###################### 版本1 #################
app:a.c b.c c.c 
	gcc a.c b.c c.c -o app
总结:
	当只更新了一个源文件时,却需要重新编译所有的源文件,比较耗时,效率低
改进措施: 
	将这个唯一的规则拆分为若干个
	
###################### 版本2 #################
app:a.o b.o c.o
	gcc a.o b.o c.o -o app
a.o:a.c
	gcc -c a.c
b.o:b.c
	gcc -c b.c
c.o:c.c
	gcc -c c.c
总结:
	改掉了版本1的弊端,却不适合源文件非常多的那种工程(只适合小工程),
	只适合源文件较少的情况,太冗余
	因为每个源文件都需要书写一个规则与之对应,这样导致Makefile书写起来比较冗长
改进措施: 
	使用变量进行精简
	
###################### 版本3 #################
使用:
	Makefile中的变量和模式匹配进行改进
	
target=app
obj=add.o sub.o mult.o div.o main.o

$(target):$(obj)
	gcc $(obj) -o $(target)

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

缺点:如果源文件比较多,在写obj(.o文件)时比较麻烦
改进:自动搜索指定目录下的源文件(.c文件),将.c-->.o文件
     使用Makefile中的函数

###################### 版本4 #################
target=app
#搜索指定目录下的指定格式的文件.c
#得到.c文件列表
'src=$(wildcard ./*.c)'
#将得到的文件列表中文件的后缀.c->.o
'obj=$(patsubst %.c,%.o,$(src))'
$(target):$(obj)
	gcc $(obj) -o $(target)
%.o:%.c
	gcc -c $< -o $@
缺点:
	功能不完善,只能编译代码,不能删除生成的中间文件
改进:
	添加一个删除文件的规则

###################### 版本5 #################
target=app

#搜索指定目录下的指定格式的文件 .c
#得到.c文件列表
'src=$(wildcard ./*.c)'
#将得到的文件列表中文件的后缀.c->.o
obj=$(patsubst %.c,%.o,$(src))
$(target):$(obj)
	gcc $(obj) -o $(target)
%.o:%.c
	gcc -c $< -o $@

#在命令前加'-',如果碰到错误会继续执行下面的指令,并不会中断执行
#'-f' 强制执行命令,不会提示
.PHONY:clean
clean:
	-rm $(obj) $(target) -f 
###################### 版本6 #################
CC=gcc
CFlagesDebug=-g -w -ggdb -std=c11 -c

CXX=g++
CxxFlagesDebug=-g -w -ggdb -std=c++11 -fshort-wchar -c
#默认情况下,windows 下的 wchar_t 占两个字节的长度,而 linux 下的 wchar_t 占四个字节的长度,
#可以在使用 gcc/g++ 编译程序的时候再后面跟上 -fshort-wchar 来解决这个问题。

target=execute
src=$(wildcard *.c)
obj=$(src:.c=.o)
$(target):$(obj)
	$(CC) -o $(target) $(obj)
%.o:%.c
	$(CC) -MM $^ 
	$(CC) $(CFlagesDebug) $^ -o $@
#'-M' : 自动找寻源文件中包含的头文件(.h文件),并生成一个依赖关系
#GNU的C/C++编译器,你得用“-MM”参数,不然,“-M”参数会把一些标准库的头文件也包含进来
#此处:$(CC) -MM $^,就是先为*.c找到需要的*.h文件,并建立完整的依赖关系
#如 gcc -MM main.c -->输出为:main.o:main.c main.h

#清除:.o
.PHONY:DotObjs
DotObjs:
	-rm -f $(obj) 
#清除:可执行文件
.PHONY:DotExecute
DotExecute:
	-rm -f $(target) 
#清除:.o、可执行文件
.PHONY:clean
clean:DotObjs DotExecute #执行顺序依次为1.DotObjs的命令、2.DotExecute的命令、3.clean的命令


#如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令
.PHONY:cdpwd1
cdpwd1:
	cd ../
	pwd

.PHONY:cdpwd2
cdpwd2:
	cd ../;pwd


# call函数代码测试如下
#reverse=$(1) $(2)	#输出 a b  分别拿到第1个参数、第2个参数
reverse=$(2) $(1) 	#输出 a b  分别拿到第2个参数、第1个参数
foo=$(call reverse ,a,b)

.PHONY:testfoo
testfoo:
	@echo $(foo)
###################### 版本6 #################
CC=gcc
CFlagesDebug=-g -w -ggdb -std=c11 -c

CXX=g++
CxxFlagesDebug=-g -w -ggdb -std=c++11 -fshort-wchar -c

Project=execute
src=$(wildcard *.c)
obj=$(src:.c=.o)
$(Project):$(obj)
	$(CC) -o $(Project) $(obj)

%.o:%.c
	$(CC) -MM $^ 
	$(CC) $(CxxFlagesDebug) $^ -o $@

#清除:.o
.PHONY:DotObjs
DotObjs:
	-rm -f $(obj) 
#清除:可执行文件
.PHONY:DotExecute
DotExecute:
	-rm -f $(Project) 
#清除:.o、可执行文件
.PHONY:clean
clean:DotObjs DotExecute





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值