buildmode 编译不同结果

最后更新于:2022-04-02 02:51:06

[TOC] ## 概述 - 可通过 `go/官方包/plugin` 路径查看对比查看 ## 命令 ``` -buildmode=archive 构建non-main packages成 .a 文件(静态库), -buildmode=c-archive c-archive 也就是将 package main 中导出的方法(// export 标记)编译成 .a 文件, 这样其它 c 程序就可以静态链接该文件,并调用其中的方法 -buildmode=c-shared 构建C共享库 -buildmode=default -buildmode选项的默认参数,把main packages构建成可执行文件,non-main packages构建成 .a 静态库。 -buildmode=shared 把所有non-main packages构建成一个go 共享库,可以使用-linkshared选项进行链接。 -buildmode=exe 把 main packages以及它import的任何文件,构建成可执行文件。 -buildmode=pie 把 main packages以及它impiort的任何文件,构建成位置无关的目标文件(可重定位文件) -buildmode=plugin 把 main packages以及它import其他packages,构建成一个go plugin. ``` ## 实例 ### -buildmode=c-archive
add.go ``` package main import "fmt" import "C" func main() {} //export Add func Add(a, b int) int { fmt.Printf("%d + %d = %d\n", a, b, a+b) return a + b } ```

myadd.c ``` # include "add.h" int main(void) { Add(1, 2); return 0; } ```

运行 ``` > go build -buildmode=c-archive add.go > cc myadd.c add.a > ./a.out ``` > 使用 add.a 编译生成的 a.out 有 1.8MB; ### -buildmode=c-shared 使用上个实例的 add.go,和 myadd.c ``` > go build -buildmode=c-shared -o add.so add.go > cc myadd.c add.so > cc myadd.c add.so ``` > 使用 add.so 编译生成的 a.out 才 8.2KB; ### -buildmode=shared
hello.go ``` package main import "fmt" func main() { fmt.Println("hello world") } ```

执行 ``` > go install -buildmode=shared std > go build -linkshared hello.go > ldd hello linux-vdso.so.1 (0x00007ffcb0db9000) libstd.so => /usr/local/go/pkg/linux_amd64_dynlink/libstd.so (0x00007f2d5c1cb000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2d5bdda000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f2d5bbd6000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f2d5b9b7000) /lib64/ld-linux-x86-64.so.2 (0x00007f2d5eb96000) ``` > 生成的可执行文件体积才 20KB, "go build hello.go" 生成的 1.9MB 小非常多 >[warning] 当然如果缺少了其中某个链接库或者版本不匹配,都将导致无法正常运行,所以一般情况下这种构建模式很少使用 ### -buildmode=plugin
demo.go ``` package main import "fmt" // 导出 var var ( V int VAR_B = "hello world B" ) // 导出函数 func F(a string) string { return fmt.Sprintf("%s:%d\n", a, V) } // 导出结构体 type num struct { res int } func NewNum() num { return num{} } func (n *num) Add(a, b int) { n.res = a + b } func (n *num) Result() int { return n.res } var Num = NewNum() ```

main.go ``` package main import ( "fmt" "plugin" ) type Numer interface { Add(int, int) Result() int } func main() { checkErr := func(err error) { if err != nil { panic(err) } } p, err := plugin.Open("./main.so") checkErr(err) b, err := p.Lookup("VAR_B") checkErr(err) var_b := *b.(*string) fmt.Printf("%+v\n", var_b) // hello world B v, err := p.Lookup("V") checkErr(err) *v.(*int) = 7 f, err := p.Lookup("F") checkErr(err) f2 := f.(func(string) string) fmt.Printf("%+v", f2("hello")) // hello:7 num, err := p.Lookup("Num") checkErr(err) n := num.(Numer) n.Add(1, 2) fmt.Printf("%+v\n", n.Result()) //3 } ```

``` go build -buildmode=plugin demo.go go run palette.go ```
';