Compiling CGO files in Golang package - go

I am trying to use CGO to bundle C files with a Golang package. Following instructions here:
https://karthikkaranth.me/blog/calling-c-code-from-go/
http://akrennmair.github.io/golang-cgo-slides/#1
https://golang.org/cmd/cgo/
I am getting this error:
# main
src/main/main.go:16:8: could not determine kind of name for C.free
src/main/main.go:23:10: could not determine kind of name for C.greet
here is the structure:
main.go just looks like:
package main
// #cgo CFLAGS: -g -Wall
// #include <stdlib.h>
// #include "genericc/greeter.h"
import "C"
import (
"fmt"
"unsafe"
)
func main() {
name := C.CString("Gopher")
defer C.free(unsafe.Pointer(name))
year := C.int(2018)
ptr := C.malloc(C.sizeof_char * 1024)
defer C.free(unsafe.Pointer(ptr))
size := C.greet(name, year, (*C.char)(ptr))
b := C.GoBytes(ptr, size)
fmt.Println(string(b))
}
and I run test.sh to build it:
#!/usr/bin/env bash
dir="$(cd `dirname "$0"` && pwd)"
export GOPATH="$dir"
cd "$dir"
export CGOFILES=main
go install main
but when I run the bash script I get that error.

I follow the instructions:
Command cgo
If the import of "C" is immediately preceded by a comment, that
comment, called the preamble, is used as a header when compiling the C
parts of the package. For example:
// #include <stdio.h>
// #include <errno.h>
import "C"
or
/*
#include <stdio.h>
#include <errno.h>
*/
import "C"
For example,
gocbuf.go:
package main
import (
"fmt"
"unsafe"
)
/*
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int printData(unsigned char *data) {
return printf("cData: %lu \"%s\"\n", (long unsigned int)strlen(data), data);
}
*/
import "C"
func main() {
// Allocate C data buffer.
width, height := 8, 2
lenData := width * height
// add string terminating null byte
cData := (*C.uchar)(C.calloc(C.size_t(lenData+1), C.sizeof_uchar))
// When no longer in use, free C allocations.
defer C.free(unsafe.Pointer(cData))
// Go slice reference to C data buffer,
// minus string terminating null byte
gData := (*[1 << 30]byte)(unsafe.Pointer(cData))[:lenData:lenData]
// Write and read cData via gData.
for i := range gData {
gData[i] = '.'
}
copy(gData[0:], "Data")
gData[len(gData)-1] = 'X'
fmt.Printf("gData: %d %q\n", len(gData), gData)
C.printData(cData)
}
Output:
$ go run gocbuf.go
gData: 16 "Data...........X"
cData: 16 "Data...........X"
$
Your code organization makes no sense to me.
You should have package greeter, which wraps C functions via cgo. For example,
src
└── greeter
├── greeter.c
├── greeter.go
└── greeter.h
with skeleton files
greeter.go:
package greeter
/*
#include "greeter.h"
*/
import "C"
greeter.c:
#include "greeter.h"
greeter.h
/* C header file */
To install the greeter package, simply use go install.
Don't use relative paths. Don't use bash scripts.

Thanks to #peterSO, this is what worked:
package main
// #cgo CFLAGS: -g -Wall
// #include <stdlib.h>
// #include "../genericc/greeter.h"
// #include "../genericc/greeter.c" // ! no whitespace after this line
import "C"
import (
"fmt"
"unsafe"
)
func main() {
name := C.CString("Gopher")
defer C.free(unsafe.Pointer(name))
year := C.int(2018)
ptr := C.malloc(C.sizeof_char * 1024)
defer C.free(unsafe.Pointer(ptr))
size := C.greet(name, year, (*C.char)(ptr))
b := C.GoBytes(ptr, size)
fmt.Println(string(b))
}

Related

How to return go (array/slice/ist) to a C function

I have C code in which I am calling golang functions. I am able to do it for primitives data types (int/float etc.) but I want to return some other data structure like array/list/slice.
I could not find any solution on internet.
Looking for help.
Want to return a array/slice/list of string data type.
It would be helpful if you provide additional information, i.e. example code you are currently working on.
As stated from the Cgo documentation page:
Go array types are not supported; use a C pointer
To do so
hello.go
package main
// #include <stdlib.h>
import "C"
import "unsafe"
// StringSlice is a wrapper arround GoStringSlice to make it usable in C.
//export StringSlice
func StringSlice() **C.char {
x := GoStringSlice()
ret := C.malloc(C.size_t(len(x)) * C.size_t(unsafe.Sizeof(uintptr(0))))
// convert to usable format so we are able to fill it with data
pRet := (*[1<<30 - 1]*C.char)(ret)
for i, item := range x {
pRet[i] = C.CString(item)
}
return (**C.char)(ret)
}
func GoStringSlice() []string {
return []string{
"Hello",
"World",
}
}
func main() {}
hello.c
#include <stdio.h>
#include "hello.h"
int main() {
printf("Hello from C!\n");
char **slice = StringSlice();
int numItems = sizeof(slice) / sizeof(char *);
printf("Number of items: %d\n", numItems+1);
printf("String #0: %s\n", *slice);
slice++;
printf("String #1: %s\n", *slice);
return 0;
}
You have to execute go build -buildmode=c-archive hello.go which will generate a hello.h and hello.a.
The hello.a has to be compiled with your C code: gcc -pthread hello.c hello.a -o hello.

Using strfmon with cgo

