我写了一起 Makefile


 陈皓

概述
——

什么是makefile?也许非常多Winodws的程序猿都不知道这个东西,由于那些Windows的IDE都为你做了这个工作。但我认为要作一个好的和professional的程序猿,makefile还是要懂。这就好像如今有这么多的HTML的编辑器。但假设你想成为一个专业人士,你还是要了解HTML的标识的含义。

特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个側面说明了一个人是否具备完毕大型project的能力。

由于,makefile关系到了整个project的编译规则。

一个project中的源文件不计数。其按类型、功能、模块分别放在若干个文件夹中,makefile定义了一系列的规则来指定,哪些文件须要先编译。哪些文件须要后编译。哪些文件须要又一次编译,甚至于进行更复杂的功能操作,由于makefile就像一个Shell脚本一样,当中也能够运行操作系统的命令。

makefile带来的优点就是——“自己主动化编译”,一旦写好,仅仅须要一个make命令,整个project全然自己主动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说。大多数的IDE都有这个命令。比方:Delphi的make,Visual C++的nmake。Linux下GNU的make。可见,makefile都成为了一种在project方面的编译方法。

如今讲述怎样写makefile的文章比較少,这是我想写这篇文章的原因。

当然,不同产商的make各不同样,也有不同的语法,但其本质都是在“文件依赖性”上做文章,这里,我仅对GNU的make进行讲述。我的环境是RedHat Linux 8.0。make的版本号是3.80。

必竟,这个make是应用最为广泛的,也是用得最多的。并且其还是最遵循于IEEE 1003.2-1992 标准的(POSIX.2)。

在这篇文档中,将以C/C++的源代码作为我们基础,所以必定涉及一些关于C/C++的编译的知识,相关于这方面的内容,还请各位查看相关的编译器的文档。这里所默认的编译器是UNIX下的GCC和CC。

关于程序的编译和链接
——————————

在此。我想多说关于程序编译的一些规范和方法。一般来说。不管是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件。UNIX下是 .o 文件,即 Object File,这个动作叫做编译(compile)。

然后再把大量的Object File合成运行文件。这个动作叫作链接(link)。

编译时,编译器须要的是语法的正确,函数与变量的声明的正确。对于后者,一般是你须要告诉编译器头文件的所在位置(头文件里应该仅仅是声明,而定义应该放在C/C++文件里)。仅仅要全部的语法正确。编译器就能够编译出中间目标文件。一般来说,每一个源文件都应该相应于一个中间目标文件(O文件或是OBJ文件)。

链接时。主要是链接函数和全局变量。所以。我们能够使用这些中间目标文件(O文件或是OBJ文件)来链接我们的应用程序。链接器并无论函数所在的源文件。仅仅管函数的中间目标文件(Object File),在大多数时候。因为源文件太多。编译生成的中间目标文件太多,而在链接时须要明显地指出中间目标文件名称,这对于编译非常不方便,所以,我们要给中间目标文件打个包,在Windows下这样的包叫“库文件”(Library File),也就是 .lib 文件,在UNIX下,是Archive File,也就是 .a 文件。

总结一下。源文件首先会生成中间目标文件,再由中间目标文件生成运行文件。在编译时,编译器仅仅检測程序语法,和函数、变量是否被声明。假设函数未被声明,编译器会给出一个警告,但能够生成Object File。

而在链接程序时。链接器会在全部的Object File中找寻函数的实现。假设找不到,那到就会报链接错误码(Linker Error)。在VC下。这样的错误通常是:Link 2001错误,意思说是说。链接器未能找到函数的实现。你须要指定函数的Object File.

好,言归正传,GNU的make有很多的内容,闲言少叙,还是让我们開始吧。

Makefile 介绍
———————

make命令运行时,须要一个 Makefile 文件,以告诉make命令须要怎么样的去编译和链接程序。

