1. 什么是 Makefile

Makefile 文件描述了 Linux 系统下 C/C++ 工程的编译规则,它用来自动化编译 C/C++ 项目。一旦写编写好 Makefile 文件,只需要一个 make 命令,整个工程就开始自动编译,不再需要手动执行 GCC 命令。一个中大型 C/C++ 工程的源文件有成百上千个,它们按照功能、模块、类型分别放在不同的目录中,Makefile 文件定义了一系列规则,指明了源文件的编译顺序、依赖关系、是否需要重新编译等。

Makefile 可以简单的认为是一个工程文件的编译规则,描述了整个工程的编译和链接等规则。其中包含了那些文件需要编译,那些文件不需要编译,那些文件需要先编译,那些文件需要后编译,那些文件需要重建等等。编译整个工程需要涉及到的,在 Makefile 中都可以进行描述。换句话说,Makefile 可以使得我们的项目工程的编译变得自动化,不需要每次都手动输入一堆源文件和参数。

2. 为什么要使用 Makefile

Linux 下的 C 语言开发为例来具体说明一下,多文件编译生成一个文件,编译的命令如下所示:

gcc -o outfile name1.c name2.c ...

outfile 要生成的可执行程序的名字,nameN.c 是源文件的名字。这是我们在 Linux 下使用 gcc 编译器编译 C 文件的例子。如果我们遇到的源文件的数量不是很多的话,可以选择这样的编译方式。如果源文件非常的多的话,就会遇到下面的这些问题。

2.1 编译的时候需要链接库的的问题

下面列举了一些需要我们手动链接的标准库:

  • name1.c 用到了数学计算库 math 中的函数,我们得手动添加参数 -lm
  • name4.c 用到了小型数据库 SQLite 中的函数,我们得手动添加参数 -lsqlite3
  • name5.c 使用到了线程,我们需要去手动添加参数 -lpthread

因为有很多的文件,还要去链接很多的第三方库。所以在编译的时候命令会很长,并且在编译的时候我们可能会涉及到文件链接的顺序问题,所以手动编译会很麻烦。

如果我们学会使用 Makefile 就不一样了,它会彻底简化编译的操作。把要链接的库文件放在 Makefile 中,制定相应的规则和对应的链接顺序。这样只需要执行 make 命令,工程就会自动编译,省略掉手动编译中的参数选项和命令,非常的方便。

2.2 编译大的工程会花费很长的时间

Makefile 支持多线程并发操作,会极大的缩短我们的编译时间,并且当我们修改了源文件之后,编译整个工程的时候,make 命令只会编译我们修改过的文件,没有修改的文件不用重新编译,也极大的解决了我们耗费时间的问题。

并且文件中的 Makefile 只需要完成一次,一般我们只要不增加或者是删除工程中的文件,Makefile 基本上不用去修改,编译时只用一个 make 命令。为我们提供了极大的便利,很大程度上提高编译的效率。

3. Makefile 规则

它的规则主要是两个部分组成,分别是依赖的关系和执行的命令,其结构如下所示:

targets : prerequisitescommand

或者

targets : prerequisites; commandcommand

相关说明如下:

  • targets:规则的目标,是必须要有的,可以是 Object File(一般称它为中间文件),也可以是可执行文件,还可以是一个标签;
  • prerequisites:是我们的依赖文件,要生成 targets 需要的文件或者是目标。可以是多个,用空格隔开,也可以是没有;
  • commandmake 需要执行的命令(任意的 shell 命令)。可以有多条命令,每一条命令占一行;

如果 command 太长, 可以用 \ 作为换行符。

注意:我们的目标和依赖文件之间要使用冒号分隔开,命令的开始一定要使用 Tab 键,不能使用空格键。

简单的概括一下Makefile 中的内容,它主要包含有五个部分,分别是:

3.1 显式规则

显式规则说明了,如何生成一个或多的的目标文件。这是由 Makefile 的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。

3.2 隐晦规则

由于我们的 make 命名有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写 Makefile,这是由 make 命令所支持的。

3.3 变量的定义

Makefile 中我们要定义一系列的变量,变量一般都是字符串,这个有点像 C 语言中的宏,当 Makefile 被执行时,其中的变量都会被扩展到相应的引用位置上。

3.4 文件指示

其包括了三个部分,一个是在一个 Makefile 中引用另一个 Makefile,就像 C 语言中的 include 一样;另一个是指根据某些情况指定 Makefile 中的有效部分,就像 C 语言中的预编译 #if 一样;还有就是定义一个多行的命令。

3.5 注释

