关于makefile中自动产生依赖的理解
本博文是在学习了《GNU Make中文手册》后记录下来的自己的关于自动产生makefile依赖的语句的理解,向大家分享。
《GNU make中文手册》中的相关章节见一下链接:
http://blog.csdn.net/gmpy_tiger/article/details/51849257
========================================================================================
为了理解自动产生依赖的代码,必须先掌握这两个基础又有点偏的知识点:
1、Makefile 中,一个文件可以作为多个规则的目标(多个规则中只能有一个规则定义命令)。这种情况时,以这个文件为目标的规则的所有依赖文件将会被合并成此目标一个依赖文件列表,当其中任何一个依赖文件比目标更新(比较目标文件和依赖文件的时间戳)时,make 将会执行特定的命令来重建这个目标。
举个例子:
有如下的makefile:
foo.o : defs.h
bar.o : defs.h test.h
foo.o : config.h
等效于:
foo.o : defs.h config.h
bar.o : defs.h test.h
就是把相同foo.o目标的规则(最多只允许一个规则有命令,其他规则只能有依赖)合并所有的依赖。
2、在linux 的命令sed中,有这么一个规则(模式替换单独的单词,见《Linux命令行与shell脚本编程大全》):
sed编辑器用圆括号来定义替代模式的子字符串,替代字符由反斜杠和数组组成。
很难理解是吧,举个例子你就懂了。
echo "maybe this is a test" | sed 's/\ (this\ ) is a \ (test\ )/Is \1 really \2 /g'
输出:
maybe Is this really test
关于脚本的echo,管道,sed的替换命令s等基础我就不讲了,自己百度学习。这里我要讲的是,用“()”小括号括起来的被替换内容,可以在替换内容上用“\数字”代替,直接动态引用,省去重复输入的麻烦。例如上面的例子,\1代表this,\2代表test,整个sed命令的意思是把
this is a test
替换为
Is this really test
ps:因为小括号在正则表达式中有意义,因此需要转义,因此是\ (...\ )而不是(...)
========================================================================================
废话不多说,先直接上我自己写得自动产生依赖的代码(与《GNU Make中文手册》有些许出入,会写linux脚本的就会发现,修改的部分无伤大雅):
%.d : %.c
gcc -MM $< > $@.$ $ $ $; \ (1)
sed 's/\ ($*\ )\.o/\1.o $@/g' < $@.$ $ $ $ > $@; \ (2)
rm -f $@.$ $ $ $ (3)
ps:网页的排版问题,为了看的直观做了修改,使用时请把四个$以及\ (和\ )之间的空格去掉,下同
继续以例子讲解:
源代码如下(helloworld.c):
#include <stdio.h>
#include "test.h" //test.h为空文件,只用于实验讲解
int main(int argc, char *argv){
printf("hello world!\n");
}
(1):
用gcc -MM helloworld.c的输出结果是:
helloworld.o: helloworld.c test.h
因此(1)行代码
gcc -MM $< > $@.$ $ $ $; \ (1)
的作用,就是生成helloworld.o.xxxx的临时文件,文件内写得是"helloworld.o: helloworld.c test.h"
ps:在第一行的代码里涉及到makefile的自动化变量$<、$@和linux脚本的重定向,自行百度,不再讲解。
(2):
第二行的代码
sed 's/\ ($*\ )\.o/\1.o $@/g' < $@.$ $ $ $ > $@;
\ (2)
参考本博文上文的基础知识2,其中,$*是自动化变量,在这里指的是:helloworld。$@也是自动化变量,在这里指的是helloworld.d。
这行代码可以理解为:
sed 's/helloworld.o/helloworld.o helloworld.d/g' < $@.$ $ $ $ >$@
ps:其中的两个< 、>为linux脚本的重定向,自己百度学习。
因此,实际的处理结果是把第(1)行代码的结果
helloworld.o: helloworld.c test.h
转换为:
helloworld.o
helloworld.d: helloworld.c test.h
并把转换的结果保存到helloworld.d文件中。
(3):
第二行代码其实就已经完成任务了,第三行代码仅仅是删除第一行代码创建的临时文件$@.$$$$。在此不再详述。
=======================================================================================
自动产生依赖的代码就这样理解,那怎么使用呢?
先看看上面代码生成的结果:
helloworld.o helloworld.d: helloworld.c test.h 保存在helloworld.d文件中
要使用,除了上面的代码之外,只需要加一句
include helloworld.d
其实就相当于把代码自动生成的 helloworld.o helloworld.d: helloworld.c test.h包含在makefile中。
包含上了helloworld.d的作用有两条
1、因为要包含helloworld.d,当搜索不到有helloworld.d文件时,就会自动匹配上文产生依赖的代码,自行生成helloworld.d,当然,当helloworld.c或者test.h修改后,由于helloworld.d已经过时,也会重新生成helloworld.d
2、helloworld.o的依赖会合并上helloworld.c test.h(参考本博文上文的基础知识1),从而实现了自动产生依赖
=======================================================================================
总结起来,我对上面helloworld源码写的makefile如下:
CC = gcc
TARGET = helloworld
$(TARGET) :
include $(TARGET).d
%.d : %.c
gcc -MM $^ > $@.$ $ $ $; \
sed 's/\ ($*.o\ )/\1 $@/g' < $@.$ $ $ $ > $@; \
rm $@.$ $ $ $
.PHONY: clean
clean:
$(RM) $(TARGET) $(TARGET).d $(TARGET).o
helloworld.d如下:
helloworld.o helloworld.d: helloworld.c test.h
关于makefile中自动产生依赖的理解的更多相关文章
- Makefile中自动生成头文件依赖
为什么需要自动生成头文件依赖? 编译单个源文件时,需要获取文件中包含的头文件的信息,但是一般的Makefile不会在规则中明确写明文件依赖的头文件,所以单独修改头文件后,不会导致包含头文件的源文件重新 ...
- Makefile 7——自动生成依赖关系 三颗星
后面会介绍gcc获得源文件依赖的方法,gcc这个功能就是为make而存在的.我们采用gcc的-MM选项结合sed命令.使用sed进行替换的目的是为了在目标名前加上“objs/”前缀.gcc的-E选项, ...
- 工程管理之makefile与自动创建makefile文件过程
(风雪之隅 http://www.laruence.com/2009/11/18/1154.html) Linux Makefile自动编译和链接使用的环境 想知道到Linux Makefile系统的 ...
- Makefile 自动生成依赖
虽然以前对Makefile有个基本概念,但是真正到自己去写一个哪怕是简单的Makefile时也会遇到不少的麻烦. 现在我有如下文件 dList.h dList.c memory.c debug. ...
- makefile自动生成依赖关系
手工编写依赖关系不仅工作量大而且极易出现遗漏,更新也很难及时,修改源或头文件后makefile可能忘记修改.为了解决这个问题,可以用gcc的-M选项自动生成目标文件和源文件的依赖关系.-M选项会把包含 ...
- makefile 中添加依赖的库文件
当库文件中包含多个头文件和c源文件时,需要执行如下步骤: 1) makefile中添加 库文件依赖, -L 后面跟库文件的路径, -l(小写)后面跟库的名字 2)将库文件中的头文件添加到工程中去,使 ...
- makefile中伪目标的理解
1. 我们知道Makefile中的语法是这样: target ... : prerequisites ... command - - 2. 假如编译两个文件可以这么写: a.o:a.c gcc -c ...
- 对 makefile 中 .DEFAULT 的理解
上例子: all:gao @echo "final".DEFAULT: @echo "In default" 由于 gao 是一个前提条件,但是 makefil ...
- Makeflie自动生成依赖,自动化编译
在netbeans里开发,有一个重要文件makefile,是用来编译所有的文件. 项目的目录结构如下,扁平的目录结构,如何实现自动化编译,写makefile呢? 第一版 基础版: CC = g++ C ...
随机推荐
- Mysql学习---Python操作Mysql 1231
安装PyMysql 安装PyMysql:Py3默认自带pip3安装,Py2默认无pip命令 cmd进入PyCharm的安装目录完成安装 pip3 install pymysql 安装完成的位置:E:\ ...
- 沉淀,再出发:web前端的一些认识
沉淀,再出发:web前端的一些认识 一.前言 作为程序员,我一直认为全栈是一种最基本的能力,没有了这种目标就会发现自己越往后面发展路就越窄,很多自己不了解的东西会阻塞自己去理解整个系统的开发过程和效率 ...
- 初始python(二)
1. 列表list 1.1 切片# 定义一个list.list = [1, 2, 3, 4, 5] 从左往右读取字符(默认步长为 1 ).如:list[-2:-1] # 返回一个list数据类型,[ ...
- c# winform文本框数字,数值校验
文本框数字,数值校验 public void DigitCheck_KeyPress(object sender, KeyPressEventArgs e) { e.Handled = !char.I ...
- ZT Android4.2关于bluetooth在HAL层的分析(1)
我的电子杂烩饭 http://blog.sina.com.cn/wuchuchu2012 [订阅][手机订阅] 首页 博文目录 图片 关于我 正文 字体大小:大 中 小 Android4.2关于blu ...
- Python2.7 - IMOOC - 2
第三章 Python变量和数据类型 3-1.数据类型 在Python中,能够直接处理的数据类型有以下几种: 整数 Python可以处理任意大小的整数,当然包括负整数,表示方法和数学上的写法一模一样,十 ...
- PhoneGap获取设备信息
一. 获取设备信息的方法列表(如果没有或者检测不出来就显示undefined) 1.device.name 设备名称(一些国产机检测不出来) 2.device.model ...
- Gym 100633G Nano alarm-clocks
题目,给定n个时钟,要求把他们调成一样的时间.求最小的步数 思路:肯定是有一个时钟作为标准的啦,要找到这个时钟,怎么找呢?没其他方便的方法,暴力枚举.那么枚举后,怎么能快速地算到其他时钟转到这个时钟的 ...
- Inno Setup替代默认的背景图片
一.这是默认的设置生成的安装程序界面. 不行,我要定制!我要换!那么,这两货是从哪里来的呢?既然是默认的就有,那我下意识的来到了inno setup的安装路径下,果然让我发现了. 好了,于是我用我准备 ...
- .NET完全手动搭建三层B/S架构
简介:三层架构(3-tier application) 通常意义上的三层架构就是将整个业务应用划分为:表现层(WebUI).业务逻辑层(BusinessLogicLayer).数据访问层(DataAc ...