Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

plugin: can't open the same plugin with different names, like dlopen #29525

Open
Jexbat opened this issue Jan 3, 2019 · 12 comments
Open

plugin: can't open the same plugin with different names, like dlopen #29525

Jexbat opened this issue Jan 3, 2019 · 12 comments

Comments

@Jexbat
Copy link

@Jexbat Jexbat commented Jan 3, 2019

What version of Go are you using (go version)?

$ go version
go version go1.11.4 linux/386

Does this issue reproduce with the latest release?

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GOARCH="386"
GOBIN=""
GOCACHE="/home/pw/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="386"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/pw/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_386"
GCCGO="gccgo"
GO386="sse2"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/pw/Documents/hello/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m32 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build808633565=/tmp/go-build -gno-record-gcc-switches"

What did you do?

go build -buildmode=plugin -o scanner.so scanner.go
cp scanner.so scanner2.so
package main

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


type Greeter interface {
    Greet()
}


func main() {


	plug, err := plugin.Open("./plugins/scanner.so")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
	}

	symGreeter, err := plug.Lookup("Greeter")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
	}

	var greeter Greeter
    greeter, ok := symGreeter.(Greeter)
    if !ok {
        fmt.Println("unexpected type from module symbol")
        os.Exit(1)
	}

	plug2, err := plugin.Open("./plugins/scanner2.so")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
	}

	symGreeter2, err := plug2.Lookup("Greeter")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
	}

	var greeter2 Greeter
    greeter2, ok2 := symGreeter2.(Greeter)
    if !ok2 {
        fmt.Println("unexpected type from module symbol")
        os.Exit(1)
    }

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

}

What did you expect to see?

Same plugin copyed to different names can plugin.Open successfully and have different instances.
For example, I have a lot of scanners connect to my device and the number of scanners is uncertain,
the scanners have same protocol but the serial port is different, so I need to load the same scanner plugin and pass different serial port to the plugin to scan,so it is not suitable to complie different plugin by 'pluginpath', if I need 100 scanners I need to complie 100 times. Why can't just like dlopen distinguish by names?

What did you see instead?

plugin.Open("./plugins/scanner2.so"): plugin already loaded
@mvdan

This comment has been minimized.

Copy link
Member

@mvdan mvdan commented Jan 3, 2019

I presume it's because of this bit of doc:

When a plugin is first opened, the init functions of all packages not already part of the program are called. The main function is not run. A plugin is only initialized once, and cannot be closed.

If you could load the same plugin twice with different paths, you'd effectively run the same init function twice. That seems to go against how plugins should be used, but the documentation isn't terribly clear about this edge case.

/cc @ianlancetaylor @cherrymui as per https://dev.golang.org/owners/

@mvdan mvdan changed the title why golang plugin can't open same plugin by different name like 'dlopen'? plugin: can't open the same plugin with different names, like dlopen Jan 3, 2019
@Jexbat

This comment has been minimized.

Copy link
Author

@Jexbat Jexbat commented Jan 4, 2019

Thank you @mvdan , I am a newcomer to golang. I am evaluating whether golang is suitable for current arm embedded projects. Is plugin not implemented for linux/arm yet?

@cherrymui

This comment has been minimized.

Copy link
Contributor

@cherrymui cherrymui commented Jan 4, 2019

@Jexbat Plugin is supported on Linux/ARM.

@Jexbat

This comment has been minimized.

Copy link
Author

@Jexbat Jexbat commented Jan 4, 2019

@cherrymui GOOS=linux GOARCH=arm go build and return:plugin: not implemented.

$ file hello
hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, not stripped

I found same issue #19569, then I enable cgo like

CGO_ENABLED=1 GOOS=linux GOARCH=arm CC="arm-poky-linux-gnueabi-gcc" CXX="arm-poky-linux-gnueabi-g++" LD="arm-poky-linux-gnueabi-ld.gold" CGO_CFLAGS="-march=armv7-a -mfpu=neon  -mfloat-abi=hard -mcpu=cortex-a9 --sysroot=/opt/fsl-imx-fb/4.1.15-2.0.1/sysroots/cortexa9hf-neon-poky-linux-gnueabi" CGO_CXXFLAGS="-march=armv7-a -mfpu=neon  -mfloat-abi=hard -mcpu=cortex-a9 --sysroot=/opt/fsl-imx-fb/4.1.15-2.0.1/sysroots/cortexa9hf-neon-poky-linux-gnueabi" CGO_LDFLAGS="  --sysroot=/opt/fsl-imx-fb/4.1.15-2.0.1/sysroots/cortexa9hf-neon-poky-linux-gnueabi" go build

Compile is succuss but when I exec it return No such file or directory.

$ file hello
hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 2.6.32, BuildID[sha1]=cd89bbf6e60242498f31375ee63e89ef7ca9c1a3, not stripped

Could it be cross-compile toolchain problem?

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Jan 4, 2019

