Is there possibility to use .so files? - go

Such similar question was posted 6 yrs ago
(How to import and use .so file in golang program)
I guess the current releases would have looked into this.
I have to call network.so from my Go code.
One of the function under network.so
bool Tape::test1(obj a,obj b) {
}
My current implementation
/* #cgo LDFLAGS: -ldl
#include <dlfcn.h>
*/
func main() {
handle := C.dlopen(C.CString("network.so"), C.RTLD_LAZY)
//How to call C.test1 function ?
}
Looking for some examples.

Related

Load and call functions from a .so shared library [duplicate]

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?
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)
}
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
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
}

cgo wrote func in cgo header to print data, but nothing gets printed from it

I'm trying to write a small cgo application using vscode and vscode-go.
I'm at least three levels deep in problems. I needed to copy a Go string to an allocated C buffer and then pass that inside a struct to a function provided by a C library. That function is returning an error that doesn't give me enough information, so I'm trying to examine what I'm passing to the function. I'm not certain I'm doing the memory copy properly, so I wanted to write a C function in the cgo header that I can call to just print out a number of hex bytes from an address. The problem I'm having right now is that that method isn't printing ANYTHING, even a simple printf statement.
My cgo header looks like this:
/*
#cgo CFLAGS: -g -Wall -I${SRCDIR}/../include
#cgo LDFLAGS: -L${SRCDIR}/../lib/linux ...
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "..."
typedef struct {
int size;
void *data;
} info;
void printBytes(info *data) {
printf("In printBytes.");
}
*/
In one of the functions in the same module, I have this code:
plaintextBuffer := C.malloc(C.ulong(C.sizeof_char * len(data)))
buf := (*[1 << 30]byte)(plaintextBuffer)
copy(buf[:], data)
fmt.Println("About to call printBytes.")
info := &C.info{size: C.int(len(data)), data: plaintextBuffer}
C.printBytes(info)
I am not certain at all whether those two lines for copying the string to the buffer are correct, but they compile and don't panic when they run, so they couldn't be that bad. :)
In any case, I wanted to verify whether it actually did work properly, by calling that "printBytes" function (which obviously needs more code to do something useful). For the first test, I just want to see "In printBytes." when I run it. However, what I see when I run it is nothing. I see the "About to call ..." line, and then a print statement that comes after this code.
I also tried changing "printBytes" and "info" to "PrintBytes" and "Info"(just the type) in the def and the reference, and it had no effect on the result.
I could use advice on any of this, starting with why the function doesn't print anything, or advice on whether that copy code is correct, or anything else.
go 1.7
plaintextBuffer := C.malloc(C.ulong(C.sizeof_char * len(data)))
C.free(unsafe.Pointer(plaintextBuffer))
slice := unsafe.Slice((*byte)(plaintextBuffer), len(data))
copy(slice[:], data)
fmt.Print(slice)

golang build with gcc instead of g++

