上一章: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. Spring 计划任务

    计划任务在Spring 中实现变得非常简单: 1. 首先通过在配置类中注解 @EnableScheduling 来开启对计划任务的支持 2. 然后在你执行任务的方法上注解 @Scheduled 来声明 ...

  2. ABAP跳转屏幕

    1.call transaction语句跳转屏幕 '. CALL TRANSACTION 'VA03' AND SKIP FIRST SCREEN. . 2.调用函数 CALL FUNCTION 'M ...

  3. Webpack 10分钟入门

    可以说现在但凡开发Single page application,webpack是一个不可或缺的工具. WebPack可以看做是一个模块加工器,如上图所示.它做的事情是,接受一些输入,经过加工产生一些 ...

  4. mac安装webpack失败

    最近开始接触构建工具webpack,公司电脑是 windows,而我自己的呢是mac.本来以为在自己电脑安装很简单,但是出了点问题,所以写出来分享下. 这里用npm的方式安装,首先你要安装node.j ...

  5. pbr 5.2.1需使用中科大的源,豆瓣的不行

    -bash-4.2$ .tox/tempest/bin/pip install pbr==5.2.1DEPRECATION: Python 2.7 will reach the end of its ...

  6. JavaScript -- 内置对象字符串

    charAt和charCodeAt charAt语法: stringObject.charAt(index) 功能: 返回stringObject中index位置的字符. charCodeAt语法 s ...

  7. x86,x64,i386,i686

    x64其实就是64位, x86其实就是32位. 1. i386 适用于intel和AMD所有32位的cpu.以及via采用X86架构的32的cpu. intel平台包括8086,80286,80386 ...

  8. 机器学习十大常用算法(CITE 不会停的蜗牛 ) interesting

    算法如下: 决策树 随机森林算法 逻辑回归 SVM 朴素贝叶斯 K最近邻算法 K均值算法 Adaboost 算法 神经网络 马尔可夫 1. 决策树 根据一些 feature 进行分类,每个节点提一个问 ...

  9. C++中有三种创建对象的方法

    #include <iostream> using namespace std; class A { private: int n; public: A(int m):n(m) { } ~ ...

  10. 转 Solr vs. Elasticsearch谁是开源搜索引擎王者

    转 https://www.cnblogs.com/xiaoqi/p/6545314.html Solr vs. Elasticsearch谁是开源搜索引擎王者 当前是云计算和数据快速增长的时代,今天 ...