Makefile

声明: 本篇博客的学习途径主要为以下网站和课堂讲解,发博客目的仅为学习使用,在该博客的基础上做了一定程序的简略和修改。
参考博客 :
原文链接:http://c.biancheng.net/makefile/

【注意】Makefile文件创建的时候,就叫Makefile,再shell中调用make命令,让Makefile文件自动执行。

什么是Makefile

Makefile 可以使得我们的项目工程的编译变得自动化,不需要每次都手动输入一堆源文件和参数,主要应用于Linux环境


【常见问题】
1)编译的时候需要链接库的的问题。拿C语言来说,编译的时候 gcc 只会默认链接一些基本的C语言标准库,很多源文件依赖的标准库都需要我们手动链接。

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

2)编译大的工程会花费很长的时间。
修改工程项目的源文件,每次修改后都要去重新编译

一个大的工程项目可不止有几个的源文件,里面的源文件个数可能有成百上千个。例如一个内核,或者是一个软件的源码包


【Makefile解决方法】:

  • 把要链接的库文件放在 Makefile 中,制定相应的规则和对应的链接顺序

这样只需要执行 make 命令,工程就会自动编译。每次想要编译工程的时候就执行 make ,省略掉手动编译中的参数选项和命令,非常的方便。

  • Makefile 支持多线程并发操作

极大的缩短我们的编译时间,并且当我们修改了源文件之后,编译整个工程的时候,make 命令只会编译我们修改过的文件,没有修改的文件不用重新编译


Makefile的内容

  1. 显式规则
    显式规则说明了,如何生成一个或多的的目标文件。这是由 Makefile 的书写者明显指出,要生成的文件文件的依赖文件生成的命令
  2. 隐晦规则
    由于我们的 make 命名有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写 Makefile,这是由 make 命令所支持的。
  3. 变量的定义
    在 Makefile 中我们要定义一系列的变量,变量一般都是字符串,这个有点像C语言中的宏,当 Makefile 被执行时,其中的变量都会被扩展到相应的引用位置上。
  4. 文件指示
    其包括了三个部分,
    ⚪ 一个是在一个 Makefile 中引用另一个 Makefile,就像C语言中的 include 一样;
    ⚪ 另一个是指根据某些情况指定 Makefile 中的有效部分,就像C语言中的预编译 #if 一样;
    ⚪ 还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。
  5. 注释
    Makefile 中只有行注释,和 UNIX 的 Shell 脚本一样,其注释是用“#”字符,这个就像 C/C++ 中的“//”一样。
    如果你要在你的 Makefile 中使用“#”字符,可以用反斜框进行转义,如:“#”。

Makefile的显式规则

规则主要是两个部分组成,分别是

  • 依赖的关系
  • 执行的命令
targets : prerequisites
    command

或者

targets : prerequisites; command
    command
  • targets目标文件(结果),可以是 Object File(一般称它为中间文件),也可以是可执行文件,还可以是一个标签;
  • prerequisites:是我们的依赖文件,要生成 targets 需要的文件或者是目标。可以是多个,也可以是没有;
  • command:make 需要执行的命令(任意的 shell 命令)。可以有多条命令,每一条命令占一行。

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


【举例】

test:test.c
    gcc -o test test.c
  • 其中 test 是的目标文件,也是我们的最终生成的可执行文件。
  • 依赖文件就是 test.c 源文件
  • 重建目标文件需要执行的操作是gcc -o test test.c

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


Makefile的工作流程

main:main.o test1.o test2.o
	gcc main.o test1.o test2.o -o main
main.o:main.c test.h
	gcc -c main.c -o main.o
test1.o:test1.c test.h
	gcc -c test1.c -o test1.o
test2.o:test2.c test.h
	gcc -c test2.c -o test2.o
	
.PHONY:clean    #.PHONY后面的target表示的也是一个伪造的target, 而不是真实存在的文件target,
clean:
    rm -rf *.o test #清除中间文件.o

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

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

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

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

【ps:红色的为清理掉的.o文件,记得清理中间文件】


Makefile变量的定义和使用

变 量 的 定 义 变量的定义
Makefile 文件中定义变量的基本语法如下:

变量的名称=值列表

调用变量的时候可以用 “$(VALUE_LIST)” 或者是 “${VALUE_LIST}” 来替换,这就是变量的引用。实例:

OBJ=main.o test.o test1.o test2.o
mytest:$(OBJ)
      gcc -o mytest $(OBJ)

这里用OBJ代替了main.o test.o test1.o test2.o,简化书写


变 量 的 赋 值 − − − S h e l l 变量的赋值 ---Shell Shell
知道了如何定义,下面我们来说一下 Makefile 的变量的四种基本赋值方式:

  • 简单赋值 ( := ) 编程语言中常规理解的赋值方式,只对当前语句的变量有效
  • 递归赋值 ( = ) 赋值语句可能影响多个变量,所有目标变量相关的其他变量都受影响。
  • 条件赋值 ( ?= ) 如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。
  • 追加赋值 ( += ) 原变量用空格隔开的方式追加一个新值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值