On Monday, March 20, 2017 at 8:36:04 AM UTC+1, Basile Starynkevitch wrote:
> *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 <https://tip.golang.org/pkg/plugin/> 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. > > > To be more concrete, Here is the scenario I am thinking of: the main (plugin loading) program has some purple package in a purple.go file (probably in some purple/ directory): /// 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 Let's assume we have a /tmp/plugin.so binary plugin. Is is made from plugintop.go and pluginyellow.go and it has a yellow package and it calls purple.Bar. So here is pluginyellow.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 And here is the top file of the plugin, plugintop.go (I don't know in what directory it should go exactly): // 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 Our main program (which is loading the plugin) defines a purple package in some purpleprog.go file // 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 Of course we need a main in our program, file mainprog.go is loading the /tmp/plugin.so plugin // 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 In real life, the purple package inside the main program which is also used by the plugin is actually using a lot of code in many other packages (e.g. go-sqlite, os/exec, and so on). *So here are my questions:* What is (or are) the exact *build command of the main program* (we need to compile both mainprog.go & purpleprog.go files...). I suspect that -buildmode=shared would be useful when compiling purpleprog.go but I am not sure. I suspect that -linkshared should be used when compiling mainprog.go What is (or are) the exact* build command of the plugin* (we need to compile both pluginyellow.go & plugintop.go files...). I expect the plugin to be compiled failrly quickly so I would like the purple package (and all its dependencies) to be external to it, and not be compiled with the plugin (just linked to it). I really want to avoid compiling twice the purple package (which actually is quite big and using many other packages). *I might have misunderstood how plugins work*. IMHO there should be some way to indicate to the compiler -when compiling the plugin- that the purple package is available in the main program. Perhaps the -buildmode=plugin mode might also accept a -loaded-from-program argument giving the main executable program that is loading it (so that the compiler can reuse and inspect packages available in the main program, like purple). Perhaps there should be some way (I was suggesting import "purple" // import "*" in my previous message) to indicate inside the source code of a plugin that a package should be imported and available from the main program. (perhaps I might have identified an issue in the current Go1.8 implementation of plugins; if I did, please tell, and say me if I could hope that issue to be covered in Go1.9) Regards, thanks for reading! Basile Starynkevitch <http://starynkevitch.net/Basile/>(France); my email is bas...@starynkevitch.net if you need to answer me privately. PS. I really hope that some Go plugin guru would answer my messages! -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.