go - 如何从插件的主应用程序调用函数?
问题描述
我最近研究了Go 插件,而不是自己手动加载 .so 文件。
基本上,我有一个游戏服务器应用程序,我希望能够在服务器启动时加载插件(使用插件包)。然后,在插件本身中,我希望能够调用作为服务器一部分的导出函数。
假设我有这个插件,它被编译为example_plugin.so
使用go build -buildmode=plugin
:
package main
import "fmt"
func init() {
fmt.Println("Hello from plugin!")
}
然后说我有这个服务器应用程序,它加载插件(并最终在后台调用“init”函数):
package main
import (
"fmt"
"plugin"
)
func main() {
fmt.Println("Server started")
if _, err := plugin.Open("example_plugin.so"); err != nil {
panic(err)
}
}
// some API function that loaded plugins can call
func GetPlayers() {}
输出是:
Server started
Hello from plugin!
这可以按预期工作,但是我希望能够GetPlayers
从插件(和任何其他插件)调用该函数(以及服务器应用程序中的任何其他导出函数,理想情况下)。我正在考虑制作某种由接口组成的库包含服务器实现的 API 函数,但是我不知道从哪里开始。我知道我可能需要使用 .a 文件或类似文件。
为了澄清起见,我正在开发此应用程序以在 Linux 上使用,因此我可以使用仅适用于 Linux 的解决方案。
抱歉,如果措辞不佳,这是第一次在 SO 上发帖。
解决方案
如评论中所述,有一个 Lookup 功能。在模块的文档中,他们有以下示例:
// A Symbol is a pointer to a variable or function.
// For example, a plugin defined as
//
// var V int
//
// func F() { fmt.Printf("Hello, number %d\n", V) }
//
// may be loaded with the Open function and then the exported package
// symbols V and F can be accessed
package main
import (
"fmt"
"plugin"
)
func main() {
p, err := plugin.Open("plugin_name.so")
if err != nil {
panic(err)
}
v, err := p.Lookup("V")
if err != nil {
panic(err)
}
f, err := p.Lookup("F")
if err != nil {
panic(err)
}
*v.(*int) = 7
f.(func())() // prints "Hello, number 7"
}
我认为这里最令人困惑的台词是
*v.(*int) = 7
f.(func())() // prints "Hello, number 7"
他们中的第一个执行类型断言来*int
断言确实是v
指向的指针int
。这是必要的,因为Lookup
返回一个interface{}
并且为了对值做任何有用的事情,你应该澄清它的类型。
第二行执行另一个类型断言,这一次确保它f
是一个没有参数且没有返回值的函数,然后立即调用它。由于F
原始模块中的函数正在引用V
(我们已将其替换为 7),因此此调用将显示Hello, number 7
.
推荐阅读
- image - 如何在用户点击的地方显示图像?SwiftUI
- javascript - 使用 JS 将 webp 转换为 jpeg
- angular - Angular 9 为步进器组件设置动画
- email - 端口 587 上的 GMail SMTP STARTTLS 不再有效
- rust - 使用谓词返回引用时的生命周期冲突(使用谓词实现“split at mut”)
- javascript - Javascript / p5.js 中的独立随机生成
- sql - 从 PostgreSQL 函数返回复合类型或多列
- c# - 在 FakeItEasy 测试期间访问属性的运行时值
- python - 轴标签间距不正确
- java - DDD 中域对象集合的最佳实践