上一章:C语言之Makefile基础(一)

上一章的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会报警告并采用最后一条规则的命令列表。

于是,之前的Makefile文件我们还可以写成这样:

main: main.o stack.o maze.o
gcc main.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:
-rm main *.o
.PHONY: clean

  

这样虽然也允许执行,但相比以前更繁琐了些,于是我们把提出来的三条规则删去,写成:

main: main.o stack.o maze.o
gcc main.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:
-rm main *.o
.PHONY: clean

  

这样就比原来简单多了,可是现在main.o、stack.o和maze.o这三个目标连编译命令都没有了,怎么编译呢?试试看:

[root@localhost linux_c]# 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会尝试在内建的隐含规则数据库中查找适用的规则。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中表示单行注释。CC是一个Makefile变量,用CC = cc定义和赋值,用$(CC)取它的值,其值应该是cc。Makefile变量像C的宏定义一样,代表一串字符,在取值的地方展开。cc是一个符号链接,通常指向gcc,在有些Unix系统上可能指向另外一种C编译器

[root@localhost linux_c]# which cc
/usr/bin/cc
[root@localhost linux_c]# ls -l /usr/bin/cc
lrwxrwxrwx. 1 root root 3 Feb 13 11:13 /usr/bin/cc -> gcc

  

在make -p中包含这一段定义:

# default
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
%.o: %.c
# commands to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<

    

CFLAGS这个变量没有定义,$(CFLAGS)展开是空,CPPFLAGS和TARGET_ARCH也是如此,这样,$(COMPILE.c)展开应该是cc 空 空 空 -c,去掉“空”就得到cc -c。所以,%.o: %.c规则的命令 $(COMPILE.c) $(OUTPUT_OPTION) $<展开之后为cc -c -o $@ $<,和上面的编译命令很接近了

$@和$<是两个特殊的变量,$@的取值为规则中的目标,$<的取值为规则中的第一个条件。 %.o:%.c是一种特殊的规则,称为模式规则,我们再来回顾一下整个过程,在我们的Makefile中,以main.o为目标的规则都没有命令列表,所以make会查找隐含规则,发现隐含规则中有一条模式规则适用main.o符合%.o模式,%代表main,以.o结尾的文件,再替换到%.c中就是main.c,所以,这条规则相当于:

main.o: main.c
cc -c -o main.o main.c

  

同理:

stack.o: stack.c
cc -c -o stack.o stack.c

  

maze.o也同样处理。这三条规则可以由make的隐含规则推导出来,所以就不必写在Makefile中了

先前我们写Makefile都是以目标为中心,一个目标依赖若干条件,现在换个角度,以条件为中心,Makefile还可以这么写:

main: main.o stack.o maze.o
gcc main.o stack.o maze.o -o main
main.o stack.o: main.h
main.o maze.o: maze.h
main.o stack.o: stack.h
clean:
-rm main *.o
.PHONY: clean

    

写规则的目的是让make建立依赖关系图,不管怎么写,只要把所有的依赖关系描述清楚就行,对于多目标的规则,make会拆成几条单目标的规则来处理,例如:

target1 target2: prerequisite1 prerequisite2
command $< -o $@

  

这样的规则相当于:

target1: prerequisite1 prerequisite2
command prerequisite1 -o target1
target2: prerequisite1 prerequisite2
command prerequisite1 -o target2

  

注意这两条规则的命令列表是一样的,但$@的取值不同

