Makefile 学习一:运行机制 您所在的位置:网站首页 makefile判断目录是否存在 Makefile 学习一:运行机制

Makefile 学习一:运行机制

2023-05-02 05:40| 来源: 网络整理| 查看: 265

前言

在 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 键)

如果 prerequisites 比 target 要新,就会 执行 command 命令 (已存在的文件比不存在的文件新) 如果 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

hello 是个 target,走一遍例一描述的流程 如果 hello 文件不存在,执行命令 go build hello.go,此时生成了 hello,比world新 如果 hello 文件存在,但是 hello.go 又有了新的修改,执行 go build hello.go,,此时生成了 hello,比 world 新 如果 hello 文件存在,且 hello.go 没有改动,继续判断 world.go world.go 是个普通文件,比不存在的 world 新 world 的依赖中,存在有比 world 新的,因此执行 command

world 存在,遍历 prerequisites

hello 是个 target,走一遍例一描述的流程 如果 hello 文件不存在,那么就会执行命令 go build hello.go,此时 hello 比 world 新了 如果 hello 文件存在,但是 hello.go 又有了新的修改,也会执行 go build hello.go,此时 hello 比 world 新 如果 hello 文件存在,且 hello.go 没有改动,不执行任何操作 world.go 是个普通文件,如果修改过,那么比 world 新,否则不如 world 新 判断 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 命令。那么,

make 会在当前目录下找名字叫 “Makefile” 或 “makefile” 的文件。如果找到,它会找文件中的第一个 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 前面可以有多个空格,但是一定不能是 Tabinclude 和 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 文件。

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

运行 Make 命令时使用 '-I' 或 '--include-dir' 参数指定的路径如果如下目录存在的话,会挨个寻找。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路

好物推荐:



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有