Go 1.15+ 不支持生成可被非C程序直接dlopen的通用动态库,仅支持buildmode=c-shared生成带C ABI的封装库,依赖Go运行时且必须由C程序调用。
Go 1.15+ 不支持直接编译传统 .so 动态库
Go 官方从 Go 1.15 开始移除了
对非 C 语言主程序的动态链接支持,且 Go 本身不生成 ELF/Dylib 风格的、可被其他语言(如 Python、C)直接
加载的通用动态库。所谓“Go 动态库”,实际仅指
生成的带 C ABI 的封装层 —— 它依赖 Go 运行时,必须由 C 程序调用,不能脱离 Go 生态独立加载。
用 buildmode=c-shared 生成 C 兼容接口
这是唯一受官方支持的“动态库”路径,产出
(Linux)或
(macOS),但本质是 C 接口桥接 + 内嵌 Go 运行时。需严格满足:
主包必须是
,且只含
函数(用
注释标记)
必须导入
包(即使没显式使用)
导出函数参数/返回值只能是 C 兼容类型:
、
、
等,不能是 Go 的
、
、
需手动管理内存:Go 分配的内存(如
)必须在 C 侧调用
释放
示例:
编译命令:
立即学习
“
go语言免费学习笔记(深入)
”;
go语言参考手册 中文CHM版
Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译
下载
调用时必须链接 lib
go
和 libc,且不能静态链接 Go 运行时
生成的
不是纯代码,它依赖 Go 运行时符号(如
)。C 程序调用时:
必须用
(不是
默认配置)链接,且顺序为:
不能加
,否则链接失败 —— Go 运行时不支持全静态链接到外部程序
运行时需确保
包含
路径,否则
找不到依赖
首次调用任意导出函数会触发 Go 运行时初始化,后续调用才真正执行逻辑
替代方案:CGO + 纯 C 库更可控
如果目标是让 Python/Java/Rust 调用 Go 逻辑,
很容易因运行时冲突、GC 干预、线程模型不匹配出问题。更稳的做法是:
用 Go 实现核心逻辑,通过
暴露极简 C 接口(只做数据转换,不启动 goroutine、不调用
等)
把 Go 编译成静态链接的
库,再用纯 C 封装一层,对外提供标准 POSIX 动态库接口
或改用
(
)生成 Python 绑定,绕过 C ABI 层
真正麻烦的从来不是编译命令,而是 Go 运行时与宿主环境的生命周期耦合 —— 比如 Python 的 GIL、Java 的 JNI Attach/Detach、C 程序的 fork 处理,都可能让 Go 的调度器卡死或泄露 goroutine。
buildmode=c-shareddlopenbuildmode=c-shared.so.dylibpackage mainexport//export FuncName"C"C.int*C.charC.size_tstringslicestructC.CStringC.free// hello.go
package main
import "C"
import "unsafe"
//export Add
func Add(a, b int) int {
return a + b
}
//export Hello
func Hello(s *C.char) *C.char {
goStr := C.GoString(s)
ret := C.CString("Hello, " + goStr)
return ret
}
func main() {} // required, but not executed
go build -buildmode=c-shared -o libhello.so hello.go
.soruntime.mallocgcgccclangyour_app.c libhello.so -lgo -lpthread-staticLD_LIBRARY_PATHlibhello.sodlopenc-sharedc-sharednet/http.agopygo get github.com/go-python/gopy