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

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
统计
 

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   砖猿  阅读(54)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
 
点击右上角即可分享
微信分享提示