Linux下的Make与Makefile
原文转载自:http://www.cpplive.com/html/1776.html
另外一个不错的博客http://bbs.chinaunix.net/thread-1950588-1-1.html
对于Linux跟Unix系统而言,make是一个极其重要的编译命令,我们在开发项目或者安装应用软件时,经常要用到make或make install,对于一个包含几十、几百甚至成千上万个源文件的项目,如果每次都要键入gcc或g++等命令来进行编译的话,那对于程序员简直就是一场噩梦,而使用make和makefile工具便可以简洁明了地理顺各个源文件之间纷繁复杂的相互关系,将大型项目分解成多个更易于管理的模块,自动完成编译工作,并且可以只对程序员上次编译后修改过的部分进行编译。
因此,有效的利用make和makefile工具可以大大提高程序开发的效率。同时也极大地减轻了Linux下应用程序安装的难度。接下来,就让我们来详细了解一下make及其描述文件makefile。
一、make
1、程序的诞生
无论是C语言还是C++,我们通常首先将源文件编译成中间代码,在Windows下是“.obj”文件,在Linux或Unix下是“.o”文件,即目标文件(Object File),这个过程叫作编译(Compile);然后再把生成的目标文件合成可执行文件,这个过程叫作链接(Link)。编译时,编译器负责检查语法、函数与变量的声明正确与否,只要检测过关,就将生成目标文件,一般而言,每个源文件都对应一个目标文件。
链接时,编译器负责链接函数和全局变量,编译器并不关心函数所在的源文件,只关心目标文件,有时候因为源文件太多,编译时生成的目标文件很多,导致在链接时需要指定一大堆的目标文件,显然很不方便,这时候我们可以将目标文件打包成一个库文件,Windows下这种库文件也就是“.lib”文件,Linux下是“.a”或“.so”文件。
总之,编译时,我们通常先将源文件编译成目标文件,再对目标文件进行链接操作,程序便诞生了。
2、make的工作原理
make工具最基本的功能是调用Makefile文件,通过Makefile文件来描述程编译的整个过程,不必每次敲gcc或g++等命令来完成编译工作。当然,Makefile文件需要按照一定的语法进行编写,说明如何编译各个源文件并链接生成可执行文件,以及各个文件之间的依赖关系。
如下图所示,演示了一个简单的make命令编译过程:
在该目录下,有三个文件,add.c main.c Makefile。内容如下:
- //add.c
- int add(int a, int b)
- {
- return(a+b);
- }
- //main.c
- #include"stdio.h"
- #include"stdlib.h"
- int add(int a,int b);
- int main(int argc, char**argv)
- {
- int a=atoi(argv[1]);
- int b=atoi(argv[2]);
- printf("%d+%d=%d\n",a,b,add(a,b));
- return 0;
- }
//Makefile
- #This is an example for describing makefile
- add:main.o add.o
- gcc -o add main.o add.o
- main.o:main.c
- gcc -c main.c
- add.o:add.c
- gcc -c add.c
- clean:
- rm main.o add.o add
在这个Makefile文件中,第一行第一个字符为#,这是一个注释行;第二行指定可执行文件add依赖目标文件main.o、add.o;第三行表述了第二行的具体依赖关系,即执行命令“gcc -o add main.o add.o”,将目标文件链接成为可执行文件;第四行指定目标文件main.o依赖源文件main.c;第五行表述第四行的具体依赖关系,即执行命令“gcc -c main.c”,将源文件main.c编译成目标文件main.o;第六行指定目标文件add.o依赖源文件add.c;第七行表述第六行的具体依赖关系,即执行命令“gcc -c add.c”,将源文件add.c编译成目标文件add.o。
在当前目录下输入make命令,系统将自动完成如下操作。
(1)make工具在当前目录下依次寻找名为GNUmakefile、makefile或Makefile的文件,找到一个则停止查找;
(2)如果找到,它会查找文件中的第一个目标,如上面例子中的add,并将这个文件作为最后一步生成的目标;
(3)如果add文件不存在,或是add所依赖的后面的“.o”文件的修改时间比add文件晚,那么系统就会执行后面所定义的命令来生成这个add文件;
(4)如果add所依赖的“.o”文件也不存在,那么make工具就会在当前文件中查找目标为“.o”文件依赖性,如果找到则根据相应的规则生成“.o”文件;
(5)如果makefile文件中列出的源文件都存在,make工具就会先生成“.o”文件,然后再用“.o”文件链接成可执行文件,否则将提示“找不到目标”错误。
make会一层一层地去解析文件的依赖关系,一步步地编译出各个目标,直到最终编译出第一个目标文件。在解析的过程中,如果出现错误,比如最后被依赖的文件没有找到,make工具就会直接退出并报错。而对于每条依赖后面所定义的命令的错误,make工具不会检查。
通常,makefile文件中还定义有clean目标,这是一个伪目标,可用来清除编译过程中生成的中间文件,例如清除上例中的内容:
clean:
rm main.o add.o add
在上述makefile文件中,clean没有被第一个目标add直接或间接依赖,那么它后面所定义的命令就不会被自动执行。不过,可以在make命令后跟clean目标作为参数来执行其后所定义的命令,即执行“make clean”命令,用于清除所有make过程中生成的目标,以便重新编译。
3、make的语法及参数选项
make命令主要有标志、宏定义和目标名三个可选参数。其标准形式为:
make[标志][宏定义][目标名]
主要标志选项及其含义如下表所示。
- -f FILE:读取FILE文件作为一个makefile.。
- -i:忽略命令执行返回的出错信息。
- -s:沉默模式,在执行之前不输出相应的命令行信息。
- -r:禁用内置隐含规则。
- -n:非执行模式,输出所有执行命令,但并不执行。
- -t:使用touch命令创建目标而不是根据依赖后面定义的命令来生成目标。
- -q:根据目标文件是否已经更新返回0或非0的状态信息。
- -p:输出所有宏定义和目标文件描述。
- -d:Debug模式,输出有关文件和检测时间的详细信息。
- -Cdir:在所有操作前切换到dir目录。
- -Idir:包含其他makefile文件时,利用该选项指定搜索目录。
- -h:打印帮助信息。
- -w:在处理makefile之前和之后,都显示makefile所在目录。
宏定义选项主要用于为makefile中已经定义的宏变量赋值,比如在下面这个GNUmakfile文件中,宏变量CC未定义。
- #This is an example for describing makefilie
- CC=
- add:main.o add.o
- $(CC) -o add main.o add.o
- main.o:main.c
- $(CC) -c main.c
- add.o:add.c
- $(CC) -c add.c
- clean:
- rm main.o add.o add
执行make命令时,我们可以通过参数为makefile文件内的宏变量CC赋值,通过宏变量CC来指定不同的编译器来编译源文件,如下图所示。
更严格的写法应该为宏定义选项将上双引号,即“CC=gcc”,尤其是在宏定义的右值有空格时。
目标名选项用来指定make命令要编译或执行的目标,并且允许同时指定多个目标,如上例中的“make clean”。操作时按照从左到右的顺序依次编译或执行各个目标。如果不指定目标名选项,则系统默认指向makefile文件中的第一个目标,如上例中的add。
二、makfile
1、剖析makefile
Makefile是make命令依赖并读取的配置文件,它描述了编译整个项目的详细规则,为了让make命令得以识别,makefile文件遵循一定的格式,它通常包含如下内容:
- 需要由make命令创建的目标对象(targets),通常是目标文件或者可执行文件;
- 要创建的目标对象所依赖的文件(dependent_files);
- 创建每个目标对象时需要运行的命令(command)。
它的格式为:
targets…:dependent_files …
(tab)command
…
例如,有两个文件分别为hello.c和hello.h,创建的目标体为hello.o,执行的命令为gcc编译指令“gcc–c hello.c”,那么对应的Makefile就可以写为:
#This is an example for describing makefile
hello.o:hello.c hello.h //要创建的目标对象所偏依赖的文件
gcc -c hello.c -o hello.o //创建目标对象要运行的命令
注意,在Makefile中的每个command前必须有制表符tab,否则在运行make命令时会出错。在Makefile文件所在目录执行make命令,使用make命令的格式为:make target,这样make命令就会自动解析Makefile文件并搜寻指定target后面的依赖文件dependent_files,当且仅当依赖文件都存在时才执行后面的command语句,否则需要先生成依赖文件方可。
2、说说makefile的文件名
默认情况下,make命令会在当前目录下按顺序寻找文件名为GNUMakefile、makefile、Makefile的文件,倘若找到一个则停止往后继续寻找,如果都未找到,则提示类似于“没有指明目标并且找不到makefile”的错误。在这个三个文件名中,最好是用Makefile这个文件名,因为这个名字首字母大写比较醒目,最好不要使用GNUMakefile作为文件名,因为它只被GNU的make识别,还有一些make只对首字母小写的makefile文件敏感,但是通常来说,大多数的make都支持Maklefile跟makefile这两个默认文件名。
我们也可以使用别的名字来命名makefile文件,比如“make.mips”、“make.arm”、“make.android”等,为了让make命令可以识别这些特殊的文件名,在执行make命令时需要加上“-f”参数,如:make -f make.mips。
3、makefile的包含
跟C/C++的“#include”一样,makefile文件可以使用include关键字将其他makefile包含进来,被包含的文件内容会原封不动地加载到当前makefile文件的包含位置。include关键词前面可以有一些空格字符,但是绝对不能以制表符tab键,因为制表符在makefile文件内通常用来标识一个命令的开始。include关键词后面指定要包含的文件名、路径或者变量,它们之间用一个或者多个空格隔开,举例来说,倘若你有几个makefile:a.make、b.make、c.make,还有一个makefile相关文件(定义一些宏变量或者宏变量的文件)make.rules,以及一个变量$(include_dir),那么下面语句:
include_dir:=/usr/include
include*.make $(include_dir)make.rules
等价于:
include a.make b.make c.make /usr/include/make.rules
make命令执行时,先将include关键字后面指定的相关文件内容加载进来并安置在当前位置,如果文件未指定绝对路径,make命令将先在当前目录寻找,倘若未找到,make命令一般还会去下面几个目录寻找:
(1)如果执行make命令时使用“-I”参数指定了某个目录,make命令会去该目下寻找相关文件;
(2)如果/usr/local/bin或/usr/include目录存在,make命令将去该目录下寻找相关文件。
make命令如果未找到include关键字指定的某个文件,将警告“没有那个文件或目录”等错误而停止运行,如果想让make命令不去理会这些相关文件是否存在而继续执行,可以在include前面加上一个减号“-”,它表示无论include加载过程中出现的错误都被忽略。
Linux下的Make与Makefile的更多相关文章
- linux下使用vscode和makefile搭建C++开发环境
最近在linux上跑一些开源库做学习用, 顺手就搭了一下vscode的c++开发环境, 这里分享一下vscode进行C++开发的基本环境结构. 1. 首先是编辑器, vscode直接官网下载的, 后期 ...
- linux下使用autoconf制作Makefile
第一步:常用工具安装:正所谓:"工欲善其事,必先利其器".我们常用的工具主要有GNU AutomakeGNU AutoconfGNU m4GNU Libtool1.查看自己系统中是 ...
- Linux下C++的通用Makefile与解析
本文给出万能Makefile的具体实现,以及对其中的关键点进行解析.所谓C++万能Makefile,即可编译链接所有的C++程序,而只需作很少的修改. 号称万能Makefile,一统江湖.我对原版的M ...
- linux下 几个常用makefile模板,亲测可用
一 生成动态链接库的模板: ####################### # Makefile ####################### # compile and lib parameter ...
- linux 下makefile
linux下c编程中makefile是必须会的,我刚开始学,将我对makefile的理解记录下来. 通常我们在windows下编写c程序,有各种ide工具为我们执行makefile工作但在linux下 ...
- Linux编程环境介绍(3) -- linux下的c/c++程序开发
目录: 1. 编辑器( Vi ) [vi 与 vim] vi(visual interface)是linux系统最重要的文本编辑器, 所有的 Unix-Like 系统都会内置vi文本编辑器. vim ...
- linux下的C语言程序设计
Linux程序设计基础知识 Linux下C语言编程环境概述 Linux下C语言编程常用的编辑器是vim或emacs,编译器一般用gcc,编译链接程序用make,跟踪调试一般使用gdb,项目管理用mak ...
- linux 下如何 makefile
本文目的: 尝试着把makefile讲解清楚.非原创,仅仅是学习笔记和备忘录之用. makefile 的目的和好处: 一个工程中的源文件不计数,其按类型.功能.模块分别放在若干个目录中,makefil ...
- Linux下MakeFile初探
make是linux下的编译命令,用于编译和生成Linux下的可执行文件.这个命令处理的对象是Makefile,makefile等.由于make的强大解析能力,makefile文件的编写也变得极为简单 ...
随机推荐
- 使用PostSharp在.NET平台上实现AOP
摘自:http://www.cnblogs.com/leoo2sk/archive/2010/11/30/aop-postsharp.html 本文首先介绍AOP(面向方面编程)的相关概念及理论,然后 ...
- SuperMap iClient如何使用WMTS地图服务
SuperMap iClient如何使用WMTS地图服务 什么是WMTS服务 WMTS,切片地图Web服务(Web Map Tile Service)当前版本是1.0.0.该服务符合 OGC(Open ...
- Quartz.NET 实现定时任务调度
Quartz.NET Quick Start Guide Welcome to the Quick Start Guide for Quartz.NET. As you read this guide ...
- 改动文件后缀的C语言实现
,其他配置项保持一致. step 3: 在"Old2New"目录下新建名为"update.bat"的批处理文件,该文件的内容为: ChangeS ...
- VS2015 经常不出现智能提示,代码颜色也没有了
重置下.开始菜单 -->所有程序-->Visual Studio 文件夹 --> Visual Studio Tools --> Developer Command Promp ...
- EHCache 在WEB项目的使用方法
EHCache 是一个纯java的在进程中的缓存,它具有下面特性:高速,简单,为Hibernate2.1充当可插入的缓存,最小的依赖性,全面的文档和測试.官方站点http://ehcache.sour ...
- Sublime Text 2中自定义代码模板
Sublime Text 2中自定义代码模板 2012-12-06 10:13 9921人阅读 评论(0) 收藏 举报 分类: 编辑器-Sublime Text 2(5) 版权声明:本文为博主原创 ...
- 跟着百度学PHP[17]-复习PDO的几个关键词
主要就是复习一下几个关键词.发现太久没有写又忘了.惭愧. final self static const
- OpenCV3.1.0+VS2013配置+Win10(64位)(转载)
OpenCV3.1.0+VS2013配置+Win10(64位) [环境]VS2013和MATLAB相互调用混合编程 Matlab 2016a和VS2013混合Dll编程步骤 更换了硬盘之后,重新配置了 ...
- 在pom.xml文件中自定义JDK版本+阿里maven镜像修改
在学习和开发中 总是修改jdk版本 但是这些配置文件又不想记 在此记录一下 方便查询: <build> <plugins> <!-- 指定jdk --> <p ...