众所周知,Go的编译系统是针对源代码的,如果想发布一个二进制文件给别人,该怎么做?如何在CI上编译不同平台的C代码?

下面跟我一起来实验下:

  1. 创建好项目 在src目录下创建两个包路径,liba 和 main,liba用来实验隐藏代码

    1. 项目各文件如下
      • liba/dummy.go, 调用代码先注释掉,避免冲突

package liba

import (
    "fmt"
)

func libdummy() {
    fmt.Println("this is in dummy lib")
}

// func LibTest() {
//     fmt.Println("dummy library")
//     libdummy()
// }
  • liba/real.go

package liba

import (
    "fmt"
)

func libreal() {
    fmt.Println("this is in real lib")
}

func LibTest() {
    fmt.Println("real library")
    libreal()
}
  • main/main.go

package main

import (
    "liba"
)

func main() {
    liba.LibTest()
}

3. 好了,我们先编译真实的library, 得到.a 文件,并跑下看看

go install ./...
 ~/exercises/golib: bin/main
real library
this is in real lib
  1. 将真实的library 拷贝出来备用 cp pkg/darwin_amd64/liba.a .

  2. 将real.go 的代码注释掉,dummy.go 的代码取消注释,并编译跑下看看


~/exercises/golib: bin/main dummy library this is in dummy lib

  1. 见证奇迹的时刻到了,我们把real.go 的实现给copy回来,编译跑下看看

 ~/exercises/golib: cp liba.a pkg/darwin_amd64
 ~/exercises/golib: go install ./...
 ~/exercises/golib: bin/main
real library
this is in real lib

通过这个实验,可以看出go最后的链接步骤是比较代码和.a文件的创建时间,如果.a 创建的晚,就不会再次对代码进行编译,只做链接。大家可以将上面的cp 换成mv验证下 :) 总结下,如果想发布二进制的go library,就要将.a 文件和 stub 代码一起交付给使用者,并且在编译的时候做一次替换。

如果有些软件需要跨平台编译,而且还有些底层访问的C代码,可以先编译成.a 文件,然后放到CI 平台上,让Go交叉编译的时候链接就好了。