Makefile编译实战

简介: Makefile编译实战

makefile 原理


Makefile 其实只是一个指示 make 程序(有时称之为 make 命令)如何为我们工作的命令文件,我们说 Makefile 其实是在说 make,这一点要有很清晰的认识。而对于我们的项目来说,Makefile 是指linux下软件项目的编译环境。


Makefile 概念

一个是目标(target),另一个就是依赖(dependency)。目标就是指要干什么,或说运行 make 后生成什么,而依赖是告诉 make 如何去做以实现目标。在 Makefile 中,目标和依赖是通过规则(rule)来表达的。 驾驭 Makefile,最为重要的是要学会采用目标和依赖关系来思考所需解决的问题。


目标: 目标放在‘:’的前面,其名字可以是由字母和下划线‘_’组成; 一个 Makefile 中可以定义多个目标。第一个目标是默认目标,这“第一个”目标也称之为默认目标(和是不是al没有关系)。


命令: 要使 make 不打印出命令,命令前加了一个‘@’。 这一符号告诉 make,在运行时不要将这一行命令显示出来;


依赖:依赖目标在 Makefile 中又被称之为先决条件。出现这种目标依赖关系时,make工具会按从左到右的先后顺序先构建规则中所依赖的每一个目标(目标和‘:’ 后的第一个元素)。

Makefile 三要素

c8bf3fb6728e1cb6895da5c1f89e527e_2e53b0b3d3f44b23bb70fc23920e5cca.png


工作原理

规则


什么是规则

一个规则是由目标(targets)、先决条件(prerequisites)以及命令(commands)所组成的;


目标和先决条件之间表达的就是依赖关系(dependency),这种依赖关系指明在构建目标之前,必须保证先决条件先满足(或构建)。而先决条件可以是其它的目标,当先决条件是目标时,其必须先被构建出来。还有就是一个规则中目标可以有多个,当存在多个目标,且这一规则是 Makefile 中的第一个规则时,如果我们运行 make 命令不带任何目标,那么规则中的第一个目标将被视为是缺省目标


代码的执行顺序和先决条件的先后顺序有关,先决条件在左边的限制性。


规则作用

规则的功能就是指明 make 什么时候以及如何来为我们重新创建目标,


规则table 占位

每行的明亮 前面必须只有 TAB(即你键盘上的 TAB键),且至少有一个 TAB,而不能用空格代替;


伪目标

在现实中也难免存在所定义的目标与所存在的文件是同名的,采用 Makefile如何处理这种情况呢?Makefile 中的假目标(phony target)可以解决这个问题.

采用.PHONY 关键字声明一个目标后,make 并不会将其当作一个文件来处理,而只是当作一个概念上的目标。对于假目标,我们可以想像的是由于并不与文件关联,所以每一次 make 这个假目标时,其所在的规则中的命令都会被执行。


假目标可以采用.PHONY: 关键字来定义,需要注意的是其必须是大写字母。


变量


变量引用

对于变量的引用,则需要采用$(变量名)或者${变量名}这种模式。


常用变量

CC:   保存编译器名
RM:    用于删除文件的命令是什么
EXE:  存放可执行文件名。
OBJS:  放置所有的目标文件名。


自动变量

  • $@用于表示一个规则中的目标。当我们的一个规则中有多个目标时, $@ 所指的是其中任何造成命令被运行的目标。
  • $^则表示的是规则中的所有先择条件
  • $<表示的是规则中的第一个先决条件


特殊变量

变量MAKE 变量,它表示的是make 命令名是什么。当我们需要在 Makefile 中调用另一个 Makefile 时需要用到这个变量,采用这种方式,有利于写一个容易移植的 Makefile。

.PHONY: all
all:
@echo "MAKE = $(MAKE)"
$make
MAKE = make


变量MAKECMDGOALS,它表示的是当前用户所输入的 make 目标是什么

MAKECMDGOALS 指的是用户输入的目标,当我们只运行 make 命令时,虽然根据 Makefile 的语法,第一个目标将成为缺省目标,即 all 目标,但 MAKECMDGOALS 仍然是空,而不是 all,这一点我们需要注意。


变量的类别

  1. 只用一个**“=”**符号定义的变量,我们称之为递归扩展变量(recursively expanded variable);递归扩展变量的引用是递归的.
  2. 使用**“:=”** 符号定义的变量,这种变量称之为简单扩展变量(simply expanded variables);make 只对其进行一次扫描和替换(变量只有第一次赋值有效);
  3. 使用“?=” 符号定义的变量,这种变量叫做条件赋值变量;条件赋值的意思是当变量以前没有定义时,就定义它并且将左边的值赋值给它,如果已经定义了那么就不再改变其值。条件赋值类似于提供了给变量赋缺省值的功能。


变量值的来源

