Makefile的使用
Makefile 使用
一、实验说明
- 课程说明
在先前的课程中,我们已经学习了 gcc 和 gdb 的使用。本节课程中,我们将介绍 Makefile 的使用。Makefile带来的好处就是——“自动化编译”,一但写好,只需要一个 make 命令,整个工程便可以完全编译,极大的提高了软件的开发效率(特别是对于那些项目较大、文件较多的工程)。
二、Makefile 简介
- 读者经常看到一个C程序的项目常常由很多的文件组成,那么,多文件的好处到底在哪里呢?一个最简单也最直接有力的理由就是,这样可以将一个大项目分成多个小的部分,独立开来,利于结构化管理。
- 在修改和维护的时候,优势就更明显了。例如,需要对代码做一点小的改动,如果这个项目所有的代码都在一个文件中,那么就要重新编译所有这些代码,这是很耗时的,不仅效率低,而且维护难度更大。但是,如果是多个不同的文件,那么只需要重新编译这些修改过的文件就行了,而且其他源文件的目标文件都已经存在,没有必要重复编译,这样就会快捷很多。
- 因此,通过合理有效的划分,将一个项目分解为多个易于处理的文件,是非常明智的做法。多文件的管理方式非常正确的选择。
一个工程中的源文件不计其数,按其类型、功能、模块分别放在若干个目录中。makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至进行更复杂的功能操作(因为makefile就像一个shell脚本一样,可以执行操作系统的命令)。 - makefile带来的好处就是——“自动化编译”,一但写好,只需要一个make命令,整个工程完全编译,极大的提高了软件的开发效率。make是一个命令工具,是一个及时makefile中命令的工具程序。
- make工具最主要也是最基本的功能就是根据makefile文件中描述的源程序至今的相互关系来完成自动编译、维护多个源文件工程。而makefile文件需要按某种语法进行编写,文件中需要说明如何编译各个源文件并链接生成可执行文件,要求定义源文件之间的依赖关系。
二、Makefile 基本规则
下面从一个简单实例入手,介绍如何编写Makefile。假设现在有一个简单的项目由几个文件组成:prog.c、 code.c、 code.h。这些文件的内容如下:
prog.c
#include <stdio.h>
#include "code.h"
int main(void){
int i = 1;
printf ("myfun(i) = %d\n", myfun(i));
}
code.c
#include "code.h"
int myfun(int in)
{
return in + 1;
}
code.h
extern int myfun(int);
这些程序都比较短,结构也很清晰,因此使用下面的命令进行编译:
- $ gcc -c code.c -o code.o
- $ gcc -c prog.c -o prog.o
- $ gcc prog.o code.o -o test
如上所示,这样就能生成可执行文件test,由于程序比较简单,而且数量也比较少,因此看不出来有多麻烦。但是,试想如果不只上面的3个文件,而是几十个或者是成百上千个甚至更多,那将是非常复杂的问题。
那么如何是好呢?这里就是makefile的绝佳舞台,下面是一个简单的makefile的例子。
首先 $ vim Makefile
test: prog.o code.o
gcc prog.o code.o -o test
prog.o: prog.c code.h
gcc -c prog.c -o prog.o
code.o: code.c code.h
gcc -c code.c -o code.o
clean:
rm -f *.o test
有了这个Makefile,不论什么时候修改源文件,只要执行一下make命令,所有必要的重新编译将自动执行。make程序利用Makefile中的数据,生成并遍历以test为根节点的树;如果要删除执行文件和所有的中间目标文件,那么,只要简单地执行一下“make clean”就可以了。
现在我们以上面的实例,来学习一下Makefile的一般写法:
`target ... : prerequisites ...
command
...
...
target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”章节中会有叙述。
prerequisites就是,要生成那个target所需要的文件或是目标。
command也就是make需要执行的命令。(任意的Shell命令)
- 这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。 说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是 Makefile的规则。也就是Makefile中最核心的内容。
- 在这个makefile中,目标文件(target)包含:执行文件edit和中间目标文件(*.o),依赖文件(prerequisites)就是冒号 后面的那些 .c 文件和 .h文件。每一个 .o 文件都有一组依赖文件,而这些 .o 文件又是执行文件 edit 的依赖文件。依赖关系的实质上就是说明了目标文件是由哪些文件生成的,换言之,目标文件是哪些文件更新的。
- 在定义好依赖关系后,后续的那一行定义了如何生成目标文件的操作系统命令,一定要以一个Tab键作为开头。记住,make并不管命令是怎么工作的,他只管 执行所定义的命令。make会比较targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期要比 targets文件的日期要新,或者target不存在的话,那么,make就会执行后续定义的命令。
- 这里要说明一点的是,clean不是一个文件,它只不过是一个动作名字,有点像C语言中的lable一样,其冒号后什么也没有,那么,make就不会自动 去找文件的依赖性,也就不会自动执行其后所定义的命令。要执行其后的命令,就要在make命令后明显得指出这个lable的名字。这样的方法非常有用,我 们可以在一个makefile中定义不用的编译或是和编译无关的命令,比如程序的打包,程序的备份,等等。
- 一个Makefile文件主要含有一系列的规则,每条规则包含以下内容:
- 一个目标,即make最终需要创建的文件,如可执行文件和目标文件;目标也可以是要执行的动作,如‘clean’;一个或多个依赖文件的列表,通常是编译目标文件所需要的其他文件。之后的一系列命令,是make执行的动作,通常是把指定的相关文件编译成目标文件的编译命令,每个命令占一行,并以tab开头
(初学者务必注意:是tab,而不是空格)
执行以上Makefile后就会自动化编译:
- $ make
- gcc -c prog.c -o prog.o
- gcc -c code.c -o code.o
- gcc prog.o code.o -o test
最后就会多产生: porg.o code.o test这三个文件,执行./test查看结果
还记得Makefile中的clean吗? make clean就会去执行rm -f *.o test这条命令,完成 clean 操作。
三、使用带宏的 Makefile
Makefile还可以定义和使用宏(也称做变量),从而使其更加自动化,更加灵活,在Makefile中定义宏的格式为:
macroname = macrotext
使用宏的格式为:
$(macroname)
四、make是如何工作的
在默认的方式下,也就是我们只输入make命令。那么,
1、make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
2、如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“test”这个文件,并把这个文件作为最终的目标文件。
3、如果test文件不存在,或是test所依赖的后面的 .o 文件的文件修改时间要比test这个文件新,那么,他就会执行后面所定义的命令来生成test这个文件。
4、如果test所依赖的.o文件也存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(这有点像一个堆栈的过程)
5、当然,你的C文件和H文件是存在的啦,于是make会生成 .o 文件,然后再用 .o 文件生命make的终极任务,也就是执行文件edit了。
这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。在找寻的过程中,如果出现错误,比如最后被依赖 的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。make只管文件的依赖性,即,如果在 我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。
五 、作业思考
用 “宏” 的方式,来改写上面的 Makefile 例子。
参考答案:
OBJS = prog.o code.o
CC = gcc
test: $(BOJS)
$(CC) $(OBJS) -o test
prog.o: prog.c code.h
$(CC) -c prog.c -o prog.o
code.o: code.c code.h
$(CC) -c code.c -o code.o
clean:
rm -f *.o test
Makefile的使用的更多相关文章
- 说说Makefile那些事儿
说说Makefile那些事儿 |扬说|透过现象看本质 工作至今,一直对Makefile半知半解.突然某天幡然醒悟,觉得此举极为不妥,只得洗心革面从头学来,以前许多不明觉厉之处顿时茅塞顿开,想想好记性不 ...
- 编写一个通用的Makefile文件
1.1在这之前,我们需要了解程序的编译过程 a.预处理:检查语法错误,展开宏,包含头文件等 b.编译:*.c-->*.S c.汇编:*.S-->*.o d.链接:.o +库文件=*.exe ...
- 编写简单的Makefile文件
makefile中的编写内容如下: www:hello.c x.h gcc hello.c -o hello clean: rm hello www:hello.c x.h 表示生成www这个文件需 ...
- 简单编写Makefile
相信很多朋友都有过这样的经历,看着开源项目中好几页的makefile文件,不知所云.在日常学习和工作中,也有意无意的去回避makefile,能改就不写,能用ide就用ide.其实makefile并没有 ...
- [转]Linux中configure/makefile
本文教你如何使用autoconf.automake等来制作一个以源代码形式(.tar.gz)发布的软件.并可在执行configure时使用自定义参数. 一.概述和基础知识 在Linux下得到一个以源代 ...
- Linux内核配置、编译及Makefile简述
Hi,大家好!我是CrazyCatJack.最近在学习Linux内核的配置.编译及Makefile文件.今天总结一下学习成果,分享给大家^_^ 1.解压缩打补丁 首先是解压缩你获取到的Linux内核. ...
- make 查找的文件名顺序为:“GNUmakefile”、“makefile”、“Makefile”
默认的情况下,make会在工作目录(执行make的目录)下按照文件名顺序寻找makefile文件读取并执行,查找的文件名顺序为:“GNUmakefile”.“makefile”.“Makefile”. ...
- 实例:对2个Makefile的备注
实例1:Makefile编译链接简单.c函数 example.c Makefile exe: example.c gcc example.c -o exe clean: rm exe 执行效果: 实例 ...
- Linux中C程序调试、makefile
gcc基本语法格式:gcc [-选项] 源文件 [-选项] 目标文件,GCC编译C程序的过程: 预处理:gcc -E hello.c hello.i.-E指定执行到预处理结束,下面类似. 编译:gcc ...
- Linux工具入门:make工具与Makefile文件
1. make工具 利用make工具可以自动完成编译工作,这些工作包括: 如果修改了某几个源文件,则只重新编译这几个源文件 如果某个头文件被修改了,则重新编译所有包含该头文件的源文件 利用这种自动编译 ...
随机推荐
- python lambda 用途
可以让一个带参数函数,传递并以无参调用 def test(a): print a a=test # #a() a=897987 fun=lambda : test(a) fun()
- Agc007_C Pushing Balls
传送门 题目大意 在一条直线上有$N$个球和$N+1$个洞,每两个球之间有一个洞,每两个洞之间有一个球,最左端和最右端都是洞,其中产生的$2N$个间隔满足从左到右是等差数列.你每次随机选择一个未被推进 ...
- .NET MVC 异步提交和返回参数
一.后台页面中的接收方法和返回写法 Jsonresult意味着返回值是json格式,也可以是string或者int等其他类型. Httppost代表只接受Post方法. Mvc中返回Jsonresul ...
- 【LeetCode】004. Median of Two Sorted Arrays
题目: There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the ...
- Word 2007 如何设置正文第一页----目录显示正文从第一页开始
最近学校里开始要求写论文了,其中有个目录中的页码都不是从第一页开始的,毕竟前面还有封面.中英文摘要.目录等,所以正文内容就不是从第一页开始的了,但是很多的书上所有正文都是从第一页开始的,我的论文如何才 ...
- bzoj 3505 [Cqoi2014]数三角形——排列组合
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3505 好题!一定要经常回顾! 那个 一条斜线上的点的个数是其两端点横坐标之差和纵坐标之差的g ...
- 第9章 DOM对象,控制HTML元素
学习地址:http://www.imooc.com/learn/10
- Poj 3287 Catch That Cow(BFS)
Description Farmer John has been informed of the location of a fugitive cow and wants to catch her i ...
- JSON-lib框架,转换JSON、XML
json-lib工具包 下载地址: http://sourceforge.net/projects/json-lib/json-lib还需要以下依赖包: jakarta commons-lang 2. ...
- 侯捷STL学习(五)--allocator和容器之间的实现关系
第十一节 分配器 STL源码学习----内存管理 分配器的好坏影响到容器的性能 operator new()里面调用malloc D:\Program Files (x86)\Microsoft Vi ...