一、理论部分
官方文档表示该参数可以指定build的目标文件类型:
The 'go build' and 'go install' commands take a -buildmode argument which indicates which kind of object file is to be built.
MIT6.824的课程中用到了plugin模式,官方文档这样描述:
-buildmode=plugin
Build the listed main packages, plus all packages that they import, into a Go plugin. Packages not named main are ignored.
把main包编译为一个插件,即生成一个动态链接.so文件(Linux的so文件到底是干嘛的?)。 语法通常为:
go build -buildmode=plugin -o [目标文件名.so] 源文件名.go
如果你不指定目标.so的文件名,go build将自动设置为同名文件。
二、实践部分
下面从 源码 和 shell命令 演示如何动态调用这个.so文件。
1.被调的插件
源码:
// wc.go
package main
// ↑ 注意必须声明在 main 包下,否则将被 -buildmode=plugin 忽略(但源文件本身可放在任意目录下)
import (
...
)
// 实现所需的若干函数
func Map(filename string, contents string) []mr.KeyValue {
...
}
func Reduce(key string, values []string) string {
...
}
shell命令:
然后使用-buildmode = plugin参数将源码文件及其依赖包编译为一个.so插件:
go build -race -buildmode=plugin ../mrapps/wc.go
这将在main/下生成与源文件wc.go同名的wc.so插件。
2.主调的代码
源码:
// mrsequential.go
package main
import (
...
"plugin" // 导入 go 官方自带的 plugin 库
...
)
...
...
// 调用.so 插件相关代码
func loadPluginSeq(filename string) (func(string, string) []mr.KeyValue, func(string, []string) string) {
p, err := plugin.Open(filename) // 1.实参: .so文件所在的相对路径
if err != nil {
log.Fatalf("cannot load plugin %v", filename)
}
xmapf, err := p.Lookup("Map") //2.**按需**用 Lookup() 动态匹配函数名
if err != nil {
log.Fatalf("cannot find Map in %v", filename)
}
mapf := xmapf.(func(string, string) []mr.KeyValue) // 3.强制转换类型
xreducef, err := p.Lookup("Reduce")
if err != nil {
log.Fatalf("cannot find Reduce in %v", filename)
}
reducef := xreducef.(func(string, []string) string)
return mapf, reducef
}
shell命令:
go run -race mrsequential.go wc.so pg*.txt
其中,pg*.txt是待利用的 datasets
三、拓展阅读
其它可选的类型还有:
-buildmode = archive
-buildmode = c-archive
-buildmode = c-shared
-buildmode = default
-buildmode = shared
-buildmode = exe
-buildmode = pie
-buildmode = plugin
-
关于
go build的-buildmode参数,官方文档解释得比较全面:
go command - cmd/go - Go Packages