Skip to content

Instantly share code, notes, and snippets.

@podhmo
Last active August 11, 2024 15:06
Show Gist options
  • Save podhmo/b472609ee211f520c519fb4eda7d3cb7 to your computer and use it in GitHub Desktop.
Save podhmo/b472609ee211f520c519fb4eda7d3cb7 to your computer and use it in GitHub Desktop.
package main
// https://pkg.go.dev/plugin
// need: go build -buildmode=plugin
import (
"fmt"
_ "m/x"
)
var V int
func F() { fmt.Printf("Hello, number %d\n", V) }
package main
import _ "m/x"
type Person struct {
Name string
Age int
Father *Person
Mother *Person
}
func New(name string, age int) *Person {
return &Person{Name: name, Age: age}
}
func Empty() Person {
return Person{}
}
package main
import (
"m/shape"
_ "m/x"
)
func New(name string, age int) *shape.Person {
return &shape.Person{Name: name, Age: age}
}
module m
go 1.22.1
package main
import (
"fmt"
"m/shape"
"plugin"
)
func main() {
useA()
fmt.Println("----------------------------------------")
useB()
fmt.Println("----------------------------------------")
useC()
}
func useA() {
p, err := plugin.Open("bin/.plugin_a.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"
}
func useB() {
// p, err := plugin.Open("bin/.plugin_b.so")
// if err != nil {
// panic(err)
// }
// // panic: runtime error: invalid memory address or nil pointer dereference
// {
// sym, err := p.Lookup("Empty")
// if err != nil {
// panic(err)
// }
// // Use unsafe to convert the symbol to the correct type
// empty := *(*func() shape.Person)(unsafe.Pointer(&sym))
// ob := empty()
// fmt.Printf("Empty: %v\n", ob)
// }
// // interface conversion: plugin.Symbol is func(string, int) *main.Person, not func(string, int) *main.Person (types from different scopes)
// {
// sym, err := p.Lookup("New")
// if err != nil {
// panic(err)
// }
// newPerson := sym.(func(string, int) *shape.Person)
// person := newPerson("Alice", 30)
// fmt.Printf("Person: %+v\n", person)
// }
}
func useC() {
p, err := plugin.Open("bin/.plugin_c.so")
if err != nil {
panic(err)
}
sym, err := p.Lookup("New")
if err != nil {
panic(err)
}
newPerson := sym.(func(string, int) *shape.Person)
person := newPerson("Alice", 30)
fmt.Printf("Person: %+v\n", person)
}
default: clean
mkdir -p bin
tree > tree.out
go build -buildmode=plugin -o bin/.plugin_a.so ./plugins/a
go build -buildmode=plugin -o bin/.plugin_b.so ./plugins/b
go build -buildmode=plugin -o bin/.plugin_c.so ./plugins/c
go build -o bin/foo ./
./bin/foo
clean:
rm -rf bin
package shape
type Person struct {
Name string
Age int
Father *Person
Mother *Person
}
.
├── Makefile
├── bin
├── go.mod
├── main.go
├── plugins
│   ├── a
│   │   └── a.go
│   ├── b
│   │   └── b.go
│   └── c
│   └── c.go
├── shape
│   └── shape.go
├── tree.out
└── x
└── x.go
8 directories, 9 files
package x
import "fmt"
var V = 10
func init() {
V++
fmt.Println("on init, V is", V)
}
@podhmo
Copy link
Author

podhmo commented Aug 11, 2024

$ make
rm -rf bin
mkdir -p bin
tree > tree.out
go build -buildmode=plugin -o bin/.plugin_a.so ./plugins/a
go build -buildmode=plugin -o bin/.plugin_b.so ./plugins/b
go build -buildmode=plugin -o bin/.plugin_c.so ./plugins/c
go build -o bin/foo ./
./bin/foo
on init, V is 11
Hello, number 7
----------------------------------------
----------------------------------------
Person: &{Name:Alice Age:30 Father:<nil> Mother:<nil>}

@podhmo
Copy link
Author

podhmo commented Aug 11, 2024

initは一回で済むのか

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment