Load and call functions from a .so shared library [duplicate] - 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
}

Related

Is there possibility to use .so files?

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.

Define variable in cgo

I want, at build time, to define a string variable in cgo. None of the following approaches works.
#cgo CFLAGS: -DLOG="common"
'common' undeclared (first use in this function)
#cgo CFLAGS: -DLOG=common
'common' undeclared (first use in this function)
#cgo CFLAGS: -DLOG=\"common\"
malformed #cgo argument: -DLOG="common"
It appears this is not possible as cgo does some mangling/parsing -- can you get away with just a normal #define LOG "common" (i.e. not use the CGO special flags).
Or failing that You can invoke go run/go build like this: CGO_CFLAGS='-DLOG="common"' go run so.go
you could define a variable in cgo same as define it in c code,
example:
package main
/*
int initflag=2;
int GetInitFlag(){
return initflag;
}
*/
import "C"
import "fmt"
// CFlag get c flag
func CFlag() int {
value := C.GetInitFlag()
return int(value)
}
func main() {
fmt.Println(CFlag())
}
string type must convert char* in c to string
// C string to Go string
func C.GoString(*C.char) string
https://golang.org/cmd/cgo/

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
}

unexpected type: ... with cgo in Go

I'm new to Go and trying to learn how to call C from Go. I wrote this program to open a named semaphore, get the value and print it to the screen.
When I run it go build semvalue.go I get the error:
./semvalue.go:16:14: unexpected type: ...
What does this mean? What am I doing wrong?
package main
import "fmt"
// #cgo LDFLAGS: -pthread
// #include <stdlib.h>
// #include <fcntl.h>
// #include <sys/stat.h>
// #include <semaphore.h>
import "C"
func main() {
name := C.CString("/fram")
defer C.free(name)
fram_sem := C.sem_open(name, C.O_CREAT, C.mode_t(0644), C.uint(1))
var val int
ret := C.sem_getvalue(fram_sem, val)
fmt.Println(val)
C.sem_close(fram_sem)
}
Thank you.
The message is confusing, until you realize that the ... is the variadic portion of a C function. You can't use C variadic functions directly from Go, so you'll have to write a small wrapper in C to call sem_open.
A couple more notes:
C.free should be called with C.free(unsafe.Pointer(name))
val needs to be a *C.int
sem_getvalue uses errno, so you should call it with ret, err := C.sem_getvalue...

Resources