• 隐藏侧边栏
  • 展开分类目录
  • 关注微信公众号
  • 我的GitHub
  • QQ:1753970025
Chen Jiehua

Golang的构建模式 

Golang的构建模式(buildmode)指的是编译器如何编译源码构建出相关的对象文件,最常见的情况下就是生成一个可执行的二进制文件。然而,其实golang的buildmode还有很多有趣的用法……

buildmode 一览

在 go build 和 go install 命令中,我们可以指定 -buildmode 参数来让编译器构建出特定的对象文件。通过命令 go help buildmode,可以看到其支持的选项:

排除掉最常用的 default,接下来我们就挑选几个比较有意思的来详细讲解一下。

c-archive C 静态链接库

说明:

Build the listed main package, plus all packages it imports, into a C archive file. The only callable symbols will be those functions exported using a cgo //export comment. Requires exactly one main package to be listed.

c-archive 也就是将 package main 中导出的方法(// export 标记)编译成 .a 文件,这样其它 c 程序就可以静态链接该文件,并调用其中的方法。

Go示例:

首先写一个简单 add.go :

然后使用 -buildmode=c-archive 编译:

生成两个文件: add.a 和 add.h,查看一下文件的类型:

 在 add.h 中我们看到 Add() 函数的定义:

C示例:

接下来,我们再写一个简单的 C 程序:

加上 add.a 文件编译一下:

生成一个可执行文件 a.out,执行 ./a.out:

c-shared C 动态链接库

说明:

Build the listed main package, plus all packages it imports, into a C shared library. The only callable symbols will
be those functions exported using a cgo //export comment. Requires exactly one main package to be listed.

c-shared 也就是将 package main 中导出的方法(// export 标记)编译成一个动态链接库(.so 或 .dll 文件),这样其它 c 程序就可以调用其中的方法。

Go示例:

继续使用上面的 add.go,改用 -buildmode=c-shared 来编译:

这次生成了 add.so 和 add.h 两个文件:

C示例:

继续使用上面的 myadd.c进行编译:

同样是生成了 a.out 可执行文件,但是留意一下前后两次的体积:

  • 使用 add.so 编译生成的 a.out 才 8.2KB;
  • 使用 add.a 编译生成的 a.out 有 1.8MB;

如果我们将 add.so 删除,再运行 a.out:

另外,我们也可以指定环境变量 LD_LIBRARY_PATH 告诉操作系统到哪里去寻找动态链接库:

版本要求:

G0 1.5

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.

G0 1.6

The implementation of build modes started in Go 1.5 has been expanded to more systems. This release adds support for the c-shared mode on android/386android/amd64android/arm64linux/386, and linux/arm64; for the shared mode on linux/386linux/armlinux/amd64, and linux/ppc64le; and for the new pie mode (generating position-independent executables) on android/386android/amd64android/armandroid/arm64linux/386linux/amd64linux/armlinux/arm64, and linux/ppc64le. See the design document for details.

Go 1.10

The various build modes have been ported to more systems. Specifically, c-shared now works on linux/ppc64lewindows/386, and windows/amd64pie now works on darwin/amd64 and also forces the use of external linking on all systems; and plugin now works on linux/ppc64le and darwin/amd64.

Go 1.11

The build modes c-shared and c-archive are now supported on freebsd/amd64.

shared Go动态链接库

说明:

Combine all the listed non-main packages into a single shared library that will be used when building with the -linkshared option. Packages named main are ignored.

shared 与 c-shared 类似,不过它是用来给 golang 构建动态链接库的。它将 非main 的package 编译为动态链接库,并在构建其他 go程序时使用 -linkshared 参数指定。

示例:

首先我们写一个非常简单的 hello.go:

然后,我们需要将 golang 的所有标准库 std 编译安装为 shared:

接着再用 -linkshared 编译 hello.go:

可以看到生成的可执行文件体积才 20KB ,相比正常的 go build hello.go 生成的 1.9MB 小非常多。我们可以使用 ldd 命令来查看调用链:

当然如果缺少了其中某个链接库或者版本不匹配,都将导致无法正常运行,所以一般情况下这种构建模式很少使用。

plugin Go插件

说明:

Build the listed main packages, plus all packages that they import, into a Go plugin. Packages not named main are ignored.

plugin 模式是 golang 1.8 才推出的一个特殊的构建方式,它将 package main 编译为一个 go 插件,并可在运行时动态加载。

示例:

首先,我们来写一个简单的 greeting:

然后将其编译为一个 go 插件:

再使用 golang 官方的 plugin 库来调用这个插件:

版本说明:

Go 1.8

Go now provides early support for plugins with a “plugin” build mode for generating plugins written in Go, and a new plugin package for loading such plugins at run time. Plugin support is currently only available on Linux. Please report any issues.

G0 1.10

The various build modes have been ported to more systems. Specifically, c-shared now works on linux/ppc64lewindows/386, and windows/amd64pie now works on darwin/amd64 and also forces the use of external linking on all systems; and plugin now works on linux/ppc64le and darwin/amd64.

 

参考:

码字很辛苦,转载请注明来自ChenJiehua《Golang的构建模式》

评论