二、UNIX-LINUX---Makefile笔记一(3-4)

3.Makefile的书写规则

  • 总述:规则包含 依赖关系 和生成目标的方法 两部分
  • 若第一条规则的目标很多个,则第一个目标会成为make最终的目标

3.1规则举例

foo.o: foo.c defs.h #foo模块
	gcc -c -g foo.c
  • foo.o文件依赖于 foo.c 和 defs.h ,若foo.c 或defs.h文件日期比foo.c 新,或者foo.o 不存在,则依赖关系产生
  • gcc -c -g foo.c 告诉了make 怎么生成 foo.o ,foo.c里include了defs.h
    3.2 规则的语法
  • 格式
target : prerequisites (推荐写法)
	command
或
target : prerequisites ; command
	command

3.3规则总使用通配符

  • 通配符 : “ * ”, “ ? ” ,“ […] ”

  • “ ~ ” 在文件名中有特殊的用途

    	1.若是“ ~/test ”,表示当前用户的 $HOME 目录下的 test 目录
    	2.若是“ ~hchen/test ” 表示用户 hchen 的宿主目录下的 test 目录
    	3.若用户没有宿主目录,则“ ~ ”根据 环境变量 " HOME "决定
    	  window ,MS-DOS)
    
  • “ * ” 代替一系列后缀为 .x 的文件 用法 " *.c "
    “ \ * ”代表真实字符串" * "

objects = *.o     # object 的值就是等于 " *.o " ,不展开 *.o
objects : = $(wildcard *.o )   # objects 等于所有 .o 文件的集合 , 展开 *.o

3.4文件搜寻

  • 特殊变量 VPATH
  • 搜寻当前目录是最高优先级
  • 若找不到,然后去所定义的目录去寻找
  • 目录之间由 “ : ” 分隔,如 VPATH = src : …/headers
  • < \pattern > 需要包含 “ % ” 字符,%.h 匹配 所有以 " .h" 结尾的文件
  • <\pattern> 指定了要搜索的文件集
  • <\directories>指定了文件集的搜索的目录
  • 如 vpath %.h …/headers, 在…/headers的目录搜索所有“.h”结尾的文件
	1. vpath <pattern> <directoriees> 为符合模式<pattern>的文件指定搜索目录<directories>
	2. vpath <pattern> 清除符合模式<pattern>的文件的搜索目录
	3. vpath 					清除所有已被设置爱好的文件搜索目录

3.5伪目标

  • 伪目标只是一个标签,不可与文件名重名
  • .PHONY : clean //明确表明 clean是一个伪目标
  • 可把伪目标理解为一个执行依赖文件的总开关,但是不会生成目标执行文件
  • 如下面例子
    	all : prog1 prog2 prog3  #all是一个伪目标,不会生成执行文件 all
    						#只会执行后面的依赖文件
    	.PHONY : all  #声明了all是一个伪目标
    	
    	prog1 : prog1.o utils.o
    		gcc -o prog1 prog1.o utils.o
    	prog2 : prog2.o 
    		gcc -o prog2 prog2.o 
    	prog3 : prog3.o sort.o utils.o
    		gcc -o prog3 prog3.o sort.o utils.o
    
	.PHONY : cleanall cleanobj cleandiff #声明都是伪目标
	cleanall : cleanobj cleandiff #make cleanall
		rm program
	cleanobj :		#make cleanobj
			rm *.o
	cleandiff : 	#make cleandiff
			rm *.diff

3.6多目标

  • 自动化变量 “ $@ ” ,表示目前规则中的所有生成目标的集合
  • 自动化变量 “ $< ” ,表示目前规则中的依赖目标集
# $@ = bigoutput littleoutput  #  $@ 类似数组,依次取出目标
bigoutput littleoutput : text.g
	generate text.g -$(subst output, $@) > $@
等价于
bigoutput : text.g
	generate text.g -big > bigoutput
littleoutput : text.g
	generate text.g -little > littleoutput

3.7静态模式

  • 格式:
<targets...> : <target-pattern> : <prereq-patterns...>
	<command>
objects = foo.o bar.o
all : $(objects)			   # 伪目标
$(objects) : %.o : %.c  #从object中%.o获得 foo.o ,bar.o  ,
						# 	依赖目标 %.c 获得 %.o 并改为 foo.c bar.c
	$(CC) -c $(CFLAGS) $< -o $@
等价于
foo.o : foo.c
	$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o : bar.c
	$(CC) -c $(CFLAGS) bar.c -o bar.o
	files = foo.elc bar.o lose.o
	$(filter %.o ,$(files) ) : %.o : %.c  #使用过滤函数filter 
									# 在files 里过滤 .o 文件
		$(CC) -c $(CFLAGS) $< -o $@
	$(filter %.elc ,$(files) ) : %.elc : %el
		emacs -f batch-byte-compile $<