首先,我们用一个演示样例来说明Makefile的书写规则。以便给大家一个感兴认识。这个演示样例来源于GNU的make使用手冊,在这个演示样例中,我们的project有8个C文件,和3个头文件。我们要写一个Makefile来告诉make命令怎样编译和链接这几个文件。我们的规则是:
    1)假设这个project没有编译过,那么我们的全部C文件都要编译并被链接。
    2)假设这个project的某几个C文件被改动。那么我们仅仅编译被改动的C文件,并链接目标程序。
    3)假设这个project的头文件被改变了,那么我们须要编译引用了这几个头文件的C文件。并链接目标程序。

仅仅要我们的Makefile写得够好,全部的这一切。我们仅仅用一个make命令就能够完毕,make命令会自己主动智能地依据当前的文件改动的情况来确定哪些文件须要重编译,从而自己编译所须要的文件和链接目标程序。

一、Makefile的规则

在讲述这个Makefile之前。还是让我们先来粗略地看一看Makefile的规则。

target ... : prerequisites ...
            command
            ...
            ...

target也就是一个目标文件,能够是Object File,也能够是运行文件。还能够是一个标签(Label)。对于标签这样的特性,在兴许的“伪目标”章节中会有叙述。

prerequisites就是,要生成那个target所须要的文件或是目标。

command也就是make须要运行的命令。(随意的Shell命令)

这是一个文件的依赖关系。也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。

说白一点就是说。prerequisites中假设有一个以上的文件比target文件要新的话,command所定义的命令就会被运行。

这就是Makefile的规则。也就是Makefile中最核心的内容。

说究竟,Makefile的东西就是这样一点。好像我的这篇文档也该结束了。呵呵。还不尽然,这是Makefile的主线和核心,但要写好一个Makefile还不够,我会以后面一点一点地结合我的工作经验给你慢慢到来。内容还多着呢。

:)

二、一个演示样例

正如前面所说的,假设一个project有3个头文件,和8个C文件。我们为了完毕前面所述的那三个规则,我们的Makefile应该是以下的这个样子的。

edit : main.o kbd.o command.o display.o /
           insert.o search.o files.o utils.o
            cc -o edit main.o kbd.o command.o display.o /
                       insert.o search.o files.o utils.o

main.o : main.c defs.h
            cc -c main.c
    kbd.o : kbd.c defs.h command.h
            cc -c kbd.c
    command.o : command.c defs.h command.h
            cc -c command.c
    display.o : display.c defs.h buffer.h
            cc -c display.c
    insert.o : insert.c defs.h buffer.h
            cc -c insert.c
    search.o : search.c defs.h buffer.h
            cc -c search.c
    files.o : files.c defs.h buffer.h command.h
            cc -c files.c
    utils.o : utils.c defs.h
            cc -c utils.c
    clean :
            rm edit main.o kbd.o command.o display.o /
               insert.o search.o files.o utils.o

反斜杠(/)是换行符的意思。

这样比較便于Makefile的易读。

我们能够把这个内容保存在文件为“Makefile”或“makefile”的文件里。然后在该文件夹下直接输入命令“make”就能够生成运行文件edit。假设要删除运行文件和全部的中间目标文件。那么,仅仅要简单地运行一下“make clean”就能够了。

