首页 > 其他分享 >Makefile 学习一:运行机制

Makefile 学习一:运行机制

时间:2022-10-30 16:31:07浏览次数:68  
标签:文件 target Makefile 学习 go 运行机制 world include hello

你必须非常努力,才能看起来毫不费力!

微信搜索公众号[ 漫漫Coding路 ],一起From Zero To Hero !

前言

在 Go 语言开发中,我们希望能够规范代码风格,每个成员在提交时可以一键格式化,同时检查是否有语法错误;我们希望能够一键运行单测,生成单测报告;我们希望能够一键编译、打包、发布项目,这就需要使用到 Make。Make 有很多种,我们常用的就是 GUN Make,有了 Make,我们将极大的提高项目开发、测试、发布的效率。

Make 最初是为 C、C++项目的编译、构建服务的,因此有很多为C、C++的特性,但是这些特性在 Go 开发中使用不到。毕竟每个人的时间有限,我们就只学习Go 开发中 Make 使用所必需的知识。Make 的规则都在 Makefile 文件编写上,我们后面就一起来学习 Makefile 的编写吧!

make 命令在 Windows 下不支持运行,需要在 Linux 或 Mac 环境下运行

规则

Makefile 的规则很简单,分为三个部分:

target : prerequisites
    command
    ...

target:目标,可以是一个文件,或者是一个标签 label

prerequisites:targets 依赖的东西, 可以是文件,也可以依赖其他 target

command:shell 命令(开头是 Tab 键)

  1. 如果 prerequisites 比 target 要新,就会 执行 command 命令 (已存在的文件比不存在的文件新)

  2. 如果 prerequisites 中存在其他 target,对该 target 重复第一条

举个例子:

hello: hello.go
	go build hello.go

如果 hello 文件不存在,hello.go 肯定比不存在的 hello 新,执行命令 go build hello.go

如果 hello 文件存在,但是 hello.go 又有了新的修改,hello.go 也比 hello 新,执行 go build hello.go

如果 hello 文件存在,且 hello.go 没有改动,不执行任何操作

再举个例子:

hello: hello.go
	go build hello.go

world: hello world.go
	go build world.go

hello 是个 target ,world 也是个 target,且 world 依赖 hello。

如果执行 world 这个 target,会有如下两种情形:

world 不存在,遍历 prerequisites

  1. hello 是个 target,走一遍例一描述的流程

    如果 hello 文件不存在,执行命令 go build hello.go,此时生成了 hello,比world新

    如果 hello 文件存在,但是 hello.go 又有了新的修改,执行 go build hello.go,,此时生成了 hello,比 world 新

    如果 hello 文件存在,且 hello.go 没有改动,继续判断 world.go

  2. world.go 是个普通文件,比不存在的 world 新

  3. world 的依赖中,存在有比 world 新的,因此执行 command

world 存在,遍历 prerequisites

  1. hello 是个 target,走一遍例一描述的流程

    如果 hello 文件不存在,那么就会执行命令 go build hello.go此时 hello 比 world 新了

    如果 hello 文件存在,但是 hello.go 又有了新的修改,也会执行 go build hello.go此时 hello 比 world 新

    如果 hello 文件存在,且 hello.go 没有改动,不执行任何操作

  2. world.go 是个普通文件,如果修改过,那么比 world 新,否则不如 world 新

  3. 判断 prerequisites 中的 hello 或者 world.go 是否存在比 world 新的,如果有,执行command;没有的话不执行任何操作

多目标

有可能我们会有多个 target 规则类似,我们可以将它们合并起来:

.PHONY: target1 target2
target1 target2: prerequisites
	command

等同于

.PHONY: target1 target2
target1: prerequisites
	command

target2: prerequisites
	command

伪目标

上面说过,target 不一定是一个文件,也可能是一个标签,因为有些操作,我们不一定会生成文件,比如清理一些中间文件,运行单测等,这种 target 我们把它叫做伪目标。

hello: hello.go
	go build hello.go

world: hello world.go
	go build world.go

clean:
	rm hello world

clean 就是一个伪目标,只是一个标签,运行这个伪目标,需要显式地指定这个目标,即 make clean

➜   make clean 
rm hello world

但是有可能会有文件和我们的伪目标名称重名,这样我们运行 make clean 的时候就达不到我们的目的了。

