无法打开 Go 插件。

huangapple go评论77阅读模式
英文:

Unable to open a Go plugin

问题

我总是遇到以下错误:

plugin.Open("./plugin"): plugin was built with a different version of package internal/cpu

我对这个问题进行了一些研究,明显指出插件使用了与加载插件的应用程序不同的上下文版本(golang版本或依赖项)。

我在Docker下进行了一个最小化的测试,使用完全相同的Go编译器版本和相同的镜像来构建插件和应用程序,但仍然遇到相同的错误。

如果有人能指出失败的原因,或者我应该检查什么以防止这个错误,我将不胜感激。

值得一提的是,我正在使用MacOS,但我正在Docker容器下运行测试。实际上,我能够在Docker中构建和运行第三方产品的golang插件。

这是代码:

// main.go

package main

import (
	"fmt"
	"plugin"
)

func main() {
	path := "./plugin.so"
	p, err := plugin.Open(path)
	if err != nil {
		fmt.Printf("无法加载插件 %s。\n%v", path, err)
	}

	symbol, err := p.Lookup("Create")
	if err != nil {
		fmt.Printf("无法在插件 %s 中找到 Create() 函数。\n%v", path, err)
	}

	createMethod, ok := symbol.(func() interface{})
	if !ok {
		fmt.Printf("Create 不是插件 %s 中的函数", path)
	}
	createMethod()
}
// plugin.go

package main

func Create() interface{} {
	return nil
}
//Dockerfile

FROM golang:1.13.5 as pluginBuilder

WORKDIR /app

COPY . .

RUN go build --buildmode=plugin --trimpath -o /plugin.so plugin.go

FROM golang:1.13.5 as serverBuilder
WORKDIR /app

COPY . .

RUN go build -o /server main.go

FROM debian:stable AS server

WORKDIR /app
COPY --from=pluginBuilder /plugin.so .
COPY --from=serverBuilder /server .

RUN /app/server

谢谢

英文:

I always get the following error:

plugin.Open("./plugin"): plugin was built with a different version of package internal/cpu

I did some research about this issue, and it's clearly pointing out that the plugin has been built using different context versions (golang version, or dependencies) than the app loading the plugin.

I ran a minimal test under Docker, using exactly the same Go compiler version and same image to build both the plugin and the app, but I'm still getting the same error.

I appreciate if anyone can point me out where's the failure, or what else should I check to prevent this error.

It's worth mentioning I'm using MacOS, but I'm running the test under Docker containers. Actually, I was able to build and run golang plugins under Docker for third party products.

This is the code:

// main.go

package main

import (
	"fmt"
	"plugin"
)

func main() {
	path := "./plugin.so"
	p, err := plugin.Open(path)
	if err != nil {
		fmt.Printf("unable to load plugin at %s.\n%v", path, err)
	}

	symbol, err := p.Lookup("Create")
	if err != nil {
		fmt.Printf("unable to find Create() function in plugin %s.\n%v", path, err)
	}

	createMethod, ok := symbol.(func()interface{})
	if !ok {
		fmt.Printf("Create is not a function in plugin %s", path)
	}
	createMethod()
}
// plugin.go

package main

func Create() interface{} {
	return nil
}
//Dockerfile

FROM golang:1.13.5 as pluginBuilder

WORKDIR /app

COPY . .

RUN go build --buildmode=plugin --trimpath -o /plugin.so plugin.go

FROM golang:1.13.5 as serverBuilder
WORKDIR /app

COPY . .

RUN go build -o /server main.go

FROM debian:stable AS server

WORKDIR /app
COPY --from=pluginBuilder /plugin.so .
COPY --from=serverBuilder /server .

RUN /app/server

Thanks

答案1

得分: 4

您正在构建插件时使用了-trimpath选项,但在构建应用程序时没有使用该选项。请编辑Dockerfile,使两个构建都使用-trimpath(或都不使用),然后应用程序将会运行(在我的机器上是这样的)。

我猜测造成这个问题的原因是trimpath会“从编译后的可执行文件中删除所有文件系统路径”,因此当运行时验证版本时,它会检测到路径的差异。

以下是对我有效的Dockerfile(在复制原始问题时遇到了相同的问题,唯一的更改是在第二个go build中添加了-trimpath):

FROM golang:1.13.5 as pluginBuilder

WORKDIR /app

COPY . .

RUN go build --buildmode=plugin --trimpath -o /plugin.so plugin.go

FROM golang:1.13.5 as serverBuilder
WORKDIR /app

COPY . .

RUN go build --trimpath -o /server main.go

FROM debian:stable AS server

WORKDIR /app
COPY --from=pluginBuilder /plugin.so .
COPY --from=serverBuilder /server .

RUN /app/server

希望对您有所帮助!

英文:

You are using the -trimpath option when building the plugin but not when building the app. Edit the docker file so both builds use -trimpath (or neither do) then the application will run (well it does on my machine).

My guess as to why this causes the issue is that trimpath "removes all file system paths from the compiled executable" so when the runtime verifies versions it picks up the difference in the paths.

Here is the dockerfile that works for me (having replicated the issue with the original; the only change is adding -trimpath to the second go build):

FROM golang:1.13.5 as pluginBuilder

WORKDIR /app

COPY . .

RUN go build --buildmode=plugin --trimpath -o /plugin.so plugin.go

FROM golang:1.13.5 as serverBuilder
WORKDIR /app

COPY . .

RUN go build --trimpath -o /server main.go

FROM debian:stable AS server

WORKDIR /app
COPY --from=pluginBuilder /plugin.so .
COPY --from=serverBuilder /server .

RUN /app/server

huangapple
  • 本文由 发表于 2021年8月9日 23:38:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/68714827.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定