英文:
Calling functions in an so file from Go
问题
从Go中调用静态对象(.so)文件是否可能?
我一直在搜索Google,我一直看到这样的说法,我可以这样做:
lib, _ := syscall.LoadLibrary("...")
但是尝试这样做会出现错误:
undefined: syscall.LoadLibrary
并且在Godocs中搜索,我找不到syscall包中对这个函数的引用。
是否可能加载一个库并调用它的函数?
英文:
Is it possible to call a static object (.so) file from Go?
I've been searchign Google and I keep hitting upon the claim that I can do
lib, _ := syscall.LoadLibrary("...")
But trying this gives an error
undefined: syscall.LoadLibrary
and searching through Godocs I cannot find reference to this function in the syscall package.
Is it possible to load a library and call its functions?
答案1
得分: 10
在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)
}
英文:
On a POSIX platform, you could use cgo
to call dlopen and friends:
// #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)
}
答案2
得分: 7
如@JimB所说,你应该使用CGO,并在那里将动态/静态库链接到代码中。示例如下:
// #cgo LDFLAGS: -lpng
// #include <png.h>
import "C"
...
var x := C.png_whatever() // 根据API的具体情况而定
在这里阅读更多信息:http://blog.golang.org/c-go-cgo
英文:
As @JimB said, you should just use CGO, and put the linking to the dynamic/static library there. as per this example:
// #cgo LDFLAGS: -lpng
// #include <png.h>
import "C"
...
var x:= C.png_whatever() // whatever the API is
Read more here: http://blog.golang.org/c-go-cgo
答案3
得分: 4
答案由@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*); // 函数指针类型
int str_length(void* f, char* s) { // 包装函数
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) // 输出 12
}
希望对你有帮助!
英文:
The answer by @Martin Törnwall explains how to use dlopen()
for function lookup. Adding this answer to include sample code for how to actually call that function as well. (Using the approach suggested in the comments).
The idea is to write a wrapper function in C language for each function the shared library, which accepts a void* pointer (pointer to the function returned by dlopen()
), converts it into an appropriate function pointer, and then call it.
Suppose we have a function named str_length
in libfoo.so
to calculate the length of a string, then the resulting Go code would be:
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
}
答案4
得分: 1
使用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!")
}
英文:
Found using purego much easier, their README example works:
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!")
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论