3.8自动生成依赖性

  • gcc -M main.c “-M”选项自动寻找源文件中包含的头文件,并生成依赖关系,GNU则为“ -MM ”
  • 为每一个源文件的自动生成的依赖文件放到一个文件中,为每一个“name.c”的文件生成一个“name.d”的Makefile文件 [.d] 文件中存放着对应[.c]文件的依赖关系
%d.c : %.c
	#清除所有的[.d]目标
	@set -e ; rm -f $@ ; \             
	$(CC) -M $(CPPFLAGS) $< >$@.    #将[.c]文件 生成对应的 [.d] 文件
; \	    	#$@后面有个“ . ”,最后生成 name.d.12345随机编号文件
	sed 's,$*\.o[ :]*,\1.0 $@ : ,g' < $@.	#用sed命令做了替换
> $@ ; \
	rm -f $@
  • main.o : main.c def.h —>变成 main.o main.d : main.c defs.h

  • [.d]文件会自动更新了,并可自动生成

  • 例子

  • include 是以按来载入文件,最载入的[.d]文件中的目标会成为默认目标

sources = foo.c bar.c
include $(sources: .c = .d) 
#将sources的[.c] 文件替换成[.d]文件

4.Makefile书写命令

4.1 显示命令

  • 在执行命令行前 加 “ @ ” 使make不会打印命令执行信息
  • make -n/–just-print 只显示命令,不会执行命令
  • make -s/–slient 全面禁止命令的显示

4.2 命令执行

  • make 完成后 会回到当前Makefile所在的目录
exec:
	cd /home/hchen  #切换到目标目录并返回执行下一条命令
	pwd  #打印Makefile所在的绝对路径
exec:
	cd /home/hchen ; pwd  #用;写在同一行, 切换到目标目录并打印目标绝对路径

在这里插入图片描述
在这里插入图片描述

  • .
    在这里插入图片描述
    在这里插入图片描述
    4.3 命令出错
  • 每当命令运行完后,make会检测每个命令的返回码
  1. 返回成功,make执行下一条命令
  2. 命令出错(命令退出码非零),make中止当前执行规则
    有可能导致所有规则被终止
  • 有时候,命令的出错并不表示有错误的

假如mkdir命令,创建的目录如果已经存在会导致出错,如果不希望终止命令执行,就忽略命令的出错,在Makefile 的命令行前加一个减号“ - ”
clean:
-rm -rf *.o

  • 全局忽略命令出错

make -i 或make --ignore-errors

  • 有一条命令出错就终止当前规则的执行,但是继续执行下一规则

make -k 或 make --keep-going

4.4 嵌套执行make

  • 对不同功能的源文件进行目录分类
  • 在每个目录下中创建该目录的Makefile
  • 对模块编译和分段编译有非常大的好处
  • 例子:加入有一个子目录叫 subdir ,这个目录下有个 Makefile 文件,来指明
    这个目录下的文件的编译规则,那么总控的Makefile 写成:
总控Makefile
意思:先进入suddir目录,然后执行make命令、
$(MAKE)是 make [commend]...的总和,方便管理维护
subsystem:
	cd subdir && $(MAKE)
等价于
subsystem:
	$(MAKE) -C subdir
  • 由上可知总控Makefile 的变量可以传递到下级的目录subdir里的Makefile
  • 以上不会覆盖下层的Makefile中所定义的变量,除非指定“ -e ”参数、
> export <variable...>    传递变量到下级的Makefile中
> unexport <variable...> 不想传递变量到下级的Makefile中
  • 例子
  • export +变量名,是用来传递变量的
  • export 不加变量名表示传递所有变量
> 例子1:
	export variable = value
	等价于
	variable = value
	export variable
	等价于
	export variable := value
	等价于
	variable := value
	export variable

> 例子2:
	export variable += value
	等价于
	variable += value
	export variable
  • MAKEFILES 是一个系统级的变量,始终传递变量
  • 在make 后加参数 -C、-f、-h、-o 、-W ,这些参数不会往下传递
make -w 或make --print-directory 在工作时会显示进入工作目录
make -C “-w”会被自动打开
make -s “-w”总是失效

4.5 定义命令包

  • 定义一个命令包
define run-yacc #  define  一个名字为run-yacc的命令包
yacc $(firstword $^) #  运行yacc程序,将 $^文件 总是生成y.tab.c文件
mv y.tab.c $@ #  将y.tab.c文件改名为 $@ 文件
endef	#  结束包的编译

如
foo.c:foo.y		# $@ = foo.c ,$^ = foo.y
	$(run-yacc)		# 执行命令包 run-yacc
					# yacc程序将foo.y生成y.foo.c文件
					# 执行mv命令 将y.foo.c文件修改名为 foo.c 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值