一. make和Makefile的使用和基本原理

1. make和Makefile的关系

  • 简单来讲 makeMakefile解释器脚本语言 的关系,在 ubuntu 下可以通过如下命令安装 make
    sudo apt install make
    
  • make可以手动指定 脚本文件,也可以不指定 脚本文件
    手动指定 脚本文件 的方法如下:
    # 手动指定脚本文件,文件名可以自己指定
    # 如下三条指令是等效的
    make -f filename	
    make --f filename
    make --makefile filename
    
    若不指定 脚本文件make 则会在当当前 工作目录 下依次寻找名为 “GNUmakefile ”“makefile ”“Makefile” 进行解释。

    注意:推荐使用 Makefile作为文件名,首字母大写而比较显著。不推荐使用 GNUmakefile 因为以此命名的文件只有 GNU make 才可以识别,而其他版本的 make 程序只会在工作目录下 makefileMakefile 这两个文件。

2. 规则 - Makefile语法的核心

Makefile 语法是由一个一个的 规则 构成的,其他的语法均是辅助完成规则的编写。

2.1 规则的语法

规则是由 目标(target)依赖(prerequisites)命令(command) 三部分组成,其中 依赖(prerequisites)命令(command)可以省略的,本节记录规则的语法,暂不对其具体用法分析,本节列举了三种写法。

在一个规则中只有 目标(target) 是必须的,依赖(prerequisites)命令(command) 都是可以省略的

2.1.1 使用 TAB键标识命令的写法。

行首出现TAB键,标识后面跟着一个命令。使用TAB键标识命令,每条命令都会创建一个新的shell进程执行,因为TAB必须在行首,所以这种写法命令需要分布在多行。

  • 有依赖的规则的写法:
    在这里插入图片描述

  • 省略依赖的规则的写法:
    在这里插入图片描述

2.1.2 使用 “;” 标识命令的写法

使用 “;” 标识命令,每条命令前面都有一个 “;”, 使用 “;” 标识的命令则不会创建新的shell进程(第一个会创建),在当前shell进程中执行。命令必须写在一行,如果要分行写则要写换行符 “\”

  • 有依赖的规则的写法:
    在这里插入图片描述
  • 省略依赖的规则的写法:
    在这里插入图片描述

2.1.3 混合写法

使用TAB标识的命令会创建新的进程并执行,使用 “;” 标识的命令则不会创建新的进程,在当前进程中执行执行

  • 有依赖的规则的写法:
    在这里插入图片描述

  • 没有依赖的规则的写法:
    在这里插入图片描述

2.2 make是如何解释规则的

Makefile 是由一个一个的 规则 构成, 可以这样理解, Makefile 文件中只有 规则, 其他的语法都是辅助。makeMakefile 的解释就是对规则的解释。

2.2.1 规则的设计思想

  • 什么是 target(目标) ?
    我们可以这样理解,target(目标) 即是 目标文件,我们为什么要费劲心思写一个 规则 ,肯定是有 目的 的;make 被设计的初衷是用来构建 c语言程序 的,所以 最终目标 是生成一个 可执行文件
  • 什么是 依赖(prerequisites)
    我们也应该将 依赖(prerequisites) 当做一个 文件 来理解,即 生成 目标文件 依赖的 文件,换句话说,要生成 目标文件 首先要有 依赖文件 ,如果没有 依赖文件make 会将 依赖文件 作为 目标 去寻找可以生成此 依赖文件 的规则,依赖文件 再有依赖文件,最终形成一个规则的 依赖树
  • 什么是命令(command)
    一条可以运行在 当前工作shell 中的 命令,暂时理解为生成 目标文件 的命令。

注:以上描述存在不准确的地方,旨在让大家对make的规则有一个感性的认识

2.2.2 make如何解释一个规则

  • 没有依赖的规则
    • make 会首先会在当前 工作路径 下寻找有没有 目标文件。如果没有则执行 当前规则下的 命令 , 如果有则退出并打印提示信息。
  • 存在依赖的规则
    • 先找到 依赖 对应的 规则依赖 可能还有 依赖 , 继续找,找到最后一层没有 依赖 为止,因为一个 目标 可能存在多个 依赖,向下找的过程是一个树形分布
    • 找到最底层的规则后,则一层一层往上比较目标依赖,若没有依赖则执行命令,若存在依赖则比较目标文件依赖文件时间戳,若依赖文件时间戳更加新则说明目标已经过时了,则执行对应命令。就这样一层一层往上解析规则,最终解析到最顶层结束退出。
  • make对于目标依赖处理的总结:
    • 没有依赖判断有无目标文件,有则执行命令,无则不执行命令。
    • 依赖则检查目标依赖的时间戳,依赖时间戳更新则执行命令

2.2.3 make对于命令的处理

  • 规则依赖的关系由make解析,命令则单独由make创建一个shell进程,由shell去解析,命令写了什么make并不知道。每条命令执行完,make会检查命令的返回码,命令执行成功则执行下一条命令(创建新的进程执行),执行失败则退出。
  • TAB键修饰命令表示创建一个新的shell进程执行命令。“;” 修饰则表示不用创建新的shell进程,就在当前shell进程中执行命令。
    • 在不同shell进程执行命令的示例
    all :
    	cd /	# 进入根目录
    	pwd		# 注意此处打印的是工作路径,而非 根目录 ,因为这两条命令在不同的进程中执行
    
    • 在同一shell进程执行命令的示例
    all :
    	@cd / ; pwd		# 这两条命令会在同一进程中执行,pwm命令会打印根目录路径。
    

2.2.4 make会首先解释哪个规则

  • 可以通过命令行指定make解释哪条规则,make通过指定目标名的方式指定规则入口,如下所示:
make all	# make会在Makefile文件下找到目标名为 “all” 的规则进行解析 
make clean  # make会在Makefile文件下找到目标名为 “clean” 的规则进行解析 
  • 没有通过命令行指定,则make会将Makefile第一个目标所在的规则作为规则入口。如果规则存在多个目标,第一个目标就是入口。

2.3 一个简单的Makefile示例

hello.out all : func.o main.o
	gcc -o hello.out func.o main.o
	
func.o : func.c
	gcc -o func.o -c func.c
	
main.o : main.c
	gcc -o main.o -c main.c

3. 本文总结

  • Makefile 的核心语法是规则,其他语法都是为为描述规则语法进行服务,本文描述了make的工作机制,make是如何解释一个规则的,本章是后续学习的基础。
  • 如有描述错误的地方欢迎指正,共同学习。
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值