I'm trying to use the C function strfmon using cgo.
The example C code that works is:
#include <stdio.h>
#include <monetary.h>
int main(void)
{
char str[100];
double money = 1234.56;
strfmon(str, 100, "%i", money);
printf("%s\n", string);
}
The Go code I've written so far is:
package main
// #cgo CFLAGS: -g -Wall
// #include <stdlib.h>
// #include <monetary.h>
import "C"
import (
"fmt"
)
func main() {
str := [100]C.char{}
var money C.double = 1234.56
C.strfmon(str, 100, "%i", money)
fmt.Printf("%+v\n", str)
}
When I go run main.go I get the following error:
./main.go:14:2: unexpected type: ...
I believe the ... refers to the variadic argument in strfmon but I'm not sure how to work around that from Go.
According to the cgo command documentation:
Calling variadic C functions is not supported. It is possible to circumvent this by using a C function wrapper.
And strfmon(3p) is indeed a variadic function as indicated by the ... characters in the signature:
ssize_t strfmon(char *restrict s, size_t maxsize,
const char *restrict format, ...);
As such, you can create a wrapper function in C which has a fixed number of arguments and calls strfmon(...) as needed, for example:
package main
// #cgo CFLAGS: -g -Wall
//
// #include <locale.h>
// #include <monetary.h>
// #include <stdlib.h>
//
// size_t format_amount(char * s, size_t maxsize, char * format, double amount)
// {
// setlocale(LC_ALL, "en_US");
// return strfmon(s, maxsize, format, amount);
// }
//
import "C"
import "fmt"
import "unsafe"
const SIZE = 100
func main() {
str := C.CString(string(make([]byte, SIZE)))
money := C.double(1234.56)
format := C.CString("[%n]")
C.format_amount(str, SIZE-1, format, money) // Call our wrapper here.
fmt.Printf("OK: %s\n", C.GoString(str))
// OK: [$1,234.56]
C.free(unsafe.Pointer(str))
C.free(unsafe.Pointer(format))
}

CGo: how to pass a 2 dimensional slice to C function

My code is:
package main
/*
#include <stdio.h>
#include <string.h>
void fill_2d_array(char (*s)[16]) {
strcpy(s[0], "hello");
strcpy(s[1],"cgo");
}
*/
import "C"
import "fmt"
import "unsafe"
func main() {
dirs := make([][]byte, 4)
for i := 0; i < 4; i++ {
dirs[i] = make([]byte, 16)
}
C.fill_2d_array(((*C.char)[16])(unsafe.Pointer(&dirs)))
fmt.Println(dirs)
}
When I run with go run test.go, it failed and said:
./test.go:21: type *C.char is not an expression
My Question is how to pass a 2 dimensional slice to a C function like fill_2d_array above?
Thanks.
Solved by:
C.fill_2d_array((*[16]C.char)(unsafe.Pointer(&dirs)))

How to use std::vector or other container in cgo of golang?

I want to malloc large number of objects in to memory.(about 100 million objects) because the gc of golang is not effective enough,so i need to use c/c++ to malloc memory and use std::vector to hold objects.
this is my code,i want use std container in cgo:
package main
import (
"fmt"
)
/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
using namespace std;
void dosome(){
vector<int> ivec; // empty vector
for (vector<int>::size_type ix = 0; ix != 10; ++ix)
ivec[ix] = ix; // disaster: ivec has no elements
}
*/
// #cgo LDFLAGS: -lstdc++
import "C"
//import "fmt"
func main() {
C.dosome()
var input string
fmt.Scanln(&input)
}
and have error message below:
go run stddemo.go
# command-line-arguments
./stddemo.go:13:10: fatal error: 'vector' file not found
#include <vector>
^
1 error generated.
how can i set the include path or is there another idea?
While you can use C++ with CGo, you can't embed that code inside the .go file, since it ultimately gets built with a C compiler.
Instead, place your dosome function in a separate .cpp file in the same directory as the .go file, and declare your function to use C linkage. For example:
extern "C" {
void dosome() {
vector<int> ivec;
...
}
}
If you include a prototype for the function in the CGo comment in the .go file so you can call it from Go.
Since you have multiple files now, you can't use the go run foo.go shorthand any more (since it only compiles a single file). Instead, you will need to use go run package or go build package, where your code is located at $GOPATH/src/package.
Uhh I think your conclusions are a bit too fast. GC cost is driven by two things: The more garbage your program produces, the more the GC will have to run. Second: The more pointers there are to scan, the longer a single GC will take.
That is to say: as long as you put your 100 million things into a go slice and keep them there: the GC won't have to run much, because there's no garbage. And second: if your things don't contain pointers, GC time, should it still occur, will be fine.
So, my question is: do your things have pointers?
if you just want to call someone's golang code this is a quick ram inefficient way:
package main
import "C"
import "fmt"
import "unsafe"
func intArrayFromC (src unsafe.Pointer, sz int) []uint64 {
dest := make([]uint64, sz)
copy(dest, (*(*[1000000000]uint64)(unsafe.Pointer(src)))[:sz:sz])// big number dose not affect ram.
return dest
}
//export doPrint
func doPrint(src unsafe.Pointer, sz int){
var numbers []uint64 = intArrayFromC(src, sz);
for i := 0; i < len(numbers); i++ {
fmt.Printf("%d index: %d\n", numbers[i], i)
}
}
func main() {}
and the c++ code:
#include "print.h"
#include <string.h>
#include <vector>
int main() {
std::vector<GoUint64> numbers{99,44,11,00,2,33,44};
while (1) {
doPrint(numbers.data(), numbers.size());
}
return 0;
}

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