从 Go 调用 so 文件中的函数

问题描述 投票:0回答:4

是否可以从 Go 调用静态对象 (.so) 文件? 我一直在搜索谷歌,我一直在寻找我能做到的说法

lib, _ := syscall.LoadLibrary("...")

但是尝试这个会出错

undefined: syscall.LoadLibrary

并通过 Godocs 进行搜索,我无法在 syscall 包中找到对此函数的引用。 是否可以加载库并调用其函数?

go static-libraries system-calls
4个回答
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)
}

7
投票

正如@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


3
投票

@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
}

0
投票

发现使用 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!")
}
© www.soinside.com 2019 - 2024. All rights reserved.