I assume you are copying the executable built with GOARCH=arm to an ARM system in order to run it. If you are getting "No such file or directory" on that system then the problem is almost certainly a disagreement about the location of the dynamic linker. You can use readelf -l EXECUTABLE to see the dynamic linker that it requests; look for the "Requesting program interpreter" line. See if that file exists on your ARM system. (When using cgo the dynamic linker is set by the C linker, and is not controlled by the Go tools.)

@Jexbat

This comment has been minimized.

Copy link
Author

@Jexbat Jexbat commented Jan 5, 2019

@ianlancetaylor sovled with ln -s /lib/ld-linux-armhf.so.3 /lib/ld-linux.so.3, thanks.
But I am still confused with plugin, if I compiled same plugin with different -pluginpath does two plugins share the same variable when I calling same func in two plugins?

hello.go

package main

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

type Greeter interface {
	Greet()
}

func main() {

	plug, err := plugin.Open("./plugins/scanner.so")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	symGreeter, err := plug.Lookup("Greeter")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	var greeter Greeter
	greeter, ok := symGreeter.(Greeter)
	if !ok {
		fmt.Println("unexpected type from module symbol")
		os.Exit(1)
	}
	greeter.Greet()
	print("=======\n")

	plug2, err := plugin.Open("./plugins/scanner2.so")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	symGreeter2, err := plug2.Lookup("Greeter")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	var greeter2 Greeter
	greeter2, ok2 := symGreeter2.(Greeter)
	if !ok2 {
		fmt.Println("unexpected type from module symbol")
		os.Exit(1)
	}

	greeter2.Greet()

}

scanner.go

package main

import "fmt"

type greeting string

var count int

func (g greeting) Greet() {
	count++
	fmt.Printf("Hello Universe %d\n", count)
}

// exported as symbol named "Greeter"
var Greeter greeting

scanner.go compiled with two different -pluginpath:

...  go build -ldflags "-pluginpath=p2" -buildmode=plugin -o scanner2.so scanner.go
...  go build -ldflags "-pluginpath=p1" -buildmode=plugin -o scanner.so scanner.go

result is:

root@imx6dlsabresd:/tmp# ls plugins/
scanner.so  scanner2.so
root@imx6dlsabresd:/tmp# ./hello
Hello Universe 1
=======
Hello Universe 2
root@imx6dlsabresd:/tmp#

Does it should be Hello Universe 1 and Hello Universe 1? It seems like two different plugins share same variable count.

@Jexbat

This comment has been minimized.

Copy link
Author

@Jexbat Jexbat commented Jan 5, 2019

I found change file name can solve this situation.Change scanner.go to scanner2.go then compile withoutpluginpath. result is:

root@imx6dlsabresd:/tmp# ./hello
Hello Universe 1
=======
Hello Universe 1

I think pluginpath just resolved plugin.open problem and still share variable in it.

@witwit

This comment has been minimized.

Copy link

@witwit witwit commented Aug 19, 2019

Hello,
Old thread, but still confused about a detail:
GOOS=linux GOARCH=arm does not work for plugins? Plugins do not run on linux/arm ? I have built a simple example, that builds a simple plugin like:
CC=arm-linux-gnueabi-gcc CGO_ENABLED=1 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags="-pluginpath=blah" -buildmode=plugin -o ./arm-dist/reader.linux.arm.so /app/plugins/rea der/...

No errors,

however when a main app on a raspberrypi tries to open the plugin, it says: could not open ./arm-dist/caller.linux.arm.so plugin: not implemented

is this the case? or did I miss something? somewhat of a showstopper...

@randall77

This comment has been minimized.

Copy link
Contributor

@randall77 randall77 commented Aug 19, 2019

@witwit: That should work. One thing you might be hitting - your main app also needs to be compiled with CGO_ENABLED=1.

@cherrymui

This comment has been minimized.

Copy link
Contributor

@cherrymui cherrymui commented Aug 19, 2019

@witwit this doesn't seem to be related to this issue, so I recommend discussing this somewhere else.

For your problem, how do you build the program that opens the plugin? In particular, is it built with cgo enabled?

@witwit

This comment has been minimized.

Copy link

@witwit witwit commented Aug 19, 2019

Oh, thank you, that got me a bit further. CGO_ENABLED=1 was missing for the main app, d'oh!
Now I am stuck at a different error message

could not open /home/pi/plugged/reader.linux.arm.so plugin.Open("/home/pi/plugged/reader.linux.arm.so"): /home/pi/plugged/reader.linux.arm.so: cannot open shared object file: No such file or directory

@witwit

This comment has been minimized.

Copy link

@witwit witwit commented Aug 19, 2019

@witwit this doesn't seem to be related to this issue, so I recommend discussing this somewhere else.

For your problem, how do you build the program that opens the plugin? In particular, is it built with cgo enabled?

yes, sorry. I truggle to find any infos on this at all. I will post a question on stack overflow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
6 participants
You can’t perform that action at this time.