Makefile 中只有行注释,和 UNIXShell 脚本一样,其注释是用 # 字符,如果你要在你的 Makefile 中使用 # 字符,可以用反斜框进行转义,如: \#

3.6 规则中的通配符

  • * 表示任意一个或多个字符
  • ? 表示任意一个字符
  • [...] [abcd] 表示 a,b,c,d中任意一个字符, [^abcd]表示除 a,b,c,d 以外的字符, [0-9] 表示 0~9中任意一个数字
  • ~ 表示用户的 home 目录

4. Makefile 示例

main.cpp 代码:

#include <iostream>int main()
{std::cout << "hello,world" << std::endl;return 0;
}

通过下面的例子来具体使用一下 Makefile 的规则,Makefile文件中添代码如下:

main: main.cppg++ main.cpp -o main

其中 main 是的目标文件,也是我们的最终生成的可执行文件。依赖文件就是 main.cpp 源文件,重建目标文件需要执行的操作是 g++ main.cpp -o main。这就是 Makefile 的基本的语法规则的使用。

使用 Makefile 的方式:首先需要编写好 Makefile 文件,然后在 shell 中执行 make 命令,程序就会自动执行,得到最终的目标文件。

wohu@ubuntu:~/cpp/demo$ ls
main.cpp  `Makefile`
wohu@ubuntu:~/cpp/demo$ make
g++ main.cpp -o main
wohu@ubuntu:~/cpp/demo$ ls
main  main.cpp  `Makefile`
wohu@ubuntu:~/cpp/demo$ ./main
hello,world
wohu@ubuntu:~/cpp/demo$

如果命令的开始使用的是空格键,那么会报错

Makefile:2: *** missing separator.  Stop.

Makefile:2 表示第二行错误,应该以 Tab 开始。

5. Makefile 流程

当我们在执行 make 条命令的时候,make 就会去当前文件下找要执行的编译规则,也就是 Makefile 文件。我们编写 Makefile 的时可以使用的文件的名称 GNUMakefilemakefileMakefilemake 执行时回去寻找 Makefile 文件,找文件的顺序也是这样的。

推荐使用 Makefile(一般在工程中都这么写,大写的会比较的规范)。如果文件不存在,make 就会给我们报错,提示:

make: *** No targets specified and no `Makefile` found.  Stop.

Makefile 中添加下面的代码:

main: main.o   name.o greeting.og++ main.o name.o greeting.o -o main
main.o: main.cppg++ -c main.cpp -o main.o
name.o: name.cppg++ -c name.cpp -o name.o
greeting.o: greeting.cppg++ -c greeting.cpp -o greeting.o

在我们编译项目文件的时候,默认情况下,make 执行的是 Makefile 中的第一规则(Makefile 中出现的第一个依赖关系),此规则的第一目标称之为“最终目标”或者是“终极目标”。

shell 命令行执行的 make 命令,就可以得到可执行文件 main 和中间文件 main.oname.ogreeting.omain 就是我们要生成的最终文件。

通过 Makefile 我们可以发现,目标 mainMakefile 中是第一个目标,因此它就是 make 的终极目标,当修改过任何文件后,执行 make 将会重建终极目标 main

它的具体工作顺序是:当在 shell 提示符下输入 make 命令以后。 make 读取当前目录下的 Makefile 文件,并将 Makefile 文件中的第一个目标作为其执行的“终极目标”,开始处理第一个规则(终极目标所在的规则)。

在我们的例子中,第一个规则就是目标 main 所在的规则。规则描述了 main 的依赖关系,并定义了链接 .o 文件生成目标 main 的命令;make 在执行这个规则所定义的命令之前,首先处理目标 main 的所有的依赖文件(例子中的那些 .o 文件)的更新规则(以这些 .o 文件为目标的规则)。

对这些 .o 文件为目标的规则处理有下列三种情况:

  • 目标 .o 文件不存在,使用其描述规则创建它;
  • 目标 .o 文件存在,目标 .o 文件所依赖的 “.cpp” 源文件 “.h” 文件中的任何一个比目标 .o 文件“更新”(在上一次 make 之后被修改),则根据规则重新编译生成它;
  • 目标 .o 文件存在,目标 .o 文件比它的任何一个依赖文件(".c" 源文件、".h" 文件)“更新”(它的依赖文件在上一次 make 之后没有被修改),则什么也不做;

通过上面的更新规则我们可以了解到中间文件的作用,也就是编译时生成的 .o 文件。作用是检查某个源文件是不是进行过修改,最终目标文件是不是需要重建。

我们执行 make 命令时,只有修改过的源文件或者是不存在的目标文件会进行重建,而那些没有改变的文件不用重新编译,这样在很大程度上节省时间,提高编程效率。

