什么是Makefile
工程编译规则,用于描述如何将代码变为可执行文件的过程
- 哪些文件需要编译,如何编译
- 需要那些类库,怎么获取这些类库
- 如何将上面的东西变成可执行文件
常用基本格式
<标签 target>: <依赖项>
<command shell 命令>
待编译的main.go文件
package main
import "fmt"
func main() {
fmt.Println("Makefile")
}
Makefile 文件
build: main.go
# 如果不想在命令行显示该命令,在其前面加@即可
# @go build main.go
go build main.go
编译
# make 也行 会默认执行第一个标签
make build
伪目标
- 伪目标即说明其command不会生成任何文件
- 使用
.PHONY
标记伪目标 - 伪目标每次都会执行
下面是一个正常的目标,其目的是生成main 可执行文件,在执行make build
时会验证 依赖项 main.go 是否是target,如果是target 则执行,是外部文件,则检查外部文件是否存在,存在则执行 command
build: main.go
# 如果不想在命令行显示该命令,在其前面加@即可
# @go build main.go
go build main.go
依赖不仅仅可以是外部文件,也可以是Makefile中的其它 target
build: net
go build main.go
net:
go build net.go
main.go
package main
import "fmt"
func main() {
fmt.Println("Makefile")
}
net.go
package main
import "fmt"
func main() {
fmt.Println("net")
}
编译,发现没有,执行两次make build
, go build net.go
就执行了一次。先明确一点,依赖项是先从内部target找起的,内部没有才找外部的。
第一次执行make build
, 找到 net target
,发现外部没有 net可执行文件
,执行 net command (go build net.go)
构建 net可执行文件
第二次执行 make build
, 找到 net target
, 发现外部有net可执行文件
,对比外部 net可执行文件 和 net target 的关系(由于net target
没有依赖项,就会认为外部 net 可执行文件
就是由 net target
生成的),所以认为可以复用,就不会执行 go build net.go
如果 net target
也有外部依赖 net.go
,那么会变为根据 net.go
是否修改来决定是否执行 command
修改 net.go
再 make build
下面我们违背伪目标的含义,将 net target
设置成 伪目标
,由于设置成伪目标所以每次都执行 go build net.go
因为和外部对比时,发现比对的目标是伪目标
, 伪目标的含义是什么: 不会生成任何文件
,那么就一定不会复用,故此,一定会执行 go build net.go
build: net
go build main.go
.PHONY: net # 其实违背了伪目标的含义,其实生成了net
net: net.go
go build net.go
指定文件名
执行make,会在当前目录下去找 makefile 或 Makefile 文件,如果是别的文件需要通过-f 指定
将Makefile 改为 abc
build: main.go
go build main.go
忽略command错误
通常运行command出错会终止后续 target
运行,但可以使用 -
忽略错误,保证运行完毕
由于没有abc,所以 make build
不会执行 go build main.go
Makefile
build: clean
go build main.go
.PHONY: clean
clean:
rm abc
使用 -
忽略错误可以继续执行
Makefile
build: clean
go build main.go
.PHONY: clean
clean:
- rm abc
多command
多个command分行写,每一行前加一个tab
键
Makefile
build:
go build main.go
go build net.go
如果有关联关系,可以写在一行中,通过 ;
来分割
Makefile
build:
- set -e; rm abc; mkdir c
- rm abc; mkdir d
由于 abc
不存在,rm abc
一定会报错,由于 第一行 有 set -e
遇到错误后不再执行后续的,所以 mkdir c
不会执行,而 写在第二行,就和第一行的 set -e
没有关联,所以遇到错误,还是会执行后面的语句 mkdir d
order-only 依赖
格式: 依赖 | order-only
下面的Makefile第一次构建完后,再 执行 make net,是不会重新构建的,除非 net.go 或者 work.go 修改
build: net
go build main.go
net: net.go work.go
go build net.go
go build work.go
如果想只有 net.go 改变时才重新构建,那么可以使用 order-only 依赖
将 work.go 作为 order-only 依赖
,修改 work.go 并不会重新构建
build: net
go build main.go
net: net.go | work.go
go build net.go
go build work.go