2021-08-17 | 阅读(1,607)
libadd.so

if 条件1 {
    loadLibrary("libadd1.so")
    调用其中的实现函数 add
else if 条件 2 {
    loadLibrary("libadd2.so")
    调用其中的实现函数 add
else {
    loadLibrary("libaddx.so")
    调用其中的实现函数  add

当然上面那样写是不行的,首先每一个动态库应该在程序运行期间只加载一次,定位的函数应该要缓存起来复用。

这时候我们是不能用 #cgo 的方式,像

1
2
3
4
5
6
/*
#cgo CFLAGS: -I.
#cgo LDFLAGS: -L../lib -ladd -Wl,-rpath,lib
#include "add.h"
*/
import "C"

因为它只能在编译构建期加载 libadd.so

System.loadLibrary("libadd")
1
char* Add(char* src, int n);
libadd.soAdd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main
 
import "C"
import (
  "fmt"
  "github.com/rainycape/dl"
)
 
func main() {
  lib, err := dl.Open("./libadd.so", 0)
  if err != nil {
    panic(err)
  }
  defer lib.Close()
  var add func(src *C.char, y int) (*C.char)  // 定义函数变量匹配 libadd 中的 Add 函数
  lib.Sym("Add", &add)                        // 定位 Add 函数地址
  val := add(C.CString("go"), 2021)
  fmt.Println("Hello c value: ", C.GoString(val))
}
go get github.com/rainycape/dl,

$ go run test.go
Hello c value: go2021

成功。

该项目的最后更新日期是 7 年前 (2015),如果稳定倒无妨,或者可以阅读它的实现代码,主要实现是步骤是

1
2
C.dlopen(library, flag)
C.dlsym(lib_handle, symbol_name)
go build -buildmode=plugin

链接: