Golang中动态库加载与卸载的实现方法
Golang中动态库加载与卸载的实现方法
我在Go语言中创建了一个共享库,并在一个Go应用程序中使用了这个库。我正在寻找这个库加载/卸载时调用的函数。库的init()函数不起作用。通过使用import "C",我在库中编写了以下代码:
package testlibrary
/*
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
static void con() __attribute__((constructor));
void con() {
fprintf(stderr,"I'm a constructor\n");
}
*/
import "C"
import "fmt"
func init() {
fmt.Println("init never called")
}
但我从未收到con()函数中的消息。
有人能建议一下库加载时调用的函数吗?
更多关于Golang中动态库加载与卸载的实现方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于Golang中动态库加载与卸载的实现方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go语言中,共享库的加载和卸载可以通过cgo结合C语言的构造函数/析构函数特性来实现。你遇到的问题可能是由于Go的运行时初始化顺序导致的。以下是正确的实现方法:
1. 共享库代码示例
// testlibrary.go
package main
import "C"
import (
"fmt"
"sync"
)
// 导出函数必须放在main包中
//export Hello
func Hello() {
fmt.Println("Hello from shared library")
}
var (
cleanupOnce sync.Once
)
// 构造函数 - 在库加载时调用
//export library_init
func library_init() {
fmt.Println("Library loaded - constructor called")
}
// 析构函数 - 在库卸载时调用
//export library_cleanup
func library_cleanup() {
cleanupOnce.Do(func() {
fmt.Println("Library unloaded - destructor called")
})
}
// C构造函数声明
/*
#include <stdio.h>
#include <stdlib.h>
// 声明Go函数
extern void library_init(void);
extern void library_cleanup(void);
// 使用GCC/Clang的构造函数属性
__attribute__((constructor)) static void init_library() {
fprintf(stderr, "C constructor called\n");
library_init();
}
__attribute__((destructor)) static void cleanup_library() {
fprintf(stderr, "C destructor called\n");
library_cleanup();
}
*/
import "C"
func init() {
// Go的init函数在共享库中可能不会被调用
fmt.Println("Go init function - may not be called in shared library")
}
func main() {
// 必须有一个空的main函数
}
2. 编译共享库
# 编译为C共享库
go build -buildmode=c-shared -o libtest.so testlibrary.go
3. 使用共享库的应用程序
// main.go
package main
/*
#cgo LDFLAGS: -L. -ltest -Wl,-rpath,.
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
typedef void (*hello_func)();
// 动态加载函数声明
void* load_library(const char* path);
void unload_library(void* handle);
void call_hello(void* handle);
*/
import "C"
import (
"fmt"
"unsafe"
)
func main() {
// 动态加载共享库
libPath := C.CString("./libtest.so")
defer C.free(unsafe.Pointer(libPath))
handle := C.load_library(libPath)
if handle == nil {
fmt.Println("Failed to load library")
return
}
// 调用库函数
C.call_hello(handle)
// 卸载库
C.unload_library(handle)
fmt.Println("Library unloaded")
}
4. C辅助函数实现
// library_loader.c
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
typedef void (*hello_func)();
void* load_library(const char* path) {
void* handle = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
if (!handle) {
fprintf(stderr, "Error loading library: %s\n", dlerror());
return NULL;
}
printf("Library loaded successfully\n");
return handle;
}
void unload_library(void* handle) {
if (handle) {
dlclose(handle);
printf("Library unloaded\n");
}
}
void call_hello(void* handle) {
hello_func hello = (hello_func)dlsym(handle, "Hello");
if (hello) {
hello();
} else {
fprintf(stderr, "Error finding Hello function: %s\n", dlerror());
}
}
5. 编译和运行
# 编译共享库
go build -buildmode=c-shared -o libtest.so testlibrary.go
# 编译C辅助代码
gcc -c -fPIC library_loader.c -o library_loader.o
# 编译主程序
go build -o main main.go library_loader.o -ldl
# 运行程序
./main
关键点说明:
- 构造函数/析构函数属性:使用
__attribute__((constructor))和__attribute__((destructor))是正确的方法 - 导出函数:共享库函数必须使用
//export注释导出 - main包:共享库代码必须在main包中
- 动态加载:使用
dlopen()/dlclose()进行动态加载卸载 - 初始化顺序:C构造函数会在库加载时立即执行,Go的
init()函数可能不会在共享库上下文中被调用
运行此代码时,你会看到构造函数和析构函数的输出信息,确认库的加载和卸载事件被正确捕获。

