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

时间:2013-10-17 15:44:00

标签: go

我的问题如下:

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

    我做了一些研究,似乎不太可能,但我可能忽视了一些事情。

    谢谢:)

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

    的内容
    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
    }
    

5 个答案:

答案 0 :(得分:21)

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

来自安德鲁·格兰德的“The State of Go”演讲:

  

共享库

     

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

     

将标准库构建为共享库:

$ go install -buildmode=shared std
     

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

$ go build -linkshared hello.go
$ ls -l hello
-rwxr-xr-x 1 adg adg 13926 May 26 02:13 hello
     

Go 1.5也可以将Go程序构建为C档案文件(对于静态文件)   可以是链接)或共享库(用于动态链接)   被C程序消耗。

     

[见:] golang.org/s/execmodes

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

答案 1 :(得分:10)

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

来自Go 1.5 release notes

  

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

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

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

如果您想使用标准的Go运行时,我建议您使用以下其中一项。 从您的其他程序调用您的Go程序,并使用以下方式进行通信:

  1. 管道沟通
  2. UNIX域套接字
  3. 共享内存的mmaped区域。
    1. 这是在/ dev / shm上创建一个文件并让两个程序都映射它。
    2. 转到mmap库:https://github.com/edsrzf/mmap-go
  4. 每个连续选项都需要花费更多精力进行设置,更具针对性,但可能比前一个更强大。

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

答案 2 :(得分:3)

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

例如,您的代码对日志记录后端具有依赖性,但是您想支持其中的几个并在运行时解决它,elasticsearchsplunk可能适合这里。 您可能需要有2个文件:es.gosplunk.go,它们都应包含实现方法LoggingBackend的类型Write(log string)的结构。

要创建插件,您需要在编译过程中使用构建模式plugin

  

go build -buildmode = plugin -o es.so es.go

     

go build -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")
}

答案 3 :(得分:2)

这很有可能,您甚至可以将其编译为本机共享库

go build -buildmode=c-shared goc.go 

# file goc
goc: ELF 32-bit LSB  shared object, ARM, EABI5 version 1 (SYSV),
dynamically linked, 
BuildID[sha1]=f841e63ee8e916d7848ac8ee50d9980642b3ad86, 
not stripped

nm -D - 仅限定义./goc | grep“T”

0004ebe8 T _cgoexp_f88ec80374ab_PrintInt
000a6178 T _cgo_panic
0004e954 T _cgo_sys_thread_start
000a48c8 T _cgo_topofstack
0004e88c T _cgo_wait_runtime_init_done
000a61a4 T crosscall2
0004ebc8 T crosscall_arm1
0004e7b0 T fatalf
00102648 T _fini
0004e544 T _init
0004e76c T PrintInt
0004ebe4 T __stack_chk_fail_local
0004eb5c T x_cgo_free
0004ea60 T x_cgo_init
0004eb24 T x_cgo_malloc
0004e8e0 T x_cgo_notify_runtime_init_done
0004eb14 T x_cgo_setenv
0004e820 T x_cgo_sys_thread_create
0004eb64 T x_cgo_thread_start
0004eb20 T x_cgo_unsetenv
像这样(在1.5.1 linux / arm上测试)

goc.go:

package main

import (
    "C"
    "fmt"
)

//export PrintInt
func PrintInt(x int) {
    fmt.Println(x)
}

// http://stackoverflow.com/questions/32215509/using-go-code-in-an-existing-c-project
// go build -buildmode=c-archive goc.go
// go build -buildmode=c-shared goc.go 

// https://groups.google.com/forum/#!topic/golang-nuts/1oELh6joLQg
// Trying it on windows/amd64, looks like it isn't supported yet.  Is this planned for the 1.5 release? 
// It will not be in the 1.5 release.
// It would be nice if somebody worked on it for 1.6.
// https://golang.org/s/execmodes

// http://stackoverflow.com/questions/19431296/building-and-linking-dynamically-from-a-go-binary
// go build -linkshared hello.g
// go install -buildmode=shared std



func main() {
    fmt.Println("Hello world")
}

答案 4 :(得分:-1)