正如标题所说,我想根据仅在运行时可用的信息动态加载(或不加载)Go 包。
目标是允许用户通过添加新的本机脚本命令的自定义包来扩展程序。目前,每次我添加新命令或想要禁止某些命令时,我都需要编辑程序并重新编译,而如果我可以制作某种 dll 或类似的东西,那么我可以创建一个“导入”脚本命令来搜索和加载一个命名的命令库。
对于好奇的程序,有问题的程序是基于自定义命令的脚本库,我用于各种事情。
我提前做了一些搜索,结果看起来不太好,但我找不到明确的否。
正如标题所说,我想根据仅在运行时可用的信息动态加载(或不加载)Go 包。
目标是允许用户通过添加新的本机脚本命令的自定义包来扩展程序。目前,每次我添加新命令或想要禁止某些命令时,我都需要编辑程序并重新编译,而如果我可以制作某种 dll 或类似的东西,那么我可以创建一个“导入”脚本命令来搜索和加载一个命名的命令库。
对于好奇的程序,有问题的程序是基于自定义命令的脚本库,我用于各种事情。
我提前做了一些搜索,结果看起来不太好,但我找不到明确的否。
Go 还不支持动态库。Elias Naur 最近发布了一些补丁,但它们还没有经过审查,它们不太可能包含在 Go 1.2 中。您可以阅读 Google Groups 上的讨论:
据我所知,这是关于该主题的最新讨论。
然而,还有另一种方法。您可以在单独的进程中启动插件并使用net/rpc包与您的主应用程序进行通信。这也允许您动态启动/停止/重新编译单独的插件,它的优点是一个坏插件不会使您的程序崩溃。Go 擅长网络通信,你只需要好好利用它。
我需要编辑程序并重新编译,
您还可以考虑编写一个小脚本来监视当前目录中的更改(使用 fsnotify)并执行“go build”,然后重新启动程序。我在本地开发期间在我的一些 Web 项目中使用了这种方法,并且效果很好。我无法观察到任何编译时间,而且我切换和刷新浏览器窗口的速度非常快。在我的 Python 开发周期中,解释器必须重新启动,并且每次更改都必须重新导入所有模块(这在大型项目中可能会花费大量时间!),与 Go 相比,感觉真的很笨拙。
Go 1.8 对此提供了支持。目前它还很不成熟和初级,但它最终是可能的。
Mateusz Gajewski 的go-bind-plugin项目可能也很有趣,因为它简化了加载插件的使用。
从插件包文档:
例如,一个插件定义为
package main
// // No C code needed.
import "C"
import "fmt"
var V int
func F() { fmt.Printf("Hello, number %d\n", V) }
可以使用 Open 函数加载,然后可以访问导出的包符号 V 和 F
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"
type Symbol interface{}
好吧,Go 有一个dlopen 包——所以,至少,您现在可以将共享库 (DLL) 加载到您的 Go 程序中……您可能必须用 C、C++ 编写您的扩展或其他东西,您可以使用能够生成共享库的工具。