gtk_text_view_get_buffer etc...). Notice that to make that possible the main program (cc1plus for GCCor gedit) has to be linked with the -rdynamic flag (to make the symbols of the main program visible from the plugin). Even if that is in theory principle, it is uncommon to dlopen a shared object which is not a plugin, designed and coded to call symbols from the main program (a program might in theory dlopen some
plain shared library like /usr/lib/x86_64-linux-gnu/libgdbm.so.3 but in practice this is never done; program loading plugins are dlopen-ing some
shared object -the plugin- specifically designed for them, and calling functions from the main program, and the main program uses dlsym to find some specific
symbols such as plugin_init for GCC obeying some signature convention). I deliberately ignore plugins loading other plugins (but I know about RTLD_GLOBAL flag to dlopen)
and I know about constructor function attributes in plugins.
In JAVA, there are class loaders with a sophisticated protocol for loading them.
In Ocaml, you have the dynlink library. The Dynlink.loadfile function is similar to dlopen (and will run the plugin initialization code).
There is no equivalent of dlsym: the plugin is supposed to e.g. register function values at initialization time, perhaps by passing them to
some function of the main program. Of course the plugin can call functions from the main program.
Plugins and packages in Go
The package concept is a core concept of Go since every source file belongs to some package (with main being a special case) and often imports several other ones.
Practically speaking, a Go plugin is likely to call functions from some package defined by the main program and having itself (the plugin) some packages. So the
tiny example in plugin documentation is a bit too naive (even if it is calling fmt.Printf). A realistic example would be a program having not only some main function
in its main package, but also defining some purple package having some Foo public function called as purple.Foo from main and having a Bar public function
(with purple.Bar called from the plugin). The plugin would have not only some public F function in its main package (which should call purple.Bar from the main
plugin-loading program) but also some plugin specific yellow package with a public Y function called (as yellow.Y) from F. I hope that such a realistic example will be
given in the documentation of future Go 1.9.
Plugins and packages in Go
The package concept is a core concept of Go since every source file belongs to some package (with main being a special case) and often imports several other ones.
Practically speaking, a Go plugin is likely to call functions from some package defined by the main program and having itself (the plugin) some packages. So the
tiny example in plugin documentation is a bit too naive (even if it is calling fmt.Printf). A realistic example would be a program having not only some main function
in its main package, but also defining some purple package having some Foo public function called as purple.Foo from main and having a Bar public function
(with purple.Bar called from the plugin). The plugin would have not only some public F function in its main package (which should call purple.Bar from the main
plugin-loading program) but also some plugin specific yellow package with a public Y function called (as yellow.Y) from F. I hope that such a realistic example will be
given in the documentation of future Go 1.9.
/// file purple.go of the main program
package purple
import "fmt"
func Foo(x int) { // called from main
fmt.Printf("purple.Foo has x=%d\n", x)
}
func Bar(s string) { // called from plugin
fmt.Printf("purple.Bar has s=%q\n", s)
}
/// eof purple.go
//file pluginyellow.go of the plugin
package yellow // the yellow package is in the plugin
import "fmt"
// we import the purple package from the main program
import "purple"
// in real life, yellow is importing a lot more of existing packages (e.g. sql)....
function F() { // this function is called from plugintop.go
fmt.Printf("in yellow.F\n")
purple.Bar("from yellow.F")
fmt.Printf("ending yellow.F\n")
}
function Gee () {
fmt.Printf("in yellow.Gee calling Foo with 345\n")
purple.Foo(345);
fmt.Printf("end yellow.Gee")
}
function GG() { // this ls looked up by the main program
fmt.Printf("in yellow.GG\n")
}
// eof pluginyellow.go
// file plugintop.go
package main
import "fmt"
import "yellow"
func init() {
fmt.Printf("init of plugintop\n")
yellow.F()
fmt.Printf("end of init of plugintop\n")
}
func Pub() { // this is looked up by the main program
fmt.Printf("in Pub of plugintop calling GG\n")
yellow.GG()
fmt.Printf("in Pub of plugintop ending\n")
}
// eof plugintop.go
// file purpleprog.go
package purple
import "fmt"
func Foo(x int) {
fmt.Printf("in purple.Foo x=%d\n", x)
}
func Bar(m string) {
fmt.Printf("in purple.Bar m=%q\n", m)
}
// eof purpleprog.go
// file mainprog.go
package main
import "fmt"
import "plugin"
import "purple"
func main() {
fmt.Printf("start of main in mainprog.go\n")
plug, err := plugin.Open("/tmp/plugin.so")
fmt.Printf("in mainprog plug=%v err=%v\n", plug, err)
if err != nil {
panic(fmt.Errorf("plugin.Open /tmp/plugin.so failed in mainprog with %v", err))
}
fmt.Printf("mainprog before call purple.Foo with 12751\n")
purple.Foo(12751)
fmt.Printf("mainprog after call purple.Foo with 12751\n")
symbPub, err := plug.Lookup("Pub")
fmt.Printf("in mainprog symbPub=%v err=%v\n", symbPub, err)
if err != nil {
panic(fmt.Errorf("Lookup of pub failed with %v", err))
}
funpub := symbPub.(func())
fmt.Printf("mainprog before calling funpub=%v\n", funpub)
funpub()
symbGG, err := plug.Lookup("yellow.GG")
fmt.Printf("in mainprog symbGG=%v err=%v\n", symbGG, err)
if err != nil {
panic(fmt.Errorf("Lookup of yellow.GG failed with %v", err))
}
funGG := symbPub.(func())
fmt.Printf("mainprog before calling funGG=%v\n", funGG)
funGG()
fmt.Printf("end of mainprog\n")
}
// end of file mainprog.go
Well, there are no Go plugin gurus, and to be honest I'm starting to
think it was a mistake to let the plugin package into 1.8. I know
that is not what you want to hear. It's in because the API seems OK,
but it has become clear that there are many related issues that we
haven't thought about.
If I understand your example, your plugin imports a package, and your
main program also imports the same package, and it's unfortunate that
the package gets linked into both the plugin and the main program.
That is true.
I think the only way to deal with is going to be to
compile the shared package with -buildmode=shared, and build both the
plugin and the main program with -linkshared. In fact that is what
you suggest. Does it work? I don't know whether it does or not.
-linkshared link against shared libraries previously created with -buildmode=shared.
multiple roots error message is really cryptic. It should be a lot more explicit.
Thanks for reading
--
Basile Starynkevitch (France)
go install -buildmode=shared std
And then I try to compile my plugin as shared:
go build -buildmode=plugin -linkshared /tmp/code_SUM.go
# command-line-arguments
runtime.islibrary: missing Go type information for global symbol: size 1
My code
# cat /tmp/code_SUM.go
package main
import (
"fmt"
)
func SUM(x int, y int) int { fmt.Println("")
return x+y}
Is there any workaround?