20

我的问题如下:

  1. 我在机器上有一个 go 二进制文件
  2. 从该二进制文件中,我需要编译一个外部 .go 文件
  3. 编译完成后,我需要将编译后的 go 文件链接到当前二进制文件中,这样我就可以使用刚刚编译的 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
}
4

5 回答 5

27

创建共享库的功能将于 2015 年 8 月在 Go 1.5 中提供¹。

来自 Andrew Gerrand 的“ 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 构建工具支持。

于 2015-05-27T16:29:58.357 回答
14

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

Go 1.5 发行说明

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

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

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

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

  1. 用于通信的管道
  2. 一个 UNIX 域套接字
  3. 共享内存的映射区域。
    1. 也就是说,在 /dev/shm 上创建一个文件并让两个程序对其进行映射。
    2. Go mmap 库:https ://github.com/edsrzf/mmap-go

每个连续的选项都将花费更多的精力来设置,更加特定于平台,但可能比前一个选项更强大。

*注意:即 Windows 世界中的 DLL 和 UNIX/Linux 世界中的 .so 文件。

于 2013-11-12T02:32:46.903 回答
7

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

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

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

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")
}
于 2018-07-23T05:23:49.260 回答
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 --defined-only ./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

像这样(在 go 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")
}
于 2015-11-03T17:29:00.970 回答
0

自 1.5 起推出的功能 :) http://talks.golang.org/2015/state-of-go-may.slide#23

于 2015-05-27T15:00:22.637 回答