go code (foo.go) compiled into a shared library and a c header (foo.h) is generated.
For calling go from c, please see here
The code below shows two ways of passing string parameter to go function:
- Using GoString structure as argument, without making a copy in go code: no conversion to go string needed.
- Using c_char_p as argument, making a copy in go code when converting to go string.
When using the first method without the copy, I don't know how python will do the memory management with the pointer passed into go. So the second method is preferred.
The go function returns a c string, and the reciving side is responsible for managing the lifecycle of the c string. It seems that python does not free it.
foo.py:
from ctypes import *
from ctypes import cdll
import time
class go_string(Structure):
_fields_ = [
("p", c_char_p),
("n", c_int)]
lib = cdll.LoadLibrary('./foo.so')
def bar(str):
b = go_string(c_char_p(str), len(str))
lib.bar.restype = c_char_p
a = lib.bar(b, c_char_p(str))
print a
bar("haha")
bar("hoho")
time.sleep(100)
foo.go:
package main
import (
"C"
"fmt"
"time"
)
//export bar
func bar(a string, b *C.char) *C.char {
c := a
d := C.GoString(b)
go func() {
for {
time.Sleep(time.Second)
fmt.Println("a:", a)
fmt.Println("b:", C.GoString(b))
fmt.Println("c:", c)
fmt.Println("d:", d)
}
}()
return C.CString("hello from go")
}
func main() {}
Command:
go build -buildmode=c-shared -o foo.so foo.go
python foo.py
Appendex:
Generated foo.h:
/* Created by "go tool cgo" - DO NOT EDIT. */
/* package command-line-arguments */
/* Start of preamble from import "C" comments. */
/* End of preamble from import "C" comments. */
/* Start of boilerplate cgo prologue. */
#ifndef GO_CGO_PROLOGUE_H
#define GO_CGO_PROLOGUE_H
typedef signed char GoInt8;
typedef unsigned char GoUint8;
typedef short GoInt16;
typedef unsigned short GoUint16;
typedef int GoInt32;
typedef unsigned int GoUint32;
typedef long long GoInt64;
typedef unsigned long long GoUint64;
typedef GoInt64 GoInt;
typedef GoUint64 GoUint;
typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
typedef float _Complex GoComplex64;
typedef double _Complex GoComplex128;
/*
static assertion to make sure the file is being used on architecture
at least with matching size of GoInt.
*/
typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];
typedef struct { const char *p; GoInt n; } GoString;
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
#endif
/* End of boilerplate cgo prologue. */
#ifdef __cplusplus
extern "C" {
#endif
extern char* bar(GoString p0, char* p1);
#ifdef __cplusplus
}
#endif
A digested version here:
The Go Source
To build it into a shared libarary:
The Python Code