golang plugin的依赖问题

Posted baizx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang plugin的依赖问题相关的知识,希望对你有一定的参考价值。

golang plugin的依赖问题

此文中涉及的plugin运行环境为mac 10.14,go版本为1.11
主要是想讨论一下插件依赖的第三方库的问题.
例子是在https://github.com/vladimirvivien/go-plugin-example一文基础之上.

简单插件

1.主程序

package main

import (
    "fmt"
    "os"
    "plugin"
)

type Greeter interface {
    Greet()
}

func main() {
    // load module
    // 1. open the so file to load the symbols
    plug, err := plugin.Open("./eng/eng.so")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    // 2. look up a symbol (an exported function or variable)
    // in this case, variable Greeter
    symGreeter, err := plug.Lookup("Greeter")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    // 3. Assert that loaded symbol is of a desired type
    // in this case interface type Greeter (defined above)
    var greeter Greeter
    greeter, ok := symGreeter.(Greeter)
    if !ok {
        fmt.Println("unexpected type from module symbol")
        os.Exit(1)
    }

    // 4. use the module
    greeter.Greet()

}

2. plugin代码

package main

import "fmt"

type greeting string

func (g greeting) Greet() {
    fmt.Println("Hello Universe")
}

// exported
var Greeter greeting

3. plugin编译方法

go build -buildmode=plugin -o eng/eng.so eng/greeter.go

4. 运行结果

go run main.go
Hello Universe

插件与主程序依赖第三方库的问题

如果主程序和插件都依赖第三方库会有什么问题呢?他们是共享一份代码?还是完全独立的copy呢?
这就类似于c语言动态链接库的依赖,但是应该又不一样. 以实验结果说话吧.

1. 同时依赖的第三方库

package anotherlib
var ShareVariable =7

2. 运行结果

和平时常见的动态库行为一致,也就是说主程序和插件共享了一份运行代码,也共享了一份运行变量.

引入了vendor的问题

实际项目中,可能代码都会使用vendor来管理自己的第三方依赖库.
这时候就会出现不一致的情况.也就是说因为主程序使用了vendor或者插件使用了vendor,
那么这时候go runtime就会认为插件和主程序用的不是同一个第三方依赖库,这时候就会出现和预期不一致的情况.

完整的代码

我已经把代码放在github,刚兴趣可以下载运行,

main.go

package main

import (
    "fmt"
    "os"
    "plugin"
    "github.com/nkbai/blog/goplugin/anotherlib"
)

type Greeter interface {
    Greet()
    GetShareVariable() int
}

func main() {
    // load module
    // 1. open the so file to load the symbols
    plug, err := plugin.Open("./eng/eng.so")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    // 2. look up a symbol (an exported function or variable)
    // in this case, variable Greeter
    symGreeter, err := plug.Lookup("Greeter")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    // 3. Assert that loaded symbol is of a desired type
    // in this case interface type Greeter (defined above)
    var greeter Greeter
    greeter, ok := symGreeter.(Greeter)
    if !ok {
        fmt.Println("unexpected type from module symbol")
        os.Exit(1)
    }

    // 4. use the module
    greeter.Greet()

    fmt.Println("anotherlib in main")
    fmt.Println(anotherlib.ShareVariable)
    fmt.Printf("plugin anotherlib =%d
",greeter.GetShareVariable())
    fmt.Println("change anotherlib's variable")
    anotherlib.ShareVariable=5
    fmt.Printf("main share=%d,plugin share=%d
",anotherlib.ShareVariable,greeter.GetShareVariable())
    //可以看到输出都是5

    //下面这种情况将会出现不一致的情况
    testpluginvendor()
}

func testpluginvendor(){
        // load module
    // 1. open the so file to load the symbols
    plug, err := plugin.Open("pluginwithvendor/eng.so")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    // 2. look up a symbol (an exported function or variable)
    // in this case, variable Greeter
    symGreeter, err := plug.Lookup("Greeter")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    // 3. Assert that loaded symbol is of a desired type
    // in this case interface type Greeter (defined above)
    var greeter Greeter
    greeter, ok := symGreeter.(Greeter)
    if !ok {
        fmt.Println("unexpected type from module symbol")
        os.Exit(1)
    }

    // 4. use the module
    greeter.Greet()
    fmt.Println("call plugin withvendor")
    fmt.Println("anotherlib in main")
    fmt.Println(anotherlib.ShareVariable)
    fmt.Printf("plugin anotherlib =%d
",greeter.GetShareVariable())
    fmt.Println("change anotherlib's variable")
    anotherlib.ShareVariable=5
    fmt.Printf("main share=%d,plugin share=%d
",anotherlib.ShareVariable,greeter.GetShareVariable())
    //可以看到输出并不一致
}

plugin eng.go

package main

import "fmt"
import "github.com/nkbai/blog/goplugin/anotherlib"

type greeting string

func (g greeting) Greet() {
    fmt.Println("Hello Universe")
}
func (g greeting) GetShareVariable() int{
    return anotherlib.ShareVariable
}
// exported
var Greeter greeting

第三方依赖库 anotherlib.go

package anotherlib
var ShareVariable =7

以上是关于golang plugin的依赖问题的主要内容,如果未能解决你的问题,请参考以下文章

golang代码片段(摘抄)

代码片段 - Golang 实现简单的 Web 服务器

代码片段 - Golang 实现集合操作

json [Golang] golang #golang #snippets中有用的片段

vim代码片段插件ultisnips的使用

maven-shade-plugin插件未生效原因分析