是否可以从 Go 调用静态对象 (.so) 文件? 我一直在搜索谷歌,我一直在寻找我能做到的说法
lib, _ := syscall.LoadLibrary("...")
但是尝试这个会出错
undefined: syscall.LoadLibrary
并通过 Godocs 进行搜索,我无法在 syscall 包中找到对此函数的引用。 是否可以加载库并调用其函数?
在 POSIX 平台上,您可以使用
cgo
调用 dlopen 和朋友:
// #cgo LDFLAGS: -ldl
// #include <dlfcn.h>
import "C"
import fmt
func foo() {
handle := C.dlopen(C.CString("libfoo.so"), C.RTLD_LAZY)
bar := C.dlsym(handle, C.CString("bar"))
fmt.Printf("bar is at %p\n", bar)
}
正如@JimB 所说,您应该只使用 CGO,并将指向动态/静态库的链接放在那里。按照这个例子:
// #cgo LDFLAGS: -lpng
// #include <png.h>
import "C"
...
var x:= C.png_whatever() // whatever the API is
在这里阅读更多内容:http://blog.golang.org/c-go-cgo
@Martin Törnwall 的回答解释了如何使用
dlopen()
进行函数查找。添加此答案以包含有关如何实际调用该函数的示例代码。 (使用评论中建议的方法)。
想法是用C语言为共享库的每个函数写一个包装函数,它接受一个void*指针(指向
dlopen()
返回的函数的指针),将其转换成合适的函数指针,然后调用它。
假设我们在
str_length
中有一个名为libfoo.so
的函数来计算字符串的长度,那么得到的Go代码将是:
package main
import (
"fmt"
)
/*
#cgo LDFLAGS: -ldl
#include <dlfcn.h>
typedef int (*str_length_type)(char*); // function pointer type
int str_length(void* f, char* s) { // wrapper function
return ((str_length_type) f)(s);
}
*/
import "C"
func main() {
handle := C.dlopen(C.CString("libfoo.so"), C.RTLD_LAZY)
str_length_ptr := C.dlsym(handle, C.CString("str_length"))
result := C.str_length(str_length_ptr, C.CString("Hello World!"))
fmt.Println(result) // prints 12
}
发现使用 purego 更容易,他们的 README 示例有效:
package main
import (
"fmt"
"runtime"
"github.com/ebitengine/purego"
)
func getSystemLibrary() string {
switch runtime.GOOS {
case "darwin":
return "/usr/lib/libSystem.B.dylib"
case "linux":
return "libc.so.6"
default:
panic(fmt.Errorf("GOOS=%s is not supported", runtime.GOOS))
}
}
func main() {
libc, err := purego.Dlopen(getSystemLibrary(), purego.RTLD_NOW|purego.RTLD_GLOBAL)
if err != nil {
panic(err)
}
var puts func(string)
purego.RegisterLibFunc(&puts, libc, "puts")
puts("Calling C from Go without Cgo!")
}