浅显易懂 Makefile 入门 (01)— 什么是Makefile、为什么要用Makefile、Makefile规则、Makefile流程如何实现增量编译相关推荐

  1. 浅显易懂 Makefile 入门 (12)— Makefile 常见的错误信息

    1. 常见的错误信息 make 执行过程中所产生错误并不都是致命的,特别是在命令行之前存在 -.或者 make 使用 -k 选项执行时. make 执行过程的致命错误都带有前缀字符串 ***.错误信息 ...

  2. Linux加减程序编写,Makefile 入门(加减乘除实现)

    Makefile 入门(加减乘除实现) 准备 使用任意Linux发行版即可,本文使用WSL Ubuntu. 开始之前,需要安装必要的工具: sudo apt install make g++ 开始 1 ...

  3. Makefile入门: 用最美味的例子

    目录 入门 为什么存在 Makefile? Make 有哪些替代方案? 运行示例 生成文件语法 初学者示例 变量 目标 全部目标 多个目标 自动变量和通配符 * 通配符 % 通配符 自动变量 花式规则 ...

  4. Makefile入门一、helloworld

    Makefile入门一.helloworld 1.了解gcc从源码到可执行文件的步骤 2.Makefile的helloworld 3.提到Makefile不得不了解gcc命令 1.了解gcc从源码到可 ...

  5. Makefile 入门教程

    1.Makefile简介 Makefile 定义了软件开发过程中,项目工程编译链.链接的方法和规则. 由 IDE 自动生成或者开发者手动书写. Unix(MAC OS.Solaris)和Linux(R ...

  6. MakeFile入门详解

          makefile很重要 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和profession ...

  7. linux内核源码只有makefile文件没有c文件,linux内核代码的编写初步以及makefile的配置...

    在linux内核代码开发中,头文件不能包含标准C头文件,只能采用GNC标准 而且内核开发中没有main函数,只有init 和 exit ,这是每个内核模块中必须要包含的函数模块. 在GNU C标准中, ...

  8. 【网络爬虫入门01】应用Requests和BeautifulSoup联手打造的第一条网络爬虫

    [网络爬虫入门01]应用Requests和BeautifulSoup联手打造的第一条网络爬虫 广东职业技术学院 欧浩源 2017-10-14  1.引言 在数据量爆发式增长的大数据时代,网络与用户的沟 ...

  9. java编程菜鸟入门01

    写在前面: 此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 传送门: java编程菜鸟入门01 java对象和类 jav ...

最新文章

  1. R计算回归模型Mallows’ Cp指标
  2. 结构体数组与指针习题
  3. 美国公司欲联合大电脑商阻止绿坝推广
  4. Spark SQL之queryExecution运行流程解析Logical Plan(三)
  5. luogu P4240 毒瘤之神的考验(莫比乌斯反演+递推前缀和+数论分块)
  6. TCP/IP 协议栈 -- 编写UDP客户端注意细节
  7. mysql双主多从高可用配置_双主MySQL+keepalived高可用配置
  8. 正在迷茫的你,为什么不考虑这份工作呢?
  9. 模版 ----- 一维指数型枚举 排列型枚举 组合型枚举
  10. 修改Windows系统管理员Administrator的名称
  11. 《客户端性能测试基本流程》
  12. 【SpringCloud】-- SpringCloud简介
  13. C#监控设备(PLC)状态仿真模拟器
  14. Flink 统计页面点击量
  15. 第三代USRP 产品对比
  16. 牛客入门编程—金字塔图案
  17. Windows 之 win SMB(smb) 功能的开启设置和使用的简单说明
  18. 多少秒算长镜头_长镜头的作用
  19. linux 批量 添加后缀名,Linux下批量修改后缀名(示例代码)
  20. 图像分割中阈值的自动选取的研究及其算法实现

热门文章

  1. 通过anaconda2安装python2.7和安装pytorch
  2. 2022-2028年中国体育赛事产业深度调研及投资前景预测报告
  3. Jquery DIV滚动至浏览器顶部后固定不动代码
  4. 2022-2028年中国工业节能行业深度调研及投资前景预测报告
  5. 2022-2028年中国内衣行业研究及前瞻分析报告
  6. Go 学习笔记(76)— Go 标准库 net/http 创建客户端(发送 GET、POST 请求)
  7. debian10 raid5+lvm
  8. 文件句柄和文件描述符的区别和理解指针
  9. 一个框架看懂优化算法之异同 SGD/AdaGrad/Adam
  10. tensorflow 学习笔记-- tf.reduce_max、tf.sequence_mask