博客园
虽然痛苦,却依旧要快乐,并相信着未来。

导航

 

Go语言so动态调用

注意事项:

  1. 编译的GO版本必须完全一致
  2. 双方依赖的公共第三方库版本必须完全一致
  3. GOPATH也得保持一致,这一点可以在编译时候使用trimpath参数解决
  4. 插件加载之后无法卸载
  5. 导出文件较大
goso/
├── modules/
│   └── hello/
│       └── hello.go
├── main.go
└── build.sh
  1. 首先创建模块代码:

如果要添加新的导出函数,需要:

  1. 在函数前添加 //export FunctionName 注释;
  2. 确保函数是可导出的(首字母大写)。
// hello.go
package main

import "C"
import "fmt"

//export SayHello
func SayHello(name string) string {
    return fmt.Sprintf("你好, %s!", name)
}

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

// 必需的main函数
func main() {}
  1. 创建主程序
// main.go
package main

import (
    "fmt"
    "plugin"
    "reflect"
)

func inspectModule(path string) {
    // 加载.so文件
    p, err := plugin.Open(path)
    if err != nil {
        fmt.Printf("加载模块失败: %v\n", err)
        return
    }

    fmt.Printf("\n检查模块: %s\n", path)
    fmt.Println("导出的符号:")
    
    // 获取所有导出的函数
    symHello, err := p.Lookup("SayHello")
    if err == nil {
        // 使用反射获取函数信息
        t := reflect.TypeOf(symHello)
        fmt.Printf("函数: SayHello\n")
        fmt.Printf("  参数: %v\n", t.String())
    }

    symAdd, err := p.Lookup("Add")
    if err == nil {
        t := reflect.TypeOf(symAdd)
        fmt.Printf("函数: Add\n")
        fmt.Printf("  参数: %v\n", t.String())
    }

    // 测试调用
    if symHello != nil {
        if f, ok := symHello.(func(string) string); ok {
            result := f("小明")
            fmt.Printf("\n测试调用 SayHello: %s\n", result)
        }
    }

    if symAdd != nil {
        if f, ok := symAdd.(func(int, int) int); ok {
            result := f(5, 3)
            fmt.Printf("测试调用 Add: 5 + 3 = %d\n", result)
        }
    }
}

func main() {
    // 扫描并检查所有.so文件
    inspectModule("modules/hello.so")
}
  1. 创建编译脚本
#!/bin/bash

# 创建输出目录
mkdir -p modules

# 编译hello模块
echo "编译 hello 模块..."
cd modules/hello
go build -buildmode=plugin -o ../hello.so
cd ../..

echo "编译完成"

python与go互调so

python 编译的so 和go编译的so,不能相互调用。
转换成C语言形式的,利用C语言调用,才能勉强调用

  1. 如果需要Go和Python互操作:
    • 使用CGO将Go编译为c-shared
    • 或使用进程间通信(如gRPC)
    • 或使用Python的ctypes调用C风格的.so
    • 如果只需要Go的插件系统:
  2. 继续使用Go的plugin模式
    • 接受较大的文件体积
  3. 如果需要最小的文件体积:
    • 考虑使用C/C++编写动态库
    • 或使用其他轻量级选项
posted on 2025-01-06 18:45  砖猿  阅读(215)  评论(0)    收藏  举报