C语言的本质(37)——makefile之隐含规则和模式规则
Makefile有很多灵活的写法,可以写得更简洁,同时减少出错的可能。本节我们来看看这样一个例子还有哪些改进的余地。
一个目标依赖的所有条件不一定非得写在一条规则中,也可以拆开写,例如:
main.o: main.h stack.h maze.h main.o: main.c
gcc-c main.c
就相当于:
main.o: main.c main.h stack.h maze.h
gcc-c main.c
如果一个目标拆开写多条规则,其中只有一条规则允许有命令列表,其它规则应该没有命令列表,否则make会报警告并且采用最后一条规则的命令列表。
这样我们的例子可以改写成:
main: main.o stack.o maze.o
gccmain.o stack.o maze.o -o main main.o: main.h stack.h maze.h
stack.o: stack.h main.h
maze.o: maze.h main.h main.o: main.c
gcc-c main.c stack.o: stack.c
gcc-c stack.c maze.o: maze.c
gcc-c maze.c clean:
-rmmain *.o .PHONY: clean
这不是比原来更繁琐了吗?现在可以把提出来的三条规则删去,写成:
main: main.o stack.o maze.o
gccmain.o stack.o maze.o -o main main.o: main.h stack.h maze.h
stack.o: stack.h main.h
maze.o: maze.h main.h clean:
-rmmain *.o .PHONY: clean
这就比原来简单多了。可是现在main.o、stack.o和maze.o这三个目标连编译命令都没有了,怎么编译的呢?试试看:
$ make
cc -c -o main.o main.c
cc -c -o stack.o stack.c
cc -c -o maze.o maze.c
gcc main.o stack.o maze.o -o main
现在解释一下前三条编译命令是怎么来。如果一个目标在Makefile中的所有规则都没有命令列表,make会尝试在内建的隐含规则(Implicit Rule)数据库中查找适用的规则。make的隐含规则数据库可以用make -p命令打印,打印出来的格式也是Makefile的格式,包括很多变量和规则,其中和我们这个例子有关的隐含规则有:
# default
OUTPUT_OPTION = -o $@ # default
CC = cc # default
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS)$(TARGET_ARCH) -c %.o: %.c
# commands to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
#号在Makefile中表示单行注释,就像C语言的//注释一样。CC是一个Makefile变量,用CC = cc定义和赋值,用$(CC)取它的值,其值应该是cc。Makefile变量像C的宏定义一样,代表一串字符,在取值的地方展开。cc是一个符号链接,通常指向gcc,在有些UNIX系统上可能指向另外一种C编译器。
CFLAGS这个变量没有定义,$(CFLAGS)展开是空,CPPFLAGS和TARGET_ARCH也是如此。这样$(COMPILE.c)展开应该是cc 空 空 空 -c,去掉“空”得到cc -c,注意中间留下4个空格,所以%.o:%.c规则的命令$(COMPILE.c) $(OUTPUT_OPTION) $<展开之后是cc -c -o $@$<,和上面的编译命令已经很接近了。
$@和$<是两个特殊的变量,$@的取值为规则中的目标,$<的取值为规则中的第一个条件。%.o: %.c是一种特殊的规则,称为模式规则(Pattern Rule)。现在回顾一下整个过程,在我们的Makefile中以main.o为目标的规则都没有命令列表,所以make会查找隐含规则,发现隐含规则中有这样一条模式规则适用,main.o符合%.o的模式,现在%就代表main(称为main.o这个名字的Stem),再替换到%.c中就是main.c。所以这条模式规则相当于:
main.o: main.c
cc -c -o main.o main.c
随后,在处理stack.o目标时又用到这条模式规则,这时又相当于:
stack.o: stack.c
cc -c -o stack.o stack.c
maze.o也同样处理。这三条规则可以由make的隐含规则推导出来,所以不必写在Makefile中。
先前我们写Makefile都是以目标为中心,一个目标依赖于若干条件,现在换个角度,以条件为中心,Makefile还可以这么写:
main: main.o stack.o maze.o
gccmain.o stack.o maze.o -o main main.o stack.o maze.o: main.h
main.o maze.o: maze.h
main.o stack.o: stack.h clean:
-rmmain *.o .PHONY: clean
我们知道,写规则的目的是让make建立依赖关系图,不管怎么写,只要把所有的依赖关系都描述清楚了就行。对于多目标的规则,make会拆成几条单目标的规则来处理,例如
target1 target2: prerequisite1prerequisite2
command$< -o $@
这样一条规则相当于:
target1: prerequisite1 prerequisite2
commandprerequisite1 -o target1 target2: prerequisite1 prerequisite2
commandprerequisite1 -o target2
注意两条规则的命令列表是一样的,但$@的取值不同。
C语言的本质(37)——makefile之隐含规则和模式规则的更多相关文章
- Makefile 隐含规则,模式规则,常见变量
隐含规则复杂的Makefile一般会使用隐含规则内的变量来简化编译处理.将隐含规则中使用的变量分成两种:一种是命令相关的,如“CC”:一种是参数相关的,如“CFLAGS”.这些变量都是大写表示. 常 ...
- 从头开始编写项目Makefile(八):型号规则
[版权声明:转载请保留源:blog.csdn.net/gentleliu.Mail:shallnew at 163 dot com] 上创建的文件夹谈及.没有生产目标文件到相应的文件夹,在这里 ...
- C语言的本质(38)——makefile之变量
我们详细看看Makefile中关于变量的语法规则.先看一个简单的例子: foo = $(bar) bar = Huh? all: @echo$(foo) 我们执行make将会打出Huh?.当make读 ...
- C语言的本质(4)——浮点数的本质与运算
C语言的本质(4)--浮点数的本质与运算 C语言规定了3种浮点数,float型.double型和long double型,其中float型占4个字节,double型占8个字节,longdouble型长 ...
- C语言的本质(28)——C语言与汇编之用汇编写一个Helloword
为了更加深入理解C语言的本质,我们需要学习一些汇编相关的知识.作为最基本的编程语言之一,汇编语言虽然应用的范围不算很广,但是非常重要.因为它能够完成许多其它语言所无法完成的功能.就拿 Linux 内核 ...
- C语言的本质(15)——C语言的函数接口入门
C语言的本质(15)--C语言的函数接口 函数的调用者和其实现者之间存在一个协议,在调用函数之前,调用者要为实现者提供某些条件,在函数返回时,实现者完成调用者需要的功能. 函数接口通过函数名,参数和返 ...
- C语言的本质(7)——C语言运算符大全
C语言的本质(7)--C语言运算符大全 C语言的结合方向 C语言中各运算符的结合性分为两种,即左结合性(自左至右)和右结合性(自右至左).例如算术运算符的结合性是自左至右,即先左后右.如有表达式 x- ...
- C语言的本质(3)——整数的本质与运算
C语言的本质(3)--整数的本质与运算 计算机存储的最小单位是字节(Byte),一个字节通常是8个bit.C语言规定char型占一个字节的存储空间.如果这8个bit按无符号整数来解释,则取值范围是0~ ...
- 开始编写Makefile(三)Makefile的默认模式规则
1.make中建立的其他语言的规则 SCCS , RCS , ar, lex 和yacc 命令 2.为了建立一个目标,make会遍历一连串的依赖关系:这个是为 决定何处开始创建: 如果没有找到目标文 ...
随机推荐
- GitHub使用说明
登陆https://github.com/,并注册账号 从如下地址下载windows客户端:https://msysgit.googlecode.com/files/Git-1.8.4-preview ...
- MongoDB GUI管理工具Mongo VUE
一.前言 现在越来越多的公司开始采用非关系数据库了,并且很多公司的面试都要求面试 者有MongoDB的使用经验,至于非关系数据库与关系型数据库之间的区别大家可以自行百度.但是作为程序员的我们,既然大部 ...
- 10招搞定web设计风格指南
From:http://www.ui.cn/detail/27579.html 今时今日,网站的创建正变得越来越复杂,而且一般都不是一个人就能干的了的.在创建网站过程中,我们需要保证设计前后一致,并符 ...
- hdu 4504 威威猫系列故事——篮球梦_简单dp
题目链接 题意:你现在分数为a,对方分数为b,你比赛还有n分钟,每次进攻需要15分钟,现在你先进攻,每次进攻可以得1或2或3,对方每次进攻得一分,问超过对方分数有多少种打法 思路:因为情况太多要用__ ...
- linux下的守护进程及会话、进程组
守护进程.会话.进程组网上有许多不错的资料.我也是网上搜罗了一堆,加上自己的理解.不敢说原创,只是写在这怕自己忘记罢了.才疏学浅,难免有错误,欢迎大家指正.下面这篇写很不错,大家可以去看看:http: ...
- gitlab升级方法
gitlab升级方法:国内网络环境推荐方法二方法一:官网的升级方式 (1)停止git服务 gitlab-ctl stop unicorn gitlab-ctl stop sidekiq gitlab- ...
- 给一个int型整数,如何将这个整数的奇偶位互换
题目: 假设一个8为整数是(10101100)b那么奇偶互换之后就是(01011100)b.假设机器是32位的 注意: 8位中最低位开始数,最低位是第0位,是偶数为,次低位时第1位,是偶数位. 做法: ...
- HttpServletRequest对象请求转发和HttpServletResponse对象请求重定向之间的区别
HttpServletRequest对象request代表浏览器请求对象,HttpServletResponse对象代表服务器响应对象,当用浏览器访问web服务器,发出请求时,Servlet调用ser ...
- 使用Xshell连接Ubuntu
使用Xshell连接Ubuntu Xshell是一个安全终端模拟软件,可以进行远程登录.我使用XShell的主要目的是在Windows环境下登录Linux终端进行编码,非常方便.本文简单介绍下它的使用 ...
- java获取当前系统毫秒,纳秒
//获取当前系统毫秒 System.out.println(System.currentTimeMillis()); //获取当前系统纳秒 System.out.println(System.nano ...