make 和 makefile 的关系
程序的 编译 和 链接
要先总结 make
和 makefile
,就需要先了解下面这个过程:
- 预编译:也叫预处理,进行一些文本替换工作,比如将
#define
定义的内容,在代码中进行替换; - 编译:将预处理得到的代码,进行词法分析、语法分析、中间代码……;如果是在Windows下,中间代码就是
.obj
文件;在Linux系统下,中间代码就是.o
文件; - 汇编:将编译得到的汇编代码,通过汇编程序得到 0 和 1 机器语言;
- 链接:链接各种静态链接库和动态链接库得到可执行文件。
make 和 makefile 能干啥?
一个工程,那么多源文件,一堆的 cpp
和 h
文件,怎么编译啊?编译一个大型工程,如果Rebuild可能就需要好几个小时,甚至十几个小时,那我们就可能要问了。
- 如何像VS那样,一键就能编译整个项目?
- 如何修改了哪个文件,就编译修改的那个文件,而不是重新编译整个工程?
好吧,make
和 makefile
就能搞定这些。makefile
定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile
就像一个Shell脚本一样,其中也可以执行操作系统的命令。makefile
带来的好处就是——“自动化编译”,一旦写好,只需要一个 make
命令,整个工程完全自动编译,极大的提高了软件开发的效率。
make
是一个命令工具,是一个解释 makefile
中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make
,Visual C++的nmake
,Linux 下 GNU 的 make
。可见,makefile
都成为了一种在工程方面的编译方法。make 命令执行时,需要一个 makefile
文件,以告诉 make
命令需要怎么样的去编译和链接程序。
现在,应该明白了吧。make
是一个命令,用来解析 makefile
文件;makefile
是一个文件,用来告诉 make
命令,如何编译整个工程,生成可执行文件。再打个比方:
导演 == make
剧本 == makefile
演员 == MAKE调用的外部命令,如编译器、链接器等
电影 == 生成的程序
解决问题举例
怎么就出现了make这个东西了呢?还记得你入门C语言时,写下的Hello World程序么?
#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}
当你在终端中输入 gcc HelloWorld.c
命令时,就会生成一个 a.out
文件(如果不用 -o 参数指定输出文件名的话,默认为 a.out),然后就可以神奇的使用 ./a.out
执行该文件,打印出了 Hello World
。这是一件让初学者兴奋的事情。问题来了,现在就仅仅是一个 HelloWorld.c
文件,如果有多个代码文件,而多个代码文件之间又存在引用关系,这个时候,该如何去编译生成一个可执行文件呢?比如现在有一下源文件:
add.h
add.c
sub.h
sub.c
mul.h
mul.c
divi.h
divi.c
main.c
这些代码文件的定义分别如下:
add.h 文件
#ifndef _ADD_H_
#define _ADD_H_
int add(int a, int b);
#endif
add.c 文件
#include "add.h"
int add(int a, int b)
{
return a + b;
}
sub.h 文件
#ifndef _SUB_H_
#define _SUB_H_
int sub(int a, int b);
#endif
sub.c 文件
#include "sub.h"
int sub(int a, int b
{
return a - b;
}
mul.h 文件
#ifndef _MUL_H_
#define _MUL_H_
int mul(int a, int b);
#endif
mul.c 文件
#include "mul.h"
int mul(int a, int b)
{
return a * b;
}
divi.h 文件
#ifndef _DIVI_H_
#define _DIVI_H_
int divi(int a, int b);
#endif
divi.c 文件
#include "divi.h"
int divi(int a, int b)
{
if (b == 0)
{
return 0;
}
return a / b;
}
main.c 文件
#include <stdio.h>
#include "add.h"
#include "sub.h"
#include "mul.h"
#include "divi.h" int main()
{
int a = 10;
int b = 2; printf("%d + %d = %d\n", a, b, add(a, b));
printf("%d - %d = %d\n", a, b, sub(a, b));
printf("%d * %d = %d\n", a, b, mul(a, b));
printf("%d / %d = %d\n", a, b, divi(a, b));
return 0;
}
你也看到了,在 main.c
中要引用这些文件,那现在如何编译,生成一个可执行文件呢?
最笨的解决方法
最笨的解决方法就是依次编译所有文件,生成对应的 .o
目标文件。参考如下:
$ gcc -c sub.c -o sub.o
$ gcc -c add.c -o add.o
$ gcc -c sub.c -o sub.o
$ gcc -c mul.c -o mul.o
$ gcc -c divi.c -o divi.o
$ gcc -c main.c -o main.o
然后再使用如下命令对所生成的单个目标文件进行链接,生成可执行文件。
$ gcc -o main add.o sub.o mul.o divi.o main.o
然后就可以得到一个可执行程序 main
,可以直接使用 ./main
进行运行。还不错,虽然过程艰辛,至少也可以得到可执行程序。那么有没有比这更简单的方法呢?如果一个项目,几千个文件,这么写下去,还不得累死人啊。办法是有的,我接着总结。
使用makefile文件
使用上面那种最笨的办法,效率是非常低得,当添加新的文件,或者修改现有文件时,维护起来也是非常难得。基于此,现在就来说说使用 makefile
文件来搞定这一切。
关于什么是 makefile
,在文章的开头我就已经总结了,至于它和 make
的关系,在文章的开头也说的非常清楚了,现在就来看看如何使用 makefile
来完成上面同样的任务,生成一个 main
的可执行文件。
#target:dependency-file
main:main.o add.o sub.o mul.o divi.o
gcc -o main main.o add.o sub.o mul.o divi.o
main.o:main.c add.h sub.h mul.h divi.h
gcc -c main.c -o main.o
add.o:add.c add.h
gcc -c add.c -o add.o
sub.o:sub.c sub.h
gcc -c sub.c -o sub.o
mul.o:mul.c mul.h
gcc -c mul.c -o mul.o
divi.o:divi.c divi.h
gcc -c divi.c -o divi.o
clean:
rm -f *.o
上面就是 makefile
文件的内容,对于 makefile
的内容的编写规则,这里先不说。
现在你可以在 makefile
的同目录下执行 make
命令,然后就可以看到生成了一堆 .o
目标文件,还有那个可执行的 main
文件;接着运行 make clean,那些 .o
文件就全部被删除了。为什么是这样?好了,你先照着做一遍吧。
makefile文件编写规则
上面只是给出了一个简单的 makefile
文件,你肯定好奇这个 makefile
的书写规则是什么样子的?
makefile 的规则大体上就是以下格式:
target
是一个目标文件,可以是 Object File
(.o文件),也可以使最终的执行文件,而 dependency-file
是生成对应 target
所需要依赖的文件或者其它的 target,command 就是最终由 make 执行的命令。
上面说了一段话,简短而言就是:生成一个 target,需要依赖的文件,而使用命令来将依赖文件生成对应的 target 的规则,是在 command 中定义的。如果 dependency-file
中有一个或者多个文件比 target
文件要新的话,command
所定义的命令就会被执行,这就是 makefile
的规则,也就是 makefile
最核心的内容。
makefile
文件中可以定义变量,可以使用函数,还有各种判断,内容繁多,这里就不一一总结了,更详细的介绍,可以看看大牛陈皓的系列博客《跟我一起写makefile》。
参考:
http://www.jellythink.com/archives/810?utm_source=tuicool&utm_medium=referral
http://bbs.csdn.net/topics/390143962
make 和 makefile 的关系的更多相关文章
- Makefile.am, Makefile.in 与 Makefile的关系(转)
文章出处:http://blog.mcuol.com/User/wangguangdong/Article/17384_1.htm Makefile.am, Makefile.in, Makefile ...
- Makefile依赖关系中的竖线“|”
网上搜索无果,于是自己查看了一下makefile的info文件,其中解释如下: [java] view plain copy print? target : prerequisites [TAB] ...
- ubuntu——Kconfig、.config、Makefile的关系
原文地址:http://blog.csdn.net/estate66/article/details/5886816 ,本人对此文有改进. 当我们编写完一个驱动后,我们要把它以模块形式编译或者直接编译 ...
- kernel Makefile Kconfig说明
实际文档位置:Documentation/kbuild/makefiles.txt,此为翻译稿. *************************************************** ...
- linux-2.6.22.6内核启动分析之Makefile文件
学习目标 分析Makefile文件,了解内核中的哪些文件被编译,如何被编译,连接时顺序如何确定! Linux内核源码中包含很多的Makefile文件,这些Makefile文件又包含其它的一些文件,比如 ...
- Makefile基础(一)
在大型的C语言项目中,一般都是由多个源文件编译链接形成的可执行程序,而这些源文件的处理步骤,通常交给Makefile来管理,Makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后 ...
- Make 和 Makefile快速入门
前言 一个项目,拥有成百上千的源程序文件,编译链接这些源文件都是有规则的.Makefile是整个工程的编译规则集合,只需要一个make命令,就可以实现“自动化编译”.make是一个解释makefile ...
- Linux C 收藏
某招聘要求:熟悉高性能分布式网络服务端设计开发,熟悉epoll.多线程.异步IO.事件驱动等服务端技术: <UNIX环境高级编程(第3版)>apue.h等源码文件的编译安装 <UNI ...
- gcc编译的四个阶段:预处理,编译,汇编,链接
1:gcc编译的四个阶段:预处理,编译,汇编,链接 #vi file.c #gcc -E file.c -o file.i//-E查看且预处理后停止编译,-o生成目标文件,-i表示已预处理 #gcc ...
随机推荐
- 【2016-11-6】【坚持学习】【Day21】【子窗口关闭时,同步关闭它的主窗口(方法二)】
根据上文,在子窗口设置一个委托.然后在子窗口关闭事件,执行委托实例,然后在主窗口增加监听委托的方法.... 想想,本事关闭事件就是一个特殊的委托.那么干嘛还要特意去声明一个新的呢?多此一举. 于是有下 ...
- Android USB Gadget复合设备驱动(打印机)测试方法
启动Android打印机设备,并用USB线连接电脑主机及Android打印机. Android打印机系统启动完成后,在Windows设备管理器中,可以看到Android Phone设备和USB打印支持 ...
- [USACO14OPEN] Dueling GPS's[最短路建模]
题目描述 Farmer John has recently purchased a new car online, but in his haste he accidentally clicked t ...
- 第3章 Linux常用命令(5)_网络命令和挂载命令
7. 网络命令 7.1 给用户发信息,以ctr+D保存结束 (1)write命令 命令名称 write 命令所在路径 /user/bin/write 执行权限 所有用户 语法 write <用户 ...
- Linux(CentOs6.4)安装Git
安装之前我们先来了解下git,并且要反问下:我为什么要使用git?svn用的不是很好嘛,我干嘛要换?... 问1:为什么需要版本控制系统? 版本控制是一种记录若干文件内容变化,以便将来查阅特定版本修订 ...
- [译]用AngularJS构建大型ASP.NET单页应用(一)
原文地址:http://www.codeproject.com/Articles/808213/Developing-a-Large-Scale-Application-with-a-Single 渣 ...
- Swift来的正是时候
早期对ObjectiveC这玩意不是很感冒,一直没有动手搞Apple平台下的开发,现在Swift来了,时机成熟,提升门槛后的IOS,才是量子本人想弄的.现在不用担心搞ObjectiveC的走在前面了. ...
- RTC时钟
1.设置时间之前取消备份区域(BKP)写保护 主要有两部分组成 1.用来和APB1总线对接,对其进行读写操作 2. 预分频模块:在RTC_CR设置相应的允许,位每个TR_CLK周期中RTC产生一个中断 ...
- 利用ucenter整合discuz数据
由于项目需要,需要用到discuz论坛用户的数据,所以想到利用ucenter获取数据.以下为整合ucenter的过程. 1.首先你需要下载官方demo:http://faq.comsenz.com/l ...
- angularJs模块ui-router之路由控制
在你的应用中大多数状态都有与其相关联的 url,路由控制不是设计完成 state 之后的事后想法,而是开始开发时就应该考虑的问题. 这里是如何设置一个基本url. $stateProvider .st ...