前情提要

上一篇《编译入门》讲了变成的基本问题。如果源文件只有一个,就如之前的例子,那么用gcc命令直接编译就可以了。但是很多实际的工程用到的源文件都是相当多的,这时候用命令一个个编译是很不现实的。所以需要一个自动化编译系统来做这件事情,那就是make和makefile了。

make和makefile介绍

一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile 定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile 就像一个 Shell 脚本一样,其中也可以执行操作系统的命令。

make 是一个命令工具,是一个解释makefile 中指令的命令工具,一般来说,大多数的 IDE 都有这个命令,比如:Delphi 的make,Visual C++的 nmake,Linux 下 GNU 的 make。可见,makefile 都成为了一种在工程方面的编译方法。

make和makefile的示例:它们是如何工作的

我们的工程有 8 个 C 文件,和 3 个头文件,我们要写一个 Makefile 来告诉 make 命令如何编译和链接这几个文件。我们要写一个 Makefile 来告诉 make 命令如何编译和链接这几个文件。我们的规则是:

1. 如果这个工程没有编译过,那么我们的所有 C 文件都要编译并被链接。

2. 如果这个工程的某几个 C 文件被修改,那么我们只编译被修改的 C 文件,并链接目标程序。

3. 如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的 C 文件,并链接目标程序。

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

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

target 也就是一个目标文件,可以是 Object File,也可以是执行文件。还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”章节中会有叙述。

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

command 也就是 make 需要执行的命令。(任意的 Shell 命令)

这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比 target 文件要新的话, command 所定义的命令就会被执行。

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

以下是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”的文件中,然后在该目录下直接输入命令“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 中定义不用的编译或是和编译无关的命令,比如程序的打包,程序的备份,等等。

上面是makfile的核心,但还有很多很多其他的细节,慢慢道来。



参考文献:
跟我一起写makefile

makefile笔记1 - 初识makefile的更多相关文章

  1. 第2课 - 初识makefile的结构

    第2课 - 初识makefile的结构 1. makefile 的意义 (1)makefile 用于定义源文件之间的依赖关系 (在阅读开源软件源码时,可通过Makefile掌握源码中各个文件之间的关系 ...

  2. Makefile笔记之二------make的递归执行

    1.make的递归过程指的是: 在Makefile中使用"make"作为一个命令来执行本身或者其它makefile文件的过程. 2.递归的意义: 当前目录下存在一个"su ...

  3. C++学习笔记24:makefile文件

    makefile make命令:负责c/c++程序编译与链接 make根据指定命令进行建构 建构规则文件:GNUmakefile , makefile,Makefile makefile 文件格式 m ...

  4. Makefile笔记

    一个简单的Makefile描述规则组成: TARGET...:PREREQUISITES... COMMANDS... ... target:规则的目标.通常是程序中间或者最后要生成的文件名,也可以是 ...

  5. makefile笔记4 - makefile命令

    每条规则中的命令和操作系统 Shell 的命令行是一致的. make 会一按顺序一条一条的执行命令,每条命令的开头必须以[Tab]键开头,除非,命令是紧跟在依赖规则后面的分号后的. 在命令行之间中的空 ...

  6. 工程管理之makefile与自动创建makefile文件过程

    (风雪之隅 http://www.laruence.com/2009/11/18/1154.html) Linux Makefile自动编译和链接使用的环境 想知道到Linux Makefile系统的 ...

  7. makefile中引用其他makefile方法

    在Makefile中引用其他Makefile文件的方法是,使用inclue   filename.mk

  8. Storm学习笔记 - Storm初识

    Storm学习笔记 - Storm初识 1. Strom是什么? Storm是一个开源免费的分布式计算框架,可以实时处理大量的数据流. 2. Storm的特点 高性能,低延迟. 分布式:可解决数据量大 ...

  9. LevelDB学习笔记 (1):初识LevelDB

    LevelDB学习笔记 (1):初识LevelDB 1. 写在前面 1.1 什么是levelDB LevelDB就是一个由Google开源的高效的单机Key/Value存储系统,该存储系统提供了Key ...

随机推荐

  1. python 学习笔记 5 ----> dive into python 3

    字符串 文本:屏幕上显示的字符或者其他的记号 计算机认识的东西:位(bit)和字节(byte) 文本的本质:某种字符编码方式保存的内容. 字符编码:一种映射(显示的内容  ----> 内存.磁盘 ...

  2. Django-models & QuerySet API

    django中配置mysql数据库 1,首先配置settings.py. 一是在INSTALLED_APPS里面加入app名称: 二是配置数据库相关信息 INSTALLED_APPS = [ 'dja ...

  3. layui 根据根据后台数据动态创建下拉框并同时默认选中

        第一步 form表单里写好一个下拉框 <div class="layui-form-item"> <label class="layui-for ...

  4. linux生成公钥私钥并上传到服务器上实现免密登陆

    1. 生成密钥对 # -t 指定加密算法: -b 指定生成的密钥长度: -C 一句话,一般都填邮箱地址. # 更多参数说明可以在终端输入:ssh-keygen --help 查看 ssh-keygen ...

  5. 『超分辨率重建』从SRCNN到WDSR

    超分辨率重建技术(Super-Resolution)是指从观测到的低分辨率图像重建出相应的高分辨率图像.SR可分为两类:    1. 从多张低分辨率图像重建出高分辨率图像    2. 从单张低分辨率图 ...

  6. 使用 HttpClient 进行文件上传

    1.使用 AddPart 方法 public static void upload(String authorization,String baseUrl,String filePath,String ...

  7. es6语法在ios低版本的支持性

    let.const.箭头函数在ios的某些版本不支持,会引起报错 参考:https://blog.csdn.net/cx091/article/details/79805369 https://can ...

  8. WSGI 的简单理解

    WSGI是Web Server Gateway Interface(Web服务器网关接口)的缩写.其位于web应用程序与web服务器之间.python标准库提供的独立WSGI服务器称为wsgiref. ...

  9. vue手把手教你实现走马灯商品左右轮播图

    <template> <div> <div class="back_add"> <div class="threeImg&quo ...

  10. ubuntu nginx ssl 证书配置

      前几天自己用 egg.js 写了个 api 接口,然后把它部署到服务器上.服务器是ubuntu 16.04 + nginx:因为要用到https,然后今天实践了一下如何配置https. 关于htt ...