从go二进制文件动态构建和链接

Jér*_*e R 15 go

我的问题如下:

  1. 我在机器上有二进制文件
  2. 从那个二进制文件我需要编译外部.go文件
  3. 编译完成后,我需要将已编译的go文件链接到当前的二进制文件中,以便我可以使用刚刚编译的go代码.

你觉得这可能吗?

我做了一些研究,似乎不太可能,但我可能忽略了一些东西.

谢谢 :)

第一个二进制文件包含类似的内容

func main() {
    // Here I need to compile an external go file (or package) which contains
    // The definition of runFoo()

    // Once the file/package is compiled and linked I need to call the compiled code
    runFoo()

    // Continue the execution process normally here
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*e C 23

创建共享库的能力将在2015年8月的Go 1.5中进行.

来自安德鲁·格兰德的" 走出去 "讲话:

共享库

Go 1.5可以生成Go程序可以使用的Go共享库.

将标准库构建为共享库:

$ go install -buildmode=shared std
Run Code Online (Sandbox Code Playgroud)

构建一个链接共享库的"Hello,world"程序:

$ go build -linkshared hello.go
$ ls -l hello
-rwxr-xr-x 1 adg adg 13926 May 26 02:13 hello
Run Code Online (Sandbox Code Playgroud)

Go 1.5还可以将Go程序构建为可由C程序使用的C归档文件(用于静态链接)或共享库(用于动态链接).

[见:] golang.org/s/execmodes

¹注意,gccgo已经有一段时间对此有限的支持,Go 1.5将是第一次得到常规go构建工具的支持.


voi*_*gic 11

更新:现在可以在主线Go中执行此操作,请参阅执行模式

Go 1.5发行说明:

仅对于amd64体系结构,编译器有一个新选项-dynlink,它通过支持对外部共享库中定义的Go符号的引用来协助动态链接.

旧答案(其他选项的有用讨论):

目前无法在主线Go中创建动态链接库*.有一些关于此的讨论,所以你可能会看到将来的支持.但是,有一个名为goandriod的第三方go项目需要您需要的相同功能,因此他们维护补丁,允许您修补官方Go代码库以支持您请求的动态链接支持.

如果您想使用标准的Go运行时,我会推荐以下之一.从您的其他程序调用您的Go程序,并使用以下方式进行通信:

  1. 管道沟通
  2. UNIX域套接字
  3. 共享内存的mmaped区域.
    1. 那就是在/ dev/shm上创建一个文件并让两个程序都映射它.
    2. 去mmap库:https://github.com/edsrzf/mmap-go

每个连续选项将需要更多的设置,更具体的平台,但可能比前一个更强大.

*注意:这是Windows世界中的DLL,以及UNIX/Linux世界中的.so文件.


vvr*_*kin 6

我认为go plugins也可能与这个问题有关,go 1.8 版支持它们。它允许您在运行时动态链接实现所需接口的 go 二进制文件。

例如,您的代码依赖于日志记录后端,但您希望支持其中的几个并在运行时解决它,elasticsearch并且splunk可以适合此处。您可能需要有 2 个文件:es.go并且splunk.go它们都应该包含一个LoggingBackend实现 method类型的结构体Write(log string)

要创建插件,您需要plugin在编译期间使用 buildmode :

去构建 -buildmode=plugin -o es.so es.go

去构建 -buildmode=plugin -o splunk.so splunk.go

之后,您可以通过命令行参数传递所需的插件并加载它:

package main

import "plugin"
import "flag"


type LoggingBackend interface {
    Write(log string)
}
var (
    backend = flag.String("backend", "elasticsearch", "Default logging backend is elasticsearch")
)

func main() {
    flag.Parse()
    var mode string
    switch backend {
    case "elasticsearch":
        mode = "./es.so"
    case "splunk":
        mode = "./splunk.so"
    default:
        fmt.Println("Didn't recognise your backend")
        os.Exit(1)
    plug, _ := plugin.Open(mod)
    loggingBackend, _ := plug.Lookup("LoggingBackend")
    logWriter, _ := loggingBackend.(LoggingBackend)
    logWriter.Write("Hello world")
}
Run Code Online (Sandbox Code Playgroud)