Make 学习笔记(1)
Make 学习笔记(1)
参考:
GNU make 学习总结(1)
基础
make是帮助程序员使编译器明白如何编译工程的一种工具; 核心是规则.
规则一般由三部分组成:
- 目标(target)
- 必要条件(prerequisite)
- 命令(command)
具体的书写规则一般为:
target1 target2 : prereq1 prereq2
command1
command2
目标和条件之间由冒号隔开, 命令在目标和条件的下一行, 并以Tab开头.每条规则中可以有多个目标,多个条件和多个命令.
make的原理简单剖析:
当规则中规定的目标文件不存在或者必要条件中某个文件的时间戳比目标文件的时间戳要新,就执行下面的命令,生成新的目标文件.
make会将第一条规则中的目标作为最终目标.
测试的例子:
|-- InputSpeed
|-- main.c
|-- timeutil.c
|-- timeutil.h
|-- wdshow.c
|-- wdshow.h
如上, 目录文件如此.
原始的Makefile文件如下:
main : main.o timeutil.o wdshow.o
gcc timeutil.o wdshow.o main.o -o main
main.o : main.c wdshow.c
gcc -c main.c
wdshow.o : wdshow.c wdshow.h timeutil.h
gcc -c wdshow.c
timeutil.o : timeutil.c timeutil.h
gcc -c timeutil.c
Make会将第一条规则中的目标作为最终目标,也就是我们的可执行文件main,在生成main的时候,需要三个对象文件作为必要条件文件,如果对象文件不存在或不是最新,Make会继续去找是否有规则以该文件为目标文件,找到的话就执行对应的命令,否则就会报错。这个过程大致如下,是一个递归的算法
make(rule) {
for target in rule
for each prerequisite file in rule
if file exist and is up-to-date
return "ok";
else if there is a rule(called rule-file) for file
make(rule-file);
else
return "error"
for each command in rule
run command
}
执行make命令,输出如下。可以看到,第一条命令是最后执行的,这不难理解,因为Make查找的过程是一个递归过程,最先入栈的程序将在最后被执行。
规则
基础知识
变量及自动变量
普通变量的定义是$后面跟字母或者是括号字母,如$x, $(x). 但是在make系统中定义了部分自动变量:
$@ 目标文件名
$% 档案文件成员,是指以a.o(b.o)这种形式作为目标时,括号中的内容
$< 第一个必要条件文件名
$? 时间戳在目标文件之后的所有必要条件文件名,空格隔开
$^ 所有必要条件的文件名,空格隔开,这份列表删除了重复的文件名
$+ 和$^一样,只是未删除重复的文件名
$* 目标的主文件名(即不包括后缀)
以上变量都有两个变体, 加D表示文件的目录部分, 加F表示文件的文件名部分, 注意要加括号, 如$(@D), $(@F)等.
可以简化makefile如下:
main : main.o timeutil.o wdshow.o
gcc $^ -o $@
main.o : main.c wdshow.c
gcc -c $<
wdshow.o : wdshow.c wdshow.h timeutil.h
gcc -c $<
timeutil.o : timeutil.c timeutil.h
gcc -c $<
这里需要解释下, 每一条规则是并行的, 但这里的自动变量是针对一条规则中说的, 在规则间没有这种自动变量.
假想目标
不指向任何实际文件的目标, 所以总是被更新, 对应的命令总会被执行, 对应的必要条件以及依赖总保持更新.
注意 : 如果clean是一个假想目标,那么当工程中也有一个命名为clean的文件时, 由于make并不知道clean到底是个实际文件还是假想目标(事实上make会优先确定clean是一个实际文件)同时clean也没有必要条件和依赖的更新, make clean会永远返回文件是最新的. 要确定向编译器表明某一目标是假想目标需要使用关键字.PHONY, 例如.PHONY : clean all需要将clean指定成.PHONY的一个必要条件,这样clean就总会被更新了,这里.PHONY是一个特殊目标,它告诉Make它的必要条件都是假想目标。于是我们可以在原来的Makefile中加入几行, 变为:
main : main.o timeutil.o wdshow.o
gcc $^ -o $@
main.o : main.c wdshow.c
gcc -c $<
wdshow.o : wdshow.c wdshow.h timeutil.h
gcc -c $<
timeutil.o : timeutil.c timeutil.h
gcc -c $<
.PHONY: clean all
all: main
clean:
rm main *.o
几个比较常用的假想目标:
clean 清除编译得到的二进制文件
all 所有需要生成的可执行文件
install 经过make all步骤后,在系统中安装生成的二进制程序
distclean 比clean更彻底的删除,包括由configure生成的Makefile文件
TAGS 提供可供编辑的标记表
info 从Textinfo源码创建GNU info源码
check 执行相关测试
类似.PHONY的特殊目标还有以下几个:
.SUFFIXES 指定Makefile已知后缀列表,用于后缀规则
.INTERMEDIATE 必要条件视为中间文件,make过程如果生成了指定的中间文件,完成后会被删除
.SECONDARY 同样指定中间文件,但make完成后不会被删除
.PRECIOUS make运行中断时不删除指定的目标文件
.DELETE_ON_ERROR make运行中断时删除指定的目标文件
VPATH 和 vpath
改善工程文件目录, 如将之前工程的形式改为:
|-- InputSpeed
\-- include
|-- wdshow.h
|-- timeutil.h
\-- src
|-- timeutil.c
|-- wdshow.c
|-- main.c
Makefile
如果不改变Makefile不能正确找到.c和.h文件, 可以使用 VPATH = src include 方式来找到文件, 但是VPATH只返回找到的第一个文件, 并且可能存在重名文件. 更好的方式是使用vpath pattern directory的形式来指定在哪个文件夹下搜索哪个文件, 并且对于头文件应该给GCC加上参数.具体的makefile如下:
vpath %.c src
vpath %.h include
CFLAGS = -I include
main : main.o timeutil.o wdshow.o
gcc $^ -o $@
main.o : main.c wdshow.c
gcc $(CFLAGS) -c $< -o $@
wdshow.o : wdshow.c wdshow.h timeutil.h
gcc $(CFLAGS) -c $< -o $@
timeutil.o : timeutil.c timeutil.h
gcc $(CFLAGS) -c $< -o $@
.PHONY: clean all
all: main
clean:
rm main *.o
编译规则的分类:
== 具体规则 ==
即目标, 条件, 命令都明确给出的规则.
== 模式规则 ==
依据是x.o和x.c之间具有对应关系, 需要编译出x.o就会对应去寻找x.c.
注意:
在一个规则中,如果主文件名中包含了%就表示这是一个模式规则。所谓模式规则,是指对符合这个模式的目标都采用这个规则,注意%和通配符的不同,在Makefile中是可以使用通配符的,*.c表示的是所有以c结尾的文件的集合,而%.c表示所有以c结尾的文件都匹配这条规则,一定要注意区分。
所有的内置规则都是模式规则,使用make -p可以看到这些内置规则,用其中生成%.o的这一条作为例子:
CC = gcc
CFLAGS = -I include
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
OUTOUT_OPTION = -o $@
%.o: %.c
# commands to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
== 静态模式规则 ==
与模式规则基本一样,只是规定了模式的范围,格式如下,模式目标文件必须在指定的变量中
$(OBJECTS): %.o: %c
== 隐含规则 ==
就是make自带的内置规则, 其实就是模式规则. 比如默认的x.o由x.c生成.当没有设定规则时, make就会使用内置规则. 简化上面的规则如:
vpath %.c src
vpath %.h include
CFLAGS = -I include
main: main.o timeutil.o wdshow.o
main.o: wdshow.h
wdshow.o: wdshow.h timeutil.h
timeutil.o: timeutil.h
== 自动生成依赖 ==
gcc有一个神奇的功能-MM, 可以得到头文件的依赖项, 如在我的电脑上以刚才的工程结构, 输入:
gcc -I include -MM src/main.c src/timeutil.c src/wdshow.c
可以得到:
main.o: src/main.c include/wdshow.h
timeutil.o: src/timeutil.c include/timeutil.h
wdshow.o: src/wdshow.c include/wdshow.h include/timeutil.h
Make 学习笔记(1)的更多相关文章
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
- 2014年暑假c#学习笔记目录
2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- seaJs学习笔记2 – seaJs组建库的使用
原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...
- CSS学习笔记
CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...
- HTML学习笔记
HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...
- DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记
今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...
- ucos实时操作系统学习笔记——任务间通信(消息)
ucos另一种任务间通信的机制是消息(mbox),个人感觉是它是queue中只有一个信息的特殊情况,从代码中可以很清楚的看到,因为之前有关于queue的学习笔记,所以一并讲一下mbox.为什么有了qu ...
随机推荐
- 1.1-1.3 HBase入门
一.HBASE入门 部分参考链接:https://www.cnblogs.com/steven-note/p/7209398.html 1.简介 HBase – Hadoop Database,是一个 ...
- C#字典常用技巧
说明 必须包含名空间System.Collection.Generic Dictionary里面的每一个元素都是一个键值对(由二个元素组成:键和值) 键必须是唯一的,而值不需要唯 ...
- Fitnesse + Xebium环境搭建
1.在搭建Fitnesse + Xebium环境之前先将selenium基础环境搭建完成并调试成功 参照:http://www.cnblogs.com/moonpool/p/5480724.html ...
- STL——stack
首先,堆栈是一个线性表,插入和删除只在表的一端进行.这一端称为栈顶(Stack Top),另一端则为栈底(Stack Bottom).堆栈的元素插入称为入栈,元素的删除称为出栈.由于元素的入栈和出栈总 ...
- VR相关网站
VR87870 http://www.87870.com/ VR玩家网 http://www.vrwanjia.cn/ VR之家 http://www.vr.cn/ http://gad.qq.com ...
- Codevs 1523 地精部落
1523 地精部落 省队选拔赛 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 大师 Master 题解 题目描述 Description 传说很久以前,大地上居住 ...
- 洛谷P4869 albus就是要第一个出场(线性基)
传送门 不知道线性基是什么东西的可以看看蒟蒻的总结 线性基居然有这性质我还不知道orz 假设$n$个数的线性基中有$k$个数,那么显然共有$2^k$个不同的异或和,而其中每一个异或和的出现次数都是$2 ...
- Cocoapods在OS X Yosemite上报错的解决方法
今天升级了Mac OS X 10.10-Yosemite以后运行pod install遇到下面的错误: /System/Library/Frameworks/Ruby.framework/Versio ...
- sed 匹配\n换行符
假设 str="a,b,c,d" echo ${str} | sed "s/,/\n/g" 输出: a b c d echo ${str} | sed &quo ...
- 再回首数据结构—AVL树(二)
前面主要介绍了AVL的基本概念与结构,下面开始详细介绍AVL的实现细节: AVL树实现的关键点 AVL树与二叉搜索树结构类似,但又有些细微的区别,从上面AVL树的介绍我们知道它需要维护其左右节点平衡, ...