I am trying to build Go that is calling c++ created .so (a.so) file on Linux, but I found that the go build . command always builds with gcc NOT g++. I already put the .cpp in the root directory instead in subdirectory.
Here is the output of go build command
client.go:90:10: could not determine kind of name for C.Init
cgo:
gcc errors for preamble:
In file included from client.go:8:
a.h:34:1: error: unknown type name 'class'
34 | class A {
| ^~~~~
a.h:34:11: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
34 | class A {
| ^ ^
Here is the client.go calling C code:
package main
// #cgo windows LDFLAGS: -la
// #cgo windows CXXFLAGS: -DWINDOWS
// #cgo linux LDFLAGS: -liba
// #cgo LDFLAGS: -L./libs
// #cgo CXXFLAGS: -I./
// #include "a.h"
import "C"
func function() {
handle, _ := dlOpen(PATH_TO_SO_FILE)
blob := C.Init(handle)
}
Here is the dlOpen related code, wrote in Go:
// +build linux
package main
// #cgo linux LDFLAGS: -ldl
// #include <dlfcn.h>
// #include <stdlib.h>
import "C"
import "errors"
import "unsafe"
type Handle {
c unsafe.Pointer
}
func dlOpen(filename string) (Handle, error) {
ptr := C.CString(filename)
defer C.free(unsafe.Pointer(ptr))
ret := C.dlopen(ptr, C.RTLD_LAZY)
if ret != nil {
return Handle{ret}, nil
}
return Handle{ret}, errors.New(C.GoString(C.dlerror()))
}
Here is the a.h
class A {
public:
Init(MHANDLE handle);
}
Your problem is not with the cpp file.
You wrote in the go file // #include "a.h".
Go currently compiles this as c and has no support for c++ and it looks like it will never have.
The only option you have is to make the header file valid in c.

How to reuse a Go callback in several packages from C?

Is there a way to build a Go + C application that:
From main package X, import packages Y and Z.
Package M exports a go callback F.
Packages X and Y are both built with accompanying C files, both want
to call F from C source code.
Generally speaking I'm trying to figure out how to call a callback from accompanying C files in other modules which are used to build a final application. I coudn't figure out how to achieve this or something similar. I'm also interested in convoluted solutions.
I don't see a way to call a Go function across packages, but all cgo packages are linked into the same binary and can call each other. This means that you can export M.F to a C function in package M and call that C function from packages Y and Z.
m/m.go:
package m
// void F();
import "C"
import "fmt"
//export F
func F() {
fmt.Println("m.f")
}
m/m.h:
void m_f();
m/m.c:
#include <stdio.h>
#include "_cgo_export.h"
#include "m.h"
void m_f() {
printf("m_f\n")
F();
}
y/y.go:
package y
// The LDFLAGS lines below are needed to prevent linker errors
// since not all packages are present while building intermediate
// packages. The darwin build tag is used as a proxy for clang
// versus gcc because there doesn't seem to be a better way
// to detect this.
// #cgo darwin LDFLAGS: -Wl,-undefined -Wl,dynamic_lookup
// #cgo !darwin LDFLAGS: -Wl,-unresolved-symbols=ignore-all
// #include "y.h"
import "C"
import (
"fmt"
_ "m"
)
func Y() {
fmt.Println("y.Y")
C.y()
}
y/y.h:
void y();
y/y.c:
#include <stdio.h>
#include "../m/m.h"
void y() {
printf("y.C.y\n");
m_f();
}
Here is an example, that will accept any go callback (not thread-safe).
b.go:
package b
// typedef void (*cbFunc) ();
// void do_run(cbFunc);
// void goCallback();
import "C"
//export goCallback
func goCallback() {
if goCallbackHolder != nil {
goCallbackHolder()
}
}
var goCallbackHolder func()
func Run(callback func()) {
goCallbackHolder = callback
C.do_run(C.cbFunc(C.goCallback))
}
b.c:
#include "_cgo_export.h"
void do_run(void (*callback)())
{
callback();
}
I couldn't make it to work in a simple fashion IMO.
Given main package X that imports Y and Z, both having to call (from C source code) F declared in package M,
I had to:
Create a small wrapper W1 for F in Y and export it to be called from Y's C source.
Create a small wrapper W2 for F in Z and export it to be called from Z's C source.
In Y CGO CPPFLAGS define -DCALLBACK=W1
In Z CGO CPPFLAGS define -DCALLBACK=W2
From C source code, anywhere, I'm now able to refer to F as CALLBACK (yeah, internally it's all different stuff, which I refer to using a single name at one end to call a single function at the other end).
This is convoluted, but it's working, although configuring such macros and producing little wrappers
is not being ideal. If anyone could detail a simpler procedure I would be glad. Everything
I tried ended up with duplicated symbols or non-visible declarations.

Calling functions in an so file from Go

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?
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)
}
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
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
}

Resources