在这个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(一)的更多相关文章

  1. [编译] 7、在Linux下搭建安卓APP的开发烧写环境(makefile版-gradle版)—— 在Linux上用命令行+VIM开发安卓APP

    April 18, 2020 6:54 AM - BEAUTIFULZZZZ 目录 0 前言 1 gradle 安装配置 1.1 卸载系统默认装的gradle 1.2 下载对应版本的二进制文件 1.3 ...

  2. linux学习 建立静态库,动态库,写简单的makefile

    建立静态库 建立四个文件 bin(可运行文件),lib(库),include(头文件),src(放源文件) 这里的起的库明为add 在src文件里运行 1)gcc -c add.c //编译add.c ...

  3. [编译] 5、在Linux下搭建安卓APP的开发烧写环境(makefile版)—— 在Linux上用命令行+VIM开发安卓APP

    星期三, 19. 九月 2018 02:19上午 - BEAUTIFULZZZZ 0)前言 本文不讨论用IDE和文本编辑器开发的优劣,是基于以下两点考虑去尝试用命令行编译安卓APP的: 了解安卓APP ...

  4. [编译] 4、在Linux下搭建nRF51822的开发烧写环境(makefile版)

    星期日, 09. 九月 2018 07:51下午 - beautifulzzzz 1.安装步骤 1) 从GNU Arm Embedded Toolchain官网下载最新的gcc-arm工具链,写文章时 ...

  5. [编译] 3、在Linux下搭建51单片机的开发烧写环境(makefile版)

    星期二, 10. 七月 2018 01:01上午 - beautifulzzzz 一.SDCC(Small Device C Compiler)编译环境搭建 SDCC是一个小型设备的C语言编译器,该编 ...

  6. [编译] 8、在Linux下搭建 stm8 单片机的开发烧写环境(makefile版)

    目录 一.SDCC(Small Device C Compiler)编译环境搭建 1.1.下载 1.2.编译 1.3.测试 二.Hex2Bin+命令行烧写工具配置使用 2.1.下载工具安装配置 2.2 ...

  7. 写的一个Makefile

    #========================================================================= # # MAKE FILE FOR ROCKY # ...

  8. 在Linux下搭建nRF51822的开发烧写环境(makefile版)

    http://www.qingpingshan.com/m/view.php?aid=394836

  9. 怎么写makefile?(转)

    跟我一起写 Makefile 陈皓 第一章.概述 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和 pr ...

随机推荐

  1. 【iOS开发-31】UITabBar背景、icon图标颜色、被选中背景设置以及隐藏UITabBar的两种方式

    一.对UITabBar背景和icon图标的一些设置 (1)由于直接给UITabBar设置的背景颜色显示的不纯.半透明的感觉,所以,有时候我们能够直接利用纯色的图片作为背景达到想要的效果. (2)给ic ...

  2. 编程语言性能游戏排行榜,C/C++第一ATS第二JAVA第三

    编程语言性能游戏排行榜,C/C++第一ATS第二JAVA第三 编程语言性能游戏排行榜,C/C++第一ATS第二JAVA第三

  3. C++中的常对象和常对象成员

    常对象 常对象必须在定义对象时就指定对象为常对象. 常对象中的数据成员为常变量且必须要有初始值,如 Time const t1(12,34,36); //定义t1为常对象 这样的话,在所有的场合中,对 ...

  4. LeetCode——Populating Next Right Pointers in Each Node II

    Follow up for problem "Populating Next Right Pointers in Each Node". What if the given tre ...

  5. DTD学习笔记

    1.  DTD基本介绍 xml文件分为两种类型,一个是在好形式,这是well-formed,还有一个合法有效,这是valid. XML文件遵循-called"好形式"各种语法规则要 ...

  6. [转]PHP 5.2~5.6 对照以及功能具体解释

    [分享]PHP 5.2~5.6 对照以及功能具体解释 作者:流水理鱼wwek 来源:http://www.iamle.com/archives/1530.html 截至眼下(2014.2), PHP ...

  7. Linux与JVM的内存关系分析(转)

    引言 在一些物理内存为8g的服务器上,主要运行一个Java服务,系统内存分配如下:Java服务的JVM堆大小设置为6g,一个监控进程占用大约600m,Linux自身使用大约800m.从表面上,物理内存 ...

  8. Note:This element neither has attached source nor attached Javadoc

    在用Eclipse编写程序时,发现把鼠标放到类名上时出现标题的提示 解决方法: 右击项目,选择 properties –> Java Build Path –> Libraries,如图 ...

  9. 用VBA宏从一个工作薄复制内容到另一个工作薄

    我们项目管理有两个工作薄,一个里面有多个表,每天建一个,记录当天项目,另一个工作薄,有多个表,其中一个是所有项目汇总. 以前都是第一个工作薄一个表做完,再复制粘贴到第二个工作薄的汇总表中. 写了个VB ...

  10. hdu1495之经典搜索

    非常可乐 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...