pkujhd / goloader

load and run golang code at runtime.
Apache License 2.0
497 stars 58 forks source link

linker 是不是设计成main.xx导出方法 #57

Closed lyh1091106900 closed 2 years ago

lyh1091106900 commented 2 years ago

我有两个文件,属于不同的包 ` package tools func Sub(a int, b int) int { return a - b } func Add(a int, b int) int { return a + b }

`

` package mathtools func Sub(a int, b int) int { return a - b + 3 } func Add(a int, b int) int { return a + b + 3 } func Add1(a int, b int) int { return a + b + 3 }

现在我使用 go tools compiler 编译两个文件输出两个.o文件,我发现linker里会把相同名字的覆盖掉,最后使用的时候也不是以包名作为 packange.xx来调用函数的,我想问这个是故意设计成这样还是我有哪些步骤漏了,我的代码是抄example的代码 package main import ( "flag" "fmt" "net/http" "os" "runtime" "strings" "sync" "unsafe" "github.com/pkujhd/goloader" )

type arrayFlags struct { File []string PkgPath []string }

func (i *arrayFlags) String() string { return "my string representation" }

func (i *arrayFlags) Set(value string) error { s := strings.Split(value, ":") i.File = append(i.File, s[0]) var path string if len(s) > 1 { path = s[1] } i.PkgPath = append(i.PkgPath, path) return nil }

func main(){ var files arrayFlags flag.Var(&files, "o", "load go object file") var pkgpath = flag.String("p", "", "package path") var parseFile = flag.String("parse", "", "parse go object file") var run = flag.String("run", "tools.Add", "run function") var times = flag.Int("times", 1, "run count") var enableStringContainer = flag.Int("s", 1, "enable string container")

flag.Parse()

if *parseFile != "" {
    parse(parseFile, pkgpath)
    return
}

if len(files.File) == 0 {
    flag.PrintDefaults()
    return
}

symPtr := make(map[string]uintptr)
err := goloader.RegSymbol(symPtr)
if err != nil {
    fmt.Println(err)
    return
}

w := sync.WaitGroup{}
goloader.RegTypes(symPtr, http.ListenAndServe, http.Dir("/"),
    http.Handler(http.FileServer(http.Dir("/"))), http.FileServer, http.HandleFunc,
    &http.Request{}, &http.Server{})
goloader.RegTypes(symPtr, runtime.LockOSThread, &w, w.Wait)
goloader.RegTypes(symPtr, fmt.Sprint)

if *enableStringContainer == 1 {
    goloader.OpenStringMap()
}

linker, err := goloader.ReadObjs(files.File, files.PkgPath)
if err != nil {
    fmt.Println(err)
    return
}

for i := 0; i < *times; i++ {
    codeModule, err := goloader.Load(linker, symPtr)
    if err != nil {
        fmt.Println("Load error:", err)
        return
    }
    runFuncPtr := codeModule.Syms[*run]
    if runFuncPtr == 0 {
        fmt.Println("files ", files)
        fmt.Println("linker ", linker)
        fmt.Println("codeModule.Syms ", codeModule.Syms)
        fmt.Println("Load error! not find function:", *run)
        return
    }
    funcPtrContainer := (uintptr)(unsafe.Pointer(&runFuncPtr))
    runFunc := *(*func(int,int)int)(unsafe.Pointer(&funcPtrContainer))
    l :=runFunc(1,3)
    fmt.Println("files ", files)
        fmt.Println("linker ", linker)
        fmt.Println("codeModule.Syms ", codeModule.Syms)
    fmt.Print("goLoader ", l)
    os.Stdout.Sync()
    codeModule.Unload()
}

}

func parse(file, pkgpath string) { if file == "" { flag.PrintDefaults() return } f, err := os.Open(file) if err != nil { fmt.Printf("%# v\n", err) return } obj, err := goloader.Parse(f, pkgpath) fmt.Printf("%# v\n", obj) f.Close() if err != nil { fmt.Printf("error reading %s: %v\n", file, err) return } } `

pkujhd commented 2 years ago

@lyh1091106900 包名导入的时候需要指定,不指定的时候默认为main,这个在参数pkgpath里

lyh1091106900 commented 2 years ago

这个项目是用来解决热更新的问题的吗?看上去像是一个plugin的替代方案

pkujhd commented 2 years ago

这个项目是用来解决热更新的问题的吗?看上去像是一个plugin的替代方案

是plugin的替代方案,但是我开始维护的时候的主要目标不是为了热更新,只是为了当作一种脚本执行器来使用,可以修复内存数据