Makefile基础(二)的更多相关文章

  1. Makefile基础(三)

    第一章:C语言之Makefile基础(一) 第二章:C语言之Makefile基础(二) 再来看一个简单的例子: [root@localhost linux_c]# cat Makefile foo = ...

  2. 彻底掌握Makefile(二)

    彻底掌握Makefile(二) 前言 在前面的文章彻底掌握Makefile(一)当中,我们简要的介绍了一些常见的makefile使用方法,在本篇文章当中我们将继续介绍一些makefile当中的常见用法 ...

  3. Python全栈开发【基础二】

    Python全栈开发[基础二] 本节内容: Python 运算符(算术运算.比较运算.赋值运算.逻辑运算.成员运算) 基本数据类型(数字.布尔值.字符串.列表.元组.字典) 其他(编码,range,f ...

  4. Bootstrap <基础二十九>面板(Panels)

    Bootstrap 面板(Panels).面板组件用于把 DOM 组件插入到一个盒子中.创建一个基本的面板,只需要向 <div> 元素添加 class .panel 和 class .pa ...

  5. Bootstrap <基础二十八>列表组

    列表组.列表组件用于以列表形式呈现复杂的和自定义的内容.创建一个基本的列表组的步骤如下: 向元素 <ul> 添加 class .list-group. 向 <li> 添加 cl ...

  6. Bootstrap<基础二十七> 多媒体对象(Media Object)

    Bootstrap 中的多媒体对象(Media Object).这些抽象的对象样式用于创建各种类型的组件(比如:博客评论),我们可以在组件中使用图文混排,图像可以左对齐或者右对齐.媒体对象可以用更少的 ...

  7. Bootstrap <基础二十六>进度条

    Bootstrap 进度条.在本教程中,你将看到如何使用 Bootstrap 创建加载.重定向或动作状态的进度条. Bootstrap 进度条使用 CSS3 过渡和动画来获得该效果.Internet ...

  8. Bootstrap <基础二十五>警告(Alerts)

    警告(Alerts)以及 Bootstrap 所提供的用于警告的 class.警告(Alerts)向用户提供了一种定义消息样式的方式.它们为典型的用户操作提供了上下文信息反馈. 您可以为警告框添加一个 ...

  9. Bootstrap<基础二十四> 缩略图

    Bootstrap 缩略图.大多数站点都需要在网格中布局图像.视频.文本等.Bootstrap 通过缩略图为此提供了一种简便的方式.使用 Bootstrap 创建缩略图的步骤如下: 在图像周围添加带有 ...

随机推荐

  1. 剑指tomcat之应用管理

    tomcat服务启动之后,有tomcat自身提供的应用管理(App Manage)页面,默认的地址就是服务的IP地址+端口号(IP:port):页面如下所示 点击上图的按钮便可进入应用管理页面,需要账 ...

  2. 织梦dedecms手机版上下篇链接错误的解决方法

    打开 \include\arc.archives.class.php 1. 找到 $this->PreNext['pre'] = "上一篇:<a href='$mlink'> ...

  3. Android里的网格空隙

    在很多移动端或者web端开发中我们会遇到很多网格布局,如果我们使用线性布局来实现一些简单的网格布局就需要使用padding/margin等属性来使其对齐,代码如下: <LinearLayout ...

  4. SVN合并步骤

    1.trunk->branch/tag 分支路径在分支文件夹中,选择右键检出 2.合并分支到主干分支新增 1.txt 文件 需要合并到主干 在trunck->鼠标右键合并->合并到不 ...

  5. BZOJ 4563: [Haoi2016]放棋子

    Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 389  Solved: 248[Submit][Status][Discuss] Descriptio ...

  6. python基础教程总结15——6 CGI远程编辑

    功能: 将文档作为普通网页显示: 在web表单的文本域内显示文档: 保存表单中的文本: 使用密码保护文档: 容易拓展,支持处理多余一个文档的情况 1.CGI CGI(Comment Gateway I ...

  7. RAC数据库后台进程介绍

    在RAC数据库上会比单实例数据库多一些进程,这些进程是RAC特有的,为了实现集群数据库功能而设置的. 10g RAC特有进程:$ ps -ef|grep ora_oracle    4721     ...

  8. Luogu [P3951] 小凯的疑惑

    题目详见:[P3951]小凯的疑惑 首先说明:此题为一道提高组的题.但其实代码并没有提高组的水平.主要考的是我们的推断能力,以及看到题后的分析能力. 分析如下: 证明当k>ab-a-b时,小凯可 ...

  9. jQuery向界面输出时保留两位小数

    通过JSTL下的<fmt:formatNumber>标签实现,具体实现代码如下: <%@ taglib uri="http://java.sun.com/jsp/jstl/ ...

  10. *运算和&运算

    /* &:取地址运算符 *:指针运算符(或称为间接运算符),取指针所指向的对象的内容 */ int a,b; int *pointer_1, *pointer_2; pointer_1 = & ...