Go语言编译模式浅谈

Golang里你不知道的小秘密

Posted by hughnian on December 29, 2020

buildmode

在刚开始接触Go语言时,就觉得它的编译比C/C++的gcc/g++方便很多,一个简单的go build命令可以完成所有gcc/g++的事情,不过之前的使用都是简单使用,编译成 可执行文件,如果想要编译成动态库什么这里就需要用到buildmode参数,当然这个参数的功能远不止编译成动态库这一项。参数的使用也完全就是go build命令完成, 不得不说Go的方便,ps: go install命令同样可以运行此参数。

buildmode的值

buildmode参数主要作用用来让Go编译器构建出特定的对象文件,目前它支持以下特定值,每个值得含义如下。

  • -buildmode=archive
    Build the listed non-main packages into .a files. Packages named main are ignored.
    把源文件编译成Go语言得静态库文件,如果包名为main会被忽略掉

  • -buildmode=c-archive 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. 这个就厉害了,这个命令可以把你的Go源文件编译成C语言可以使用的静态库,也就是.a文件,C语言程序就可以使用你用Go语言编写的程序了

  • -buildmode=c-shared
    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-开头的说明他们都是可以被C语言程序调用,这里的命令可以把Go源文件编译成C语言可以使用的动态库文件,也就是.so文件或者.dll文件

  • -buildmode=default
    Listed main packages are built into executables and listed non-main packages are built into . a files (the default behavior). 就是默认编译方式

  • -buildmode=shared
    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. 这个是把Go源文件编译成Go语言可以使用的静态库文件,C语言不能使用,它将非main的package编译为动态链接库,并在构建其他 Go程序时使用 -linkshared 参数来指定, 编译Go动态库go install -buildmode=shared std,需要注意的是-buildmode=shared暂不支持macOS,使用Go动态库go build -linkshared hello.go

  • -buildmode=exe
    Build the listed main packages and everything they import into executables. Packages not named main are ignored. 这就不用多说了,就是编译成.exe文件,包名为main的忽略

  • -buildmode=pie
    Build the listed main packages and everything they import into position independent executables (PIE). Packages not named main are ignored. 这个参数也是十分的有用,编译带上这个参数可以让你的Go程序更安全,没法反编译,即使反编译了也看不懂

  • -buildmode=plugin
    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 插件,并可在运行时动态加载。可以理解为Go语言的动态库,当然C语言不能使用 实列代码如下

          package main
             
          import "fmt"
             
          type gethw string
             
          func (g gethw) HelloWorld() {
           fmt.Println("hello world")
          }
             
          var GetHelloWorld gethw
    
          package main
             
          import (
           "fmt"
           "os"
           "plugin"
          )
             
          type GetHelloWorld interface {
           HelloWorld()
          }
             
          func main() {
           plug, err := plugin.Open("./test/helloworld.so")
           if err != nil {
              panic(err)
           }
             
           getplug, err := plug.Lookup("GetHelloWorld")
           if err != nil {
              panic(err)
           }
             
           var hw GetHelloWorld
           hw, ok := getplug.(GetHelloWorld)
           if !ok {
              fmt.Println(err)
              os.Exit(1)
           }
             
           hw.HelloWorld()
          }