Go 編譯(Build mode)介紹

編譯模式(Build mode)介紹

go 的編譯模式有下列幾種:
* static exe
* exe with libc
* exe with libc and non-Go code
* pie
* c-archive
* c-shared
* shared
* plugin

編譯基本語法

usage: go build [-o output] [-i] [build flags] [packages]

// 等義的命令
go build
go build .
go build hello.go

// 編譯目錄下的所有程式
go build flysnow.org/tools/...

static exe

  • All code is in one binary. No other userspace dependencies. ex: go build hello.go
  • Great in tiny containers.
  • Works in across distributions.

exe with libc

  • when program is executed, libc is loaded.
  • Used by net or DNS and os/user for user name lookup
  • This mode lets a Go program use that OS configuration.
  • Programs dependent on user-space.

exe with libc and non-Go code

  • When program is built, the linker knows about some non-Go code(C, Fortran, anything following the ELF ABI). The non-Go code can be called via cgo.
  • Non-Go code can be built into the binary, or loaded when the program is started.
  • Good for working with legacy system.
  • Builds are more complex.
  • C is not Go

編譯建議

  • build 的時候都加上 CGO_ENABLED=0 GOOS=linux GOARCH=amd64

pie

  • Position Independent Executables
  • A relatively minor build mode. Programs behave just as they do with the exe build mode.
  • Reading the technology tea leaves, PIE binaries will prbably be the norm in the future.(Security)
  • The same as exe, except:
    • Systems are a bit harder to attack.
    • Currently binaries are bigger.(Bug.)
    • Small ~ 1% performance cost.

c-archive

  • Take a Go program and bundle it into an archive(.a) file.
  • C programs can statically link it.
  • Integrate Go into an existing C program.
  • This is how Go on iOS works.
  • very useful when the non-Go build is pre-existing and extremely complex.
  • Cross-language calls in Go are tricky.
// hello.go
package main

import(
   "fmt"
     "C"
)

func main() { }

// export Hello, Exports a symbol visible to C
func Hello() {
   fmt.Println("Hello, World.")
}

// hello.c
# include "hello.h"
int main(void) {
   Hello();
     return 0;
}
// 編譯及執行
$>go build -buildmode=c-archive hello.go
$>cc hello.a hello.c
$>./a.out
Hello, World.

c-shared

  • Build a Go program as a shared object(.so) file.
  • C programs can dynamically link it.
  • Integrate Go into an existing C program.
  • Can be loaded at run time.
  • This is how Go works in Android apps.
  • Cross-language calls in Go are tricky.
    c-shared
$>go build -buildmode=c-shared hello.go
$>cc hello.c hello.so
$>LD_LIBRARY_PATH=../a.out
Hello, World.
  • hello-dyn.c
#include <dlfcn.h>

int main(void) {
   void *lib = dlopen("hello", 0);
     void *fn = dlsym(lib, "Hello");

     if(!fn) {
        fprintf(stderr, "no fn: %s\n", dlerror());
            return 1;
     }
     ((void (*))fn)(); // Calls Hello()
     return 0;   
}

shared

  • The shared build mode bundles Go packages into a shared library that can be dynamically linked by a Go binary.
  • A number of binaries share .so files.
  • This is how many OSs hadle binaries created in other languages.
  • Can save a little disk space, but that’s not important any more.
  • Can save RAM.
  • Managing deployment is harder.
// hi.go
package main

import "fmt"

func main() {
   fmt.Println("Hello, World.")
}
  • 編譯
$>go install -buildmode=shared std
$>go build -linkshared hi.go
$>./hi
Hello, World.

$>ls -l hi
-rwxr-x--- 1 crawshaw 16123 hello
$>ldd hi
   linux-vdso.so.1 => (...)
     libstd.so => $GOROOT/.../libstd.so (...)
     libc.so.6 => /lib/.../libc.so.6 (...)

plugin

  • The plugin build mode bundles Go packages into a shared library that can be dynamically loaded by the plugin package.
  • Let Go in go at run time.
  • Allows different parts of a single program to be built at different times.
  • Complex build and deployment.

$GoPATH/…/myplugin/myplugin.go

package main

import "fmt"

func main() {
   fmt.Println("Hello, World.")
}
// funplugin.go
package main

import "plugin"

func main() {
   p, err := plugin.Open("myplugin")    // ...handle err
     fn, err := p.Lookup("Hello")    // ...handle err
     fn.(func())()
}
  • 編譯
$>go build -buildmode=plugin myplugin
$>go build runplugin.go
$>./runplugin
Hello, World.

範例

example