Golang中使用.so文件的实践指南
Golang中使用.so文件的实践指南
你好,我有一个已编译的 .so 文件,位于 /usr/share/colours.so。
我可以在我的 Go 代码中使用这个文件吗?我应该如何使用它?我需要使用 import "/usr/share/colours.so" 吗?还是有其他方法?
如果你知道,请帮帮我。
2 回复
要在Linux上编译共享库并从Go代码中调用,你需要启用CGO。以下是我找到的可能对你有帮助的信息:
标签: go, static-libraries, system-calls
更多关于Golang中使用.so文件的实践指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go语言中直接导入.so文件是不支持的。你需要使用cgo来调用.so文件中的C函数。以下是具体步骤:
1. 创建C头文件声明
首先,你需要知道.so文件提供的函数签名。假设colours.so有以下函数:
// colours.h
#ifndef COLOURS_H
#define COLOURS_H
#ifdef __cplusplus
extern "C" {
#endif
const char* get_colour_name(int colour_code);
int get_colour_count(void);
#ifdef __cplusplus
}
#endif
#endif
2. Go代码中使用cgo调用
package main
/*
#cgo LDFLAGS: -L/usr/share -lcolours -Wl,-rpath,/usr/share
#include "colours.h"
*/
import "C"
import (
"fmt"
"unsafe"
)
func main() {
// 调用无参数函数
count := C.get_colour_count()
fmt.Printf("Total colours: %d\n", count)
// 调用有参数函数
cstr := C.get_colour_name(1)
// 将C字符串转换为Go字符串
colourName := C.GoString(cstr)
fmt.Printf("Colour name: %s\n", colourName)
// 如果需要处理内存
cstr2 := C.get_colour_name(2)
defer C.free(unsafe.Pointer(cstr2))
}
3. 编译和运行
# 确保头文件存在
cp /usr/share/colours.h .
# 编译Go程序
go build -o colour_app main.go
# 运行
LD_LIBRARY_PATH=/usr/share:$LD_LIBRARY_PATH ./colour_app
4. 动态加载.so文件(使用dlopen)
如果不知道函数签名,可以使用dlopen动态加载:
package main
/*
#cgo LDFLAGS: -ldl
#include <dlfcn.h>
#include <stdlib.h>
*/
import "C"
import (
"fmt"
"unsafe"
)
func main() {
// 打开.so文件
libpath := C.CString("/usr/share/colours.so")
defer C.free(unsafe.Pointer(libpath))
handle := C.dlopen(libpath, C.RTLD_LAZY)
if handle == nil {
err := C.GoString(C.dlerror())
panic(fmt.Sprintf("dlopen failed: %s", err))
}
defer C.dlclose(handle)
// 获取函数指针
funcName := C.CString("get_colour_count")
defer C.free(unsafe.Pointer(funcName))
funcPtr := C.dlsym(handle, funcName)
if funcPtr == nil {
err := C.GoString(C.dlerror())
panic(fmt.Sprintf("dlsym failed: %s", err))
}
// 类型转换并调用函数
getCount := (*func() C.int)(unsafe.Pointer(&funcPtr))
count := (*getCount)()
fmt.Printf("Colour count: %d\n", int(count))
}
注意事项
- 函数签名必须匹配:C函数必须使用
extern "C"声明,避免C++名称修饰 - 内存管理:C返回的字符串需要适当处理,使用
C.GoString()转换或手动释放 - 链接选项:
-L指定库路径,-l指定库名(去掉lib前缀和.so后缀) - 线程安全:确保C函数是线程安全的,特别是从多个goroutine调用时
如果.so文件是你自己编译的,建议同时提供头文件。如果是第三方库,需要查阅其文档获取正确的函数签名。

