【Go语言】动态库和静态库详解

前言

首先,引用七牛云存储团队在《Go语言编程》的观点(第7章,第9节):

就目前而言,以二进制方式分发Go包并不是很现实。由于Go语言对于兼容性控制的非常严格,任何一个版本号的不同都将导致无法链接包。因此,如果你使用Go语言开发了一个库,那么最合适的库分发方式是直接打包源代码包并进行分发,由使用者自行编译。

但是,笔者认为Go语言的编译和C语言一样,有汇编、链接阶段。所以,有必要了解、学习Go语言的动态库和静态库,也有助于以后分发包。

示例工程

一个标准的Golang工程包含3个目录

  • bin 放可执行文件
  • pkg 放静态库
  • src 放源代码
[user@host goprj]$ ls
bin  pkg  src
[user@host goprj]$ tree
.
├── bin
├── pkg
│   ├── gccgo_linux_amd64
│   └── linux_amd64
└── src
    ├── calc
    │   ├── fibonacci
    │   │   ├── fibonacci.go
    │   │   └── fibonacci_test.go
    │   └── calc.go
    └── simplemath
        ├── add.go
        └── sqrt.go

6 directories, 5 files
[user@host goprj]$

pkg

等下我既使用google的gc工具链,也使用gnu的gccgo工具链,所以pkg下面有两个文件夹

  • gccgo_linux_amd64 放gccgo生成的静态库
  • linux_amd64 放gc生成的静态库

src

代码有2个包和1个可执行文件

  • calc 主程序
  • calc/fibonacci 提供斐波那契数相关函数
  • simplemath 提供基础的数学运算

src/calc/calc.go

package main

import "fmt"
import "calc/fibonacci"

func main() {
    var res int64
    var err error

    res, err = fibonacci.Fibonacci(30)
    if err != nil {
            panic(err.Error())
    } else {
            fmt.Println("Result:", res)
    }

    res, err = fibonacci.Fibonacci_r(30)
    if err != nil {
            panic(err.Error())
    } else {
            fmt.Println("Result:", res)
    }
}

src/calc/calc/fibonacci/fibonacci.go

package fibonacci

import "simplemath"
import "errors"

func Fibonacci(n int64) (int64, error) {
    if n < 1 {
        err := errors.New("Should be greater than 0!")
        return 0, err
    } else if n > 92 {
        err := errors.New("Should be less than 93!")
        return 0, err
    }

    var res int64 = 0
    var tmp int64 = 1
    var idx int64 = 0

    for ; idx < n; idx++ {
        res = simplemath.Add(res, tmp)
        res, tmp = tmp, res
    }

    return res, nil
}

func Fibonacci_r(n int64) (int64, error) {
    if n < 1 {
        err := errors.New("Should be greater than 0!")
        return 0, err
    } else if n < 3 {
        return 1, nil
    } else if n > 92 {
        err := errors.New("Should be less than 93!")
        return 0, err
    }

    lhs, _ := Fibonacci_r(n - 1)
    rhs, _ := Fibonacci_r(n - 2)
    ret := simplemath.Add(lhs, rhs)
    return ret, nil
}

src/simplemath/add.go

package simplemath

func Add(a int, b int) int {
    return a + b
}

src/simplemath/sqrt.go

package simplemath

import "math"

func Sqrt(i int) int {
    v := math.Sqrt(float64(i))
    return int(v)
}

一键编译

首先,将工程路径添加到环境变量。
然后,用go install命令一键编译

  • gc go install ./...
  • gccgo go install -compiler gccgo ./...

gc编译静态库

  1. go tool compile编译出二进制文件
  2. go tool pack打包成静态库

注意事项:

  • 同一个包要编译成同一个.o文件
  • gc静态库的命名规则是gopackage.a
  • 以后使用这个静态库需要用到-I和-L参数
[user@host goprj]$ go tool compile -o simplemath.o src/simplemath/add.go src/simplemath/sqrt.go
[user@host goprj]$ go tool pack c pkg/linux_amd64/simplemath.a simplemath.o
[user@host goprj]$
[user@host goprj]$ go tool compile -o fibonacci.o -I pkg/linux_amd64 src/calc/fibonacci/fibonacci.go
[user@host goprj]$ go tool pack c pkg/linux_amd64/calc/fibonacci.a fibonacci.o
[user@host goprj]$ 
[user@host goprj]$ go tool compile -o calc.o -I pkg/linux_amd64 src/calc/calc.go
[user@host goprj]$ go tool link -o bin/calc -L pkg/linux_amd64 calc.o
[user@host goprj]$ 

gccgo编译静态库

  1. gccgo编译出二进制文件
  2. ar打包成静态库
    注意事项:
  • 同一个包要编译成同一个.o文件
  • gccgo静态库的命名规则是libgopackage.a
[user@host goprj]$ gccgo -c -o simplemath.o src/simplemath/add.go src/simplemath/sqrt.go
[user@host goprj]$ ar rv pkg/gccgo_linux_amd64/libsimplemath.a simplemath.o
ar: creating pkg/gccgo_linux_amd64/libsimplemath.a
a - simplemath.o
[user@host goprj]$ 
[user@host goprj]$ gccgo -c -o fibonacci.o -I pkg/gccgo_linux_amd64 src/calc/fibonacci/fibonacci.go
[user@host goprj]$ ar rv pkg/gccgo_linux_amd64/calc/libfibonacci.a fibonacci.o
ar: creating pkg/gccgo_linux_amd64/calc/libfibonacci.a
a - fibonacci.o
[user@host goprj]$ 
[user@host goprj]$ gccgo -c -o calc.o -I pkg/gccgo_linux_amd64 src/calc/calc.go
[user@host goprj]$ gccgo -o bin/calc \
>                        -L pkg/gccgo_linux_amd64 \
>                        -L pkg/gccgo_linux_amd64/calc \
>                        calc.o \
>                        -lfibonacci -lsimplemath
[user@host goprj]$ 

gccgo编译动态库

gcc有着丰富的编译经验,还提供了编译go动态库的工具。
最简单的方法是用-shared编译选项

[user@host goprj]$ gccgo -shared -fPIC \
>                        -o pkg/gccgo_linux_amd64/libsimplemath.so \
>                        src/simplemath/add.go \
>                        src/simplemath/sqrt.go
[user@host goprj]$ gccgo -shared -fPIC \
>                        -o pkg/gccgo_linux_amd64/calc/libfibonacci.so \
>                        -I pkg/gccgo_linux_amd64 \
>                        src/calc/fibonacci/fibonacci.go
[user@host goprj]$ 

总结

总的来说,go tool非常方便,而手动编译更加灵活。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值