● 对于前面所说到的自动变量,其值是在每一个规则中根据规则的上下文自动获得变量值的。

● 可以在运行 make 时,在 make 命令行上定义一个或多个变量

● 变量还可以来自于 Shell 环境,采用 Shell 中的 export 命令定义了一个 bar变量后 Makefile 的运行结果。


override 指令

ovrride 关键字,该关键字在Makefile 中定义的变量受到保护,不会被重新赋值,覆盖掉。


Makefile 函数


1. wildcard函数 patsubst 函数

wildcard函数 是通配符函数,通过它可以得到我们所需的文件

形式 :$(wildcard pattern)


patsubst 函数是用来进行 字符串替换 的,其形式是:

$(patsubst pattern, replacement, text)


2. addprefix 函数

addprefix 函数是用来在给字符串中的每个子串前加上一个前缀,其形式是:

$(addprefix prefix, names...)

3.filter

filter 函数用于从一个字符串中,根据模式得到满足模式的字符串,其形式是:

$(filter pattern..., text)

4. filter-out

filter-out 函数用于从一个字符串中根据模式滤除一部分字符串,其形式是:

$(filter-out pattern..., text)

5. patsubst 函数

patsubst 函数是用来进行字符串替换的,其形式是:

$(patsubst pattern, replacement, text)

6.strip

strip 函数用于去除变量中的多余的空格,其形式是:

$(strip string)

7.wilrdcard 函数

wildcard 是通配符函数,通过它可以得到我们所需的文件,这个函数如果我们在 Windows 或是Linux 命令行中的“*”。其形式是:

$(wildcard pattern)


条件语法


当 make 看到条件语法时将立即对其进行分析,这包括 ifdef、ifeq、ifndef 和 ifneq 四种语句形式。

Makefile 中的条件语法有三种形式,其中的 conditional-directive 可以是 ifdef、ifeq、ifndef 和 ifneq 中的任意一个。


conditional-directive

text-if-true

endif

conditional-directive

text-if-true

else

text-if-false

endif

conditional-directive

text-if-one-is-true

else conditional-directive

text-if-true

else

text-if-false

endif


Makefile 思想


写一个 Makefile 文件的第一步不是一个猛子扎进去试着写一个规则,而是先用面向依赖关系的方法想清楚,所要写的 Makefile 需要表达什么样的依赖关系,这一点非常的重要;


makefile 怎么确定文件是否发生了更新


通过文件的时间戳!

make 会检查所有规则当中的目标(文件)与先决条件(文件)之间的时间先后关系,从而来决定是否要重新创建规则中的目标。


Makefile 中通配符


在makefile 中使用"%"当通配符。


包含文件


Makefile 中的 include关键字,它如同 C/C++中的#include 预处理指令。

在 Makefile 中,如果在 include 前加上一个‘-’号,当 make 处理这一包含指示时,如果文件不存在就会忽略这一错误。


命令

make 都是在一个新的 Shell 上运行它的,如果希望多个命令在同一个 Shell 中运行,则需要用‘;’将这些命令连起来。当命令很长时,为了方便阅读,我们需要将一行命令分成多行,这需要用‘\


通用模板



参考


  1. 《GUN make》
  2. 参考-Makefile实战 https://www.yuque.com/linuxer/xngi03/nfsm1k?

本专栏知识点是通过<零声教育>的系统学习,进行梳理总结写下文章,对c/c++linux课程感兴趣的读者,可以点击链接,详细查看详细的服务

目录
相关文章
|
4月前
|
编译器 Linux C语言
Makefile实战论(一)
Makefile实战论(一)
|
6月前
我为什么更推荐你使用cmake编译grpc程序?
我为什么更推荐你使用cmake编译grpc程序?
127 0
|
7月前
Makefile(1)入门
Makefile(1)入门
52 0
|
编译器 Shell Linux
Makefile学习1
Makefile学习1
|
Shell
如何使用makefile
如何使用makefile
|
NoSQL 编译器 Linux
【三、深入浅出GCC编译器】一个源文件到可执行文件是如何生成的:GCC编译工具链及编译参数详解(三)
【三、深入浅出GCC编译器】一个源文件到可执行文件是如何生成的:GCC编译工具链及编译参数详解
323 0
【三、深入浅出GCC编译器】一个源文件到可执行文件是如何生成的:GCC编译工具链及编译参数详解(三)
|
IDE Linux Shell
【Makefile】简单的Makefile编写
【Makefile】简单的Makefile编写
|
Java Linux 程序员
玩转Makefile | 一文入门Makefile
玩转Makefile | 一文入门Makefile
244 0
玩转Makefile | 一文入门Makefile
|
编译器 Shell C语言
Makefile文件 | 进阶指南
Makefile文件 | 进阶指南
381 0