# 如果有重名文件存在,make clean 就不会运行
➜  touch clean
➜  make clean 
make: `clean' is up to date.

为了防止这样的情况,我们可以使用 ".PHONY" 显式地声明我们的 target 是个 伪目标,这样即使有重名文件在,也不会影响 target 的运行。

hello: hello.go
	go build hello.go

world: hello world.go
	go build world.go

# 显式声明 clean 是个伪目标
.PHONY: clean
clean:
	rm hello world
➜   make world
go build hello.go
go build world.go
➜   touch clean
➜   make clean 
rm hello world

运行

上面我们其实已经运行过 makefile 了,这里我们再来简单看下:

hello: hello.go
	go build hello.go

world: hello world.go
	go build world.go

# 显式声明 clean 是个伪目标
.PHONY: clean
clean:
	rm hello world

在默认的方式下,也就是我们只输入 make 命令。那么,

  1. make 会在当前目录下找名字叫 “Makefile” 或 “makefile” 的文件。
  2. 如果找到,它会找文件中的第一个 target,运行该 target,并打印相应的日志。

或者我们可以输入 make + target ,强制运行某个 target,比如输入 make world

➜   make
go build hello.go
➜  makefile_study make world
go build world.go
➜   make clean 
rm hello world

引用 Makefile

在 Makefile 中使用 include 关键字可以把别的 Makefile 包含进来,这很像C语言的 #include ,被包含的文件会放在当前文件的包含位置。 include 的语法是:

include filenames…
  • filename 可以是绝对路径或者当前目录下的文件;如果 filename 是空,不会进行引用也不会报错。
  • include 前面可以有多个空格,但是一定不能Tab
  • include 和 filename 直接使用空格分隔;多个 filename 之间也使用空格分隔
  • filename 中可以使用变量

举个例子,如果你当前文件夹下有三个 makefile 文件,分别叫做 a.mk、b.mk、c.mk,那么如下引用

include foo *.mk 

相当于

include foo a.mk b.mk c.mk

Makefile 在处理 include 时,遇到一个 include 文件就读取该文件内容,读取完后再处理下一个 include 文件。

如果一个文件没有指定路径,会在当前路径下寻找,如果没找到,还会按照如下顺序寻找:

  1. 运行 Make 命令时使用 '-I' 或 '--include-dir' 参数指定的路径
  2. 如果如下目录存在的话,会挨个寻找。prefix/include(一般是/usr/local/include) 、/usr/gnu/include、/usr/local/include、 /usr/include

在处理 include 时,如果一个 include 的文件没有找到,程序不会终止,只会打印一条警告信息,然后继续处理。当读取完整个 Makefile 文件后,程序再去重试处理这些没有找到的文件,如果还是处理失败,会产生一个致命错误。如果想忽略文件不存在带来的报错,可以在 include 前面加上一个减号 '-',表示忽略引用错误。

-include filenames…

我们一般都是有一个主文件 Makefile 对外暴露,其他的引用文件被主文件 Makefile 调用,类似函数调用。一个 target 调用 另一个 target,可以直接使用 $(MAKE)+target

a.mk

.PHONY: a_func
a_func:
	echo "this is a_func"

Makefile

include a.mk

.PHONY: func
func:
	$(MKAKE) a_func  # 调用 a.mk 中的 a_func target

总结

本文主要介绍了 Makefile 的运行机制,分为以下几个方面:

  • 规则:依据 prerequisites 是否比 target新,决定是否执行 command
  • 多目标:多个 target 的 prerequisites 和 command类似时,使用多目标
  • 伪目标:target 不是一个目标文件
  • 运行:如何运行 Make
  • 引用:引用其他 Makefile 文件

更多

个人博客: https://lifelmy.github.io/

微信公众号:漫漫Coding路

标签:文件,target,Makefile,学习,go,运行机制,world,include,hello
From: https://blog.51cto.com/u_12260130/5807536

相关文章

  • STA学习笔记-0
    如今的逻辑设计复杂度和工作频率要求越来越高。为了保证设计稳定可靠,必须对设计附加时序约束,对综合实现结果进行时序分析。导言时序约束:主要用于规范设计的时序行为,表达......
  • MarkDown学习
    Makdown学习标题三级标题四级标题字体HelloWorld!HelloWorld!HelloWorld!HelloWorld!HelloWorld!引用狂神说Java分割线图片超链接点击跳转列表......
  • JavaScript学习
    (只用于自己学习,只是个目录形式,具体内容涉及不多)JavaScript用于用户和网页之间的交互,比如提交的时候,用于用户名是否为空的判断 1.document是JavaScript的内置对象,代表浏......
  • 学习笔记-权限提升
    权限提升免责声明本文档仅供学习和研究使用,请勿使用文中的技术源码用于非法用途,任何人造成的任何负面影响,与本人无关.大纲WinLinuxMysqlMSSQLPostg......
  • vue学习笔记
    今日内容概要计算属性监听属性组件介绍和定义父子通信之父传子父子通信之子传父ref属性动态组件插槽vue-cli今日内容详细计算属性我们可以通过计算属性c......
  • GO学习一
    变量函数内的变量,声明后必须使用否则报错;包内变量,生命后可以不使用。var什么时候要使用,什么时候可以不使用函数内可以使用:=,此时省略var关键字,且只有这种情况可以省......
  • 第六章学习心得
    知识点归纳信号和信号处理;信号和中断的统一处理将信号视为进程中断,将进程从正常执行转移到信号处理信号的来源,包括来自硬件、异常和其他进程的信号信号在Unix/Linux......
  • 20201208史逸霏第六章学习笔记
    6.1~6.3信号和中断中断:中断是I/O设备发送到CPU的外部请求,将CPU从正常执行转移到中断处理。信号:信号是发送给进程的请求,将进程从正常执行转移到中断处理。中断的类型:......
  • 【博学谷学习记录】超强总结,用心分享|Python容器详解
    一、Python中容器的介绍容器:也可以称为是数据序列,或者高级数据类型,也是Python中的数据类型。容器中可以存放多个数据。Python中常用的容器有4种:list(列表)、......
  • USB取证 学习笔记
    USB取证免责声明本文档仅供学习和研究使用,请勿使用文中的技术源码用于非法用途,任何人造成的任何负面影响,与本人无关.相关文章USB-CTFWikiUSB流量取证分析......