构建和链接动态库的go二进制文件。

huangapple go评论87阅读模式
英文:

Building and linking dynamically from a go binary

问题

你的问题是:

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

你认为这个可能吗?

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

谢谢 构建和链接动态库的go二进制文件。

第一个Go二进制文件可能包含以下内容:

func main() {
    // 在这里我需要编译一个包含runFoo()定义的外部go文件(或包)

    // 一旦文件/包被编译和链接,我需要调用编译好的代码
    runFoo()

    // 在这里继续正常执行过程
}
英文:

My problem is the following:

  1. I have a go binary on a machine
  2. From that binary I need to compile an external .go file
  3. Once compiled, I need to link the compiled go file into the current binary so I can use the just-compiled go code.

Do you think that's possible ?

I did a few researches and it does not seem to be possible, but I might have overlooked something.

Thanks 构建和链接动态库的go二进制文件。

The first go binary would contain something like

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
}

答案1

得分: 29

能够创建共享库的功能将在Go 1.5中推出,预计在2015年8月发布。

根据Andrew Gerrand在“Go的现状”演讲中的说法:

共享库

Go 1.5可以生成可以被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构建工具首次支持此功能的版本。

英文:

The ability to create shared libraries will be in Go 1.5 in August 2015¹.

From "The State of Go" talk by Andrew Gerrand:

> Shared libraries
> ----------------
>
> Go 1.5 can produce Go shared libraries that can be consumed by Go
> programs.
>
> Build the standard library as shared libraries:
>
> $ go install -buildmode=shared std
>
> Build a "Hello, world" program that links against the shared
> libraries:
>
> $ go build -linkshared hello.go
> $ ls -l hello
> -rwxr-xr-x 1 adg adg 13926 May 26 02:13 hello
>
> Go 1.5 can also build Go programs as C archive files (for static
> linking) or shared libraries (for dynamic linking) that can be
> consumed by C programs.
>
> [See:] golang.org/s/execmodes

<sub>¹ Note, gccgo already had limited support for this for some time, Go 1.5 will be the first time this is supported by the regular go build tools.</sub>

答案2

得分: 16

**更新:**现在在Go的主线版本中可以实现这一点,请参阅Go执行模式

根据Go 1.5发布说明

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

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

目前在Go的主线版本中无法创建动态链接库。关于这个问题已经有一些讨论,所以将来可能会看到支持。然而,有一个第三方的Go项目叫做goandroid,它需要与您相同的功能,所以他们维护了一些补丁,应该可以让您打补丁到官方的Go代码库中,以支持您所请求的动态链接支持。

如果您想使用标准的Go运行时,我建议使用以下其中一种方法来与其他程序进行通信:

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

每个连续的选项都需要更多的设置工作,更加依赖于平台,但可能比前一个选项更强大。

***注意:**在Windows世界中是DLL文件,在UNIX/Linux世界中是.so文件。

英文:

Update: It is now possible to do this in mainline Go, see Go Execution Modes

From the Go 1.5 release notes:

> For the amd64 architecture only, the compiler has a new option,
> -dynlink, that assists dynamic linking by supporting references to Go symbols defined in external shared libraries.

Old Answer (useful discussion of other options):

It is not currently possible to create dynamically linked libraries* in main line Go. There has been some talk about this, so you may see support in the future. However, there is a 3rd party go project called goandroid that needed the same functionality you need, so they maintain patches that should allow you to patch the official Go code base to support the dynamic linked support you are requesting.

If you want to use a the standard Go run-time, I would recommend the one of the following.
Invoke your Go program from your other program, and communicate using:

  1. Pipes to communicate
  2. A UNIX domain socket
  3. An mmaped region of shared memory.
  4. That is, create a file on /dev/shm and have both programs mmap it.
  5. The Go mmap library: https://github.com/edsrzf/mmap-go

Each consecutive option will take more effort to setup, be more platform specific, but potentially be more powerful than the previous one.

*Note: That is, DLLs in the Windows world, and .so files in the UNIX/Linux world.

答案3

得分: 7

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

例如,你的代码依赖于一个日志后端,但你希望支持多个后端并在运行时解决它,elasticsearchsplunk可能适用于这里。
你可能需要有两个文件: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(mode)
    loggingBackend, _ := plug.Lookup("LoggingBackend")
    logWriter, _ := loggingBackend.(LoggingBackend)
    logWriter.Write("Hello world")
}
英文:

I think go plugins could be also related to this question, they are supported from go version 1.8. It allows you to dynamically link go binaries implementing required interfaces at runtime.

For example your code has a dependency for a logging backend, but you'd like to support several of them and resolve it at runtime, elasticsearch and splunk could fit here.
You might need to have 2 files: es.go and splunk.go which should both contain a struct of type LoggingBackend implementing a method Write(log string).

To create plugins you need to use buildmode plugin during compilation:
> go build -buildmode=plugin -o es.so es.go
>
> go build -buildmode=plugin -o splunk.so splunk.go

After that you could pass the needed plugin via command line arguments and load it:

package main

import &quot;plugin&quot;
import &quot;flag&quot;


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

func main() {
    flag.Parse()
    var mode string
    switch backend {
    case &quot;elasticsearch&quot;:
        mode = &quot;./es.so&quot;
    case &quot;splunk&quot;:
        mode = &quot;./splunk.so&quot;
    default:
        fmt.Println(&quot;Didn&#39;t recognise your backend&quot;)
        os.Exit(1)
    plug, _ := plugin.Open(mod)
    loggingBackend, _ := plug.Lookup(&quot;LoggingBackend&quot;)
    logWriter, _ := loggingBackend.(LoggingBackend)
    logWriter.Write(&quot;Hello world&quot;)
}

答案4

得分: 3

这是非常可能的,你甚至可以将其编译为本地共享库。

go build -buildmode=c-shared goc.go

文件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")
}
英文:

This is very possible, you can even compile it as a native shared library

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

like so (tested on go 1.5.1 linux/arm)

goc.go:

package main

import (
    &quot;C&quot;
    &quot;fmt&quot;
)

//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&#39;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(&quot;Hello world&quot;)
}

答案5

得分: 0

1.5版本中承诺的功能 构建和链接动态库的go二进制文件。
http://talks.golang.org/2015/state-of-go-may.slide#23

英文:

Feature promiced since 1.5 构建和链接动态库的go二进制文件。
http://talks.golang.org/2015/state-of-go-may.slide#23

huangapple
  • 本文由 发表于 2013年10月17日 23:44:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/19431296.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定