Go

Go静态库动态库使用

如何提供和使用闭源代码库

Posted by 吴俊贤 on August 2, 2018

内容参考如下文章:

首先给出一个重要结论,Go语言并不支持使用只有二进制文件(.a与可执行文件)的库

静态库编译使用

库编写者要做的事

假如我写了一个超级厉害的排序库(不会给你看代码的手动滑稽),库的位置在$GOPATH/src/github.com/packagewjx/gostudy/libuse/niu,那么我首先需要编译一个静态库文件,下面这个命令就会自动的编译。

go install github.com/packagewjx/gostudy/libuse/niu

然后会在GOPATHpkg文件夹下,根据路径找到对应的.a文件。

我们可以提供一个头文件,供库的使用者使用。但是Go本身是没有头文件的,所有的东西只会定义一次。

我的想法是,使用buildtag来区别头文件和实际文件,比如,在我们开发者的项目中,所有的头文件都将拥有一个buildtag,叫header就ok。然后,使用go install命令编译成静态库。打包的时候,将只包含我们静态库文件和头文件的,依据GOPATH的格式,打包pkgsrc文件夹到一个tarball里面,这样用户只需要将这个tarball解压到他们的gopath里面就行了。但是,要注意的是,用户不能编译那些header文件,否则就会覆盖那些编译好的静态库文件了。

可能还要找一找方法去规避编译header文件,go本身没有提供可以使用只有静态库文件没有源代码的软件库的功能(被列为实验性功能)。

挖个坑?可能永远都不会填的。想做一个小工具,输入库的路径,就可以自动寻找库中已经被导出的函数,以及自定义结构等数据类型,并连同注释,放入到一个头文件中。完了之后会打包成一个tarball,就能够很方便的输出闭源软件库了。

库使用者使用方法

将静态库文件和头文件(如果有)放到相应的目录中,我们的主程序就导入,如下

package main

import (
    "math/rand"
    "time"
    "github.com/packagewjx/gostudy/libuse/niu"
    "fmt"
)

func main() {
    length := 1000
    nums := make([]int, length)
    rand.Seed(time.Now().Unix())
    for i := 0; i < length; i++ {
        nums[i] = rand.Int()
    }
    niuSort := niu.NiuSort(nums)
    fmt.Println(nums)
    fmt.Println(niuSort)
}

编译时需要注意,我们不能够让go自动的编译那个头文件,这样会覆盖掉那个静态库。

能做到这么编译的,只能是这样子了

首先编译(工作目录在gostudy)

go tool compile -I /home/wjx/go/pkg/linux_amd64/ libuse/main.go

然后链接

go tool link -o main -L /home/wjx/go/pkg/linux_amd64/ main.o

这样子使用的确非常麻烦。

关于Go提供闭源的讨论

https://github.com/golang/go/issues/2775

里面有些有意思的点

  1. go的不同版本编译出来的.a文件无法共用。只能使用同一个版本编译出的文件。
  2. mtime hack

只是到最后也只是把这个功能标注为实验性功能,加入到了go1.7版本中。描述在这个文档中:https://tip.golang.org/pkg/go/build/#hdr-Binary_Only_Packages

使用//go: binary-only-package

1.10出来以后,要求使用//go: binary-only-package的包,需要显式声明使用了的包。

我们继续用回刚才的例子,那么我只要改成下面这样子

//go:binary-only-package

package niu

// 1.10开始必须有显式的import
import (
    "sort"
)

// 函数声明、这些是可以省略的,但是为了文档的需要,以及让编译器能够提供代码提示,我们可以在这里提供辣鸡实现。
func NiuSort(nums []int) []int {
    return nil
}

然后,需要把这个文件和.a文件放到相应的位置,就能够给其他包使用了。

这里也有一个例子:https://github.com/tcnksm/go-binary-only-package