原文转载自: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”文件。

总之,编译时,我们通常先将源文件编译成目标文件,再对目标文件进行链接操作,程序便诞生了。

2make的工作原理

make工具最基本的功能是调用Makefile文件,通过Makefile文件来描述程编译的整个过程,不必每次敲gcc或g++等命令来完成编译工作。当然,Makefile文件需要按照一定的语法进行编写,说明如何编译各个源文件并链接生成可执行文件,以及各个文件之间的依赖关系。

如下图所示,演示了一个简单的make命令编译过程:

在该目录下,有三个文件,add.c main.c Makefile。内容如下:

  1. //add.c
  2. int add(int a, int b)
  3. {
  4. return(a+b);
  5. }
  1. //main.c
  2. #include"stdio.h"
  3. #include"stdlib.h"
  4. int add(int a,int b);
  5. int main(int argc, char**argv)
  6. {
  7. int a=atoi(argv[1]);
  8. int b=atoi(argv[2]);
  9. printf("%d+%d=%d\n",a,b,add(a,b));
  10. return 0;
  11. }

//Makefile

  1. #This is an example for describing makefile
  2. add:main.o add.o
  3. gcc -o add main.o add.o
  4. main.o:main.c
  5. gcc -c main.c
  6. add.o:add.c
  7. gcc -c add.c
  8. clean:
  9. 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过程中生成的目标,以便重新编译。

3make的语法及参数选项

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未定义。

  1. #This is an example for describing makefilie
  2. CC=
  3. add:main.o add.o
  4. $(CC) -o add main.o add.o
  5. main.o:main.c
  6. $(CC) -c main.c
  7. add.o:add.c
  8. $(CC) -c add.c
  9. clean:
  10. 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。

3makefile的包含

跟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的更多相关文章

  1. linux下使用vscode和makefile搭建C++开发环境

    最近在linux上跑一些开源库做学习用, 顺手就搭了一下vscode的c++开发环境, 这里分享一下vscode进行C++开发的基本环境结构. 1. 首先是编辑器, vscode直接官网下载的, 后期 ...

  2. linux下使用autoconf制作Makefile

    第一步:常用工具安装:正所谓:"工欲善其事,必先利其器".我们常用的工具主要有GNU AutomakeGNU AutoconfGNU m4GNU Libtool1.查看自己系统中是 ...

  3. Linux下C++的通用Makefile与解析

    本文给出万能Makefile的具体实现,以及对其中的关键点进行解析.所谓C++万能Makefile,即可编译链接所有的C++程序,而只需作很少的修改. 号称万能Makefile,一统江湖.我对原版的M ...

  4. linux下 几个常用makefile模板,亲测可用

    一 生成动态链接库的模板: ####################### # Makefile ####################### # compile and lib parameter ...

  5. linux 下makefile

    linux下c编程中makefile是必须会的,我刚开始学,将我对makefile的理解记录下来. 通常我们在windows下编写c程序,有各种ide工具为我们执行makefile工作但在linux下 ...

  6. Linux编程环境介绍(3) -- linux下的c/c++程序开发

    目录: 1. 编辑器( Vi ) [vi 与 vim] vi(visual interface)是linux系统最重要的文本编辑器, 所有的 Unix-Like 系统都会内置vi文本编辑器.  vim ...

  7. linux下的C语言程序设计

    Linux程序设计基础知识 Linux下C语言编程环境概述 Linux下C语言编程常用的编辑器是vim或emacs,编译器一般用gcc,编译链接程序用make,跟踪调试一般使用gdb,项目管理用mak ...

  8. linux 下如何 makefile

    本文目的: 尝试着把makefile讲解清楚.非原创,仅仅是学习笔记和备忘录之用. makefile 的目的和好处: 一个工程中的源文件不计数,其按类型.功能.模块分别放在若干个目录中,makefil ...

  9. Linux下MakeFile初探

    make是linux下的编译命令,用于编译和生成Linux下的可执行文件.这个命令处理的对象是Makefile,makefile等.由于make的强大解析能力,makefile文件的编写也变得极为简单 ...

随机推荐

  1. 使用PostSharp在.NET平台上实现AOP

    摘自:http://www.cnblogs.com/leoo2sk/archive/2010/11/30/aop-postsharp.html 本文首先介绍AOP(面向方面编程)的相关概念及理论,然后 ...

  2. SuperMap iClient如何使用WMTS地图服务

    SuperMap iClient如何使用WMTS地图服务 什么是WMTS服务 WMTS,切片地图Web服务(Web Map Tile Service)当前版本是1.0.0.该服务符合 OGC(Open ...

  3. Quartz.NET 实现定时任务调度

    Quartz.NET Quick Start Guide Welcome to the Quick Start Guide for Quartz.NET. As you read this guide ...

  4. 改动文件后缀的C语言实现

    ,其他配置项保持一致.         step 3: 在"Old2New"目录下新建名为"update.bat"的批处理文件,该文件的内容为: ChangeS ...

  5. VS2015 经常不出现智能提示,代码颜色也没有了

    重置下.开始菜单 -->所有程序-->Visual Studio 文件夹 --> Visual Studio Tools --> Developer Command Promp ...

  6. EHCache 在WEB项目的使用方法

    EHCache 是一个纯java的在进程中的缓存,它具有下面特性:高速,简单,为Hibernate2.1充当可插入的缓存,最小的依赖性,全面的文档和測试.官方站点http://ehcache.sour ...

  7. Sublime Text 2中自定义代码模板

    Sublime Text 2中自定义代码模板 2012-12-06 10:13 9921人阅读 评论(0) 收藏 举报  分类: 编辑器-Sublime Text 2(5)  版权声明:本文为博主原创 ...

  8. 跟着百度学PHP[17]-复习PDO的几个关键词

    主要就是复习一下几个关键词.发现太久没有写又忘了.惭愧. final self static const

  9. OpenCV3.1.0+VS2013配置+Win10(64位)(转载)

    OpenCV3.1.0+VS2013配置+Win10(64位) [环境]VS2013和MATLAB相互调用混合编程 Matlab 2016a和VS2013混合Dll编程步骤 更换了硬盘之后,重新配置了 ...

  10. 在pom.xml文件中自定义JDK版本+阿里maven镜像修改

    在学习和开发中 总是修改jdk版本 但是这些配置文件又不想记 在此记录一下 方便查询: <build> <plugins> <!-- 指定jdk --> <p ...