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.

Reply via email to