pkujhd / goloader

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

Multi file compilation problem #53

Closed Liang2580 closed 2 years ago

Liang2580 commented 2 years ago

Hi! Your cases are all single file calls. My problem now is that there is a problem with multi file compilation

How can I compile multiple files into an o file suitable for the current project

For example:

package main

import (
    "fmt"
    "logs/system"
)

func main()  {
    fmt.Println(system.GetExternalIP())
}

system.go


package system
func GetExternalIP() (string, error) {
    response, err := http.Get("http://www.httpbin.org/ip")
    if err != nil {
        return "", errors.New("external IP fetch failed, detail:" + err.Error())
    }
    defer response.Body.Close()
    res := ""
    for {
        tmp := make([]byte, 32)
        n, err := response.Body.Read(tmp)
        if err != nil {
            if err != io.EOF {
                return "", errors.New("external IP fetch failed, detail:" + err.Error())
            }
            res += string(tmp[:n])
            break
        }
        res += string(tmp[:n])
    }
    return strings.TrimSpace(res), nil
}
pkujhd commented 2 years ago

@Liang2580 , hi, The file in package main and other in package system, so you could not compile them into one object file, could not tell goloader package information. You could compile the system package into an archive file, and load it with main package object at the same time

Liang2580 commented 2 years ago

我尝试使用go install 编译成.a 的系统包。 但是呢。会碰到一个问题。我开启了mod 的方式。 好像得关闭这种模式。回归到GOROOT 编译的方式才行。主要是这种方式不兼容mod的模式。这就会导致项目大了。就很麻烦。请问有啥解决方案吗。

Liang2580 commented 2 years ago

如果只能使用main 的单个文件编译的话。那太难受了。

pkujhd commented 2 years ago

@Liang2580

可以多个文件编译成一个.o, 但是必须在一个package下面,因为golang的compile默认这些函数在一个包里

如果你使用了go mod, .a 的产生方式如下,具体可以看另外一个issue https://github.com/pkujhd/goloader/issues/21#issuecomment-754521033

Liang2580 commented 2 years ago

也就是说。 例如main 包下的多个文件。算作一个package。其他的目录不能算作一个package 把。

pkujhd commented 2 years ago

一个package下面的文件都是这个package的

Liang2580 commented 2 years ago

通过 https://github.com/pkujhd/goloader/issues/21#issuecomment-754521033

进行测试如下:

[root@localhost test]# go get github.com/spf13/cast
[root@localhost test]# go build github.com/spf13/cast
[root@localhost test]# cat test.go  
package main

import "github.com/spf13/cast"
import "fmt"

func main() {
        fmt.Println(cast.ToInt(8))
}
[root@localhost test]# go build -x -n -v test.go 2>&1 | sed  -n "/^# import config/,/EOF$/p" |grep -v EOF > importcfg  
[root@localhost test]# go tool compile -importcfg importcfg test.go   
[root@localhost test]# 
[root@localhost test]# ls -l test.o 
-rw-r--r-- 1 root root 7758 May 29 16:55 test.o
[root@localhost test]# go build github.com/pkujhd/goloader/examples/loader
[root@localhost test]# ./loader -o test.o 
Load error: unresolve external:github.com/spf13/cast..inittask
[root@localhost test]# 

导入错误。

Liang2580 commented 2 years ago

importcfg 内容如下:

[root@localhost test]# cat importcfg 
# import config
packagefile fmt=/usr/local/go/pkg/linux_amd64/fmt.a
packagefile github.com/spf13/cast=/root/.cache/go-build/55/55adaf29b5e920e3c20f5b0f58fd3819aaf322f2ae72c5451477f43dcf825ef3-d
packagefile runtime=/usr/local/go/pkg/linux_amd64/runtime.a
[root@localhost test]# 
Liang2580 commented 2 years ago

实在没看懂你说的

你需要把obj里边要调用的函数注册一下,这样编译出来的loader里才有这个符号

pkujhd commented 2 years ago
packagefile github.com/spf13/cast=/root/.cache/go-build/55/55adaf29b5e920e3c20f5b0f58fd3819aaf322f2ae72c5451477f43dcf825ef3-d

@Liang2580, 这个是说你需要的cast的package在这个archive文件里(packagefile github.com/spf13/cast=/root/.cache/go-build/55/55adaf29b5e920e3c20f5b0f58fd3819aaf322f2ae72c5451477f43dcf825ef3-d)

如果你的loader里边没有使用到cast这个包,那么你需要加载这个archive文件, 使用goloader.RegTypes注册实际上就是使用到了

pkujhd commented 2 years ago

如果还有问题,reopen这个issue