Open JesseGuoX opened 5 years ago
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/
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?
@Jexbat Plugin is supported on Linux/ARM.
@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?
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.)
@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
.
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.
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...
@witwit: That should work. One thing you might be hitting - your main app also needs to be compiled with CGO_ENABLED=1.
@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?
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 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.
# plugin code in plugin/hello.go
package main
import "fmt"
var V int
func F() { fmt.Printf("Hello, number %d\n", V) }
# main in main.go
package main
import "plugin"
func main() {
p, err := plugin.Open("plugin/hello.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"
p, err = plugin.Open("plugin/hello2.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
// *v.(*int) = 7
f.(func())() // prints "Hello, number 7"
}
go build -trimpath -ldflags "-pluginpath=plugin/hot-$(date +%s)" -buildmode=plugin -o plugin/hello.so plugin/hello.go
go build -trimpath -ldflags "-pluginpath=plugin/hot-$(date +%s)" -buildmode=plugin -o plugin/hello2.so plugin/hello.go
go run -trimpath main.go
panic: plugin.Open("plugin/hello"): could not find symbol V: dlsym(0x100205980, plugin/hot-1670990324.V): symbol not found
goroutine 1 [running]:
main.main()
./main.go:8 +0x4ae
exit status 2
nm plugin/hello.so| grep '.V' 00000000001d6e68 S _plugin/unnamed-b2203a0be6431d575e0f9179980c3c58f09e7987.V 000000000007e200 t _reflect.(*MapIter).Value
Is there something wrong with compiling the symbol table?
Ok, as this is a duplicate, do we have some work arounds for more modern go versions that would allow us to:
I particularly mention this as buildvcs is a recent addition, and there's -pluginpath
https://github.com/golang/go/issues/19418 ; seems both options have no effect in plugin builds. Trimpath for plugins should, if anything, replace the plugin path with name.$(date +%s)
or some equivalent?
Is there any approach considered in resolving this in the toolchain? Would we need a proposal to discuss a change, submit patches, or how can we move this forward?
@ianlancetaylor @cherrymui as cmd/link and plugins package owners, I would appreciate your input and perhaps guidance towards contributing a patch, priorities permitting.
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
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?