Skip to content

Commit 5741f99

Browse files
rickrick
rick
authored and
rick
committedAug 25, 2022
add c-go ffi examples
1 parent 1fbcec6 commit 5741f99

31 files changed

+640
-368
lines changed
 

‎.gitmodules

+6
Original file line numberDiff line numberDiff line change
@@ -814,3 +814,9 @@
814814
[submodule "submodules/utf8.h"]
815815
path = submodules/utf8.h
816816
url = https://github.com/sheredom/utf8.h
817+
[submodule "submodules/Simplified-QOI-Codec"]
818+
path = submodules/Simplified-QOI-Codec
819+
url = https://github.com/Aftersol/Simplified-QOI-Codec
820+
[submodule "submodules/CommonC"]
821+
path = submodules/CommonC
822+
url = https://github.com/ScrimpyCat/CommonC

‎c-go-interface/Makefile

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
default: all
2+
.PHONY: clean
3+
CCFLAGS := -pthread -Iadder -Ihello
4+
UNAME_S := $(shell uname -s)
5+
ifeq ($(UNAME_S), Darwin)
6+
# This prevents a warning about PIE on Mac OS
7+
CCFLAGS += -Wl,-no_pie
8+
endif
9+
10+
11+
clean:
12+
$(MAKE) -C go_adder clean
13+
$(MAKE) -C go_hello clean
14+
rm -f c_adder c_hello
15+
16+
c_adder:
17+
$(MAKE) -C go_adder
18+
gcc $(CCFLAGS) -o c_adder c_adder.c go_adder/libadder.a
19+
20+
c_hello: go_hello
21+
$(MAKE) -C go_hello
22+
gcc $(CCFLAGS) -o c_hello c_hello.c go_hello/libhello.a
23+
24+
build: c_hello c_adder
25+
26+
test:
27+
./c_adder
28+
./c_hello
29+
30+
all: clean build test

‎c-go-interface/c_adder.c

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include <stdio.h>
2+
#include "go_adder/libadder.h"
3+
4+
void go_string(void);
5+
6+
7+
int main() {
8+
printf("C says: about to call Go...\n");
9+
int total = GoAdder(1, 7);
10+
printf("C says: Go calculated our total as %i\n", total);
11+
return 0;
12+
}
13+
14+

‎c-go-interface/c_hello.c

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#include <stdio.h>
2+
#include "go_hello/libhello.h"
3+
4+
void go_string(void);
5+
6+
7+
int main() {
8+
go_string();
9+
return 0;
10+
}
11+
12+
// Callback function to be called from Go
13+
void CallbackInC(char *go_str) {
14+
printf("CallbackInC(): %s\n", go_str);
15+
GoFreeString(go_str); // Release the Go string
16+
}
17+
18+
19+
20+
void go_string(void){
21+
22+
{
23+
char *go_str = GoStringFromGo();
24+
printf("GoStringFromGo(): %s\n", go_str);
25+
GoFreeString(go_str); // Release the Go string
26+
}
27+
{
28+
GoStringToGo("Calling from C");
29+
}
30+
{
31+
Demo_Array *go_array = GoArrayFromGo();
32+
printf("GoArrayFromGo():");
33+
int i;
34+
for(i=0; i < go_array->len; i++) {
35+
printf(" %d", ( (int *)(go_array->data) )[i]);
36+
}
37+
printf("\n");
38+
GoFreeArray(go_array); // Release the Demo_Array
39+
}
40+
41+
// Pass array to a Go library function
42+
{
43+
int c_array[] = { 4, 5, 6 };
44+
// Create a Demo_Array wrapper for the native C array
45+
Demo_Array go_array = { c_array, sizeof(c_array)/sizeof(c_array[0]) };
46+
}
47+
{
48+
GoFunctionToGo(&CallbackInC);
49+
}
50+
51+
// Receive a Go callback function and call it from here
52+
{
53+
void (*go_ptr)() = GoFunctionFromGo();
54+
(go_ptr)("Calling from C");
55+
}
56+
}

‎c-go-interface/go_adder/Makefile

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.PHONY: clean
2+
3+
libadder.a:
4+
[[ -f go.mod ]] || go mod init adder
5+
goimports -w adder.go
6+
go build -buildmode=c-archive -o $@
7+
8+
clean:
9+
rm -f libadder.* go.mod

‎c-go-interface/go_adder/adder.go

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package main
2+
3+
import "fmt"
4+
5+
import "C"
6+
7+
//export GoAdder
8+
func GoAdder(x, y int) int {
9+
fmt.Printf("Go says: adding %v and %v\n", x, y)
10+
return x + y
11+
}
12+
13+
func main() {} // Required but ignored

‎c-go-interface/go_hello/Makefile

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.PHONY: clean
2+
3+
libhello.a:
4+
[[ -f go.mod ]] || go mod init hello
5+
go mod tidy
6+
goimports -w hello.go
7+
go get
8+
go build -buildmode=c-archive -o $@
9+
10+
clean:
11+
rm -f libhello.a go.sum go.mod libhello.h

‎c-go-interface/go_hello/hello.go

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package main
2+
3+
import (
4+
"unsafe"
5+
)
6+
7+
/*
8+
#include <stdlib.h>
9+
#include <string.h>
10+
11+
// Array info struct for passing arrays
12+
typedef struct { void *data; int len; } Demo_Array;
13+
14+
// Inline C stubs for function pointers
15+
typedef void (*Demo_Func_Ptr)();
16+
static inline void call_out(Demo_Func_Ptr ptr, void *data) {
17+
(ptr)(data);
18+
}
19+
20+
extern void GoCallbackInGo(char*);
21+
static inline Demo_Func_Ptr _GoFunctionFromGo() {
22+
return &GoCallbackInGo;
23+
}
24+
*/
25+
import "C"
26+
27+
//
28+
// STRINGS
29+
//
30+
31+
//export GoStringFromGo
32+
func GoStringFromGo() *C.char {
33+
go_string := C.CString(StringFromGo())
34+
return go_string
35+
}
36+
37+
//export GoStringToGo
38+
func GoStringToGo(c_string *C.char) {
39+
StringToGo(C.GoString(c_string))
40+
}
41+
42+
//export GoFreeString
43+
func GoFreeString(str *C.char) {
44+
C.free(unsafe.Pointer(str))
45+
}
46+
47+
//
48+
// ARRAYS
49+
//
50+
51+
//export GoArrayFromGo
52+
func GoArrayFromGo() *C.Demo_Array {
53+
go_array := ArrayFromGo()
54+
55+
// malloc a new C array and copy contents of the Go slice
56+
go_array_size := C.size_t(C.sizeof_int * len(go_array))
57+
c_array_data := C.malloc(go_array_size)
58+
C.memcpy(c_array_data, unsafe.Pointer(&go_array[0]), go_array_size)
59+
60+
// malloc a new Demo_Array struct and set contents
61+
c_array := (*C.Demo_Array)(C.malloc(C.size_t(unsafe.Sizeof(C.Demo_Array{}))))
62+
c_array.len = (C.int)(len(go_array))
63+
c_array.data = c_array_data
64+
65+
return c_array
66+
}
67+
68+
//export GoArrayToGo
69+
func GoArrayToGo(c_array *C.Demo_Array) {
70+
data := (*C.int)(c_array.data)
71+
len := c_array.len
72+
go_array := (*[1 << 30]int32)(unsafe.Pointer(data))[:len:len]
73+
ArrayToGo(go_array)
74+
}
75+
76+
//export GoFreeArray
77+
func GoFreeArray(arr *C.Demo_Array) {
78+
C.free(unsafe.Pointer(arr.data))
79+
C.free(unsafe.Pointer(arr))
80+
}
81+
82+
//
83+
// FUNCTIONS
84+
//
85+
86+
//export GoCallbackInGo
87+
func GoCallbackInGo(c_string *C.char) {
88+
go_string := C.GoString(c_string)
89+
CallbackInGo(go_string)
90+
}
91+
92+
//export GoFunctionFromGo
93+
func GoFunctionFromGo() C.Demo_Func_Ptr {
94+
// Use the C stub wrapper to return a C function pointer
95+
return C._GoFunctionFromGo()
96+
}
97+
98+
//export GoFunctionToGo
99+
func GoFunctionToGo(c_ptr C.Demo_Func_Ptr) {
100+
c_string := C.CString("Calling from Go")
101+
C.call_out(c_ptr, unsafe.Pointer(c_string))
102+
}
103+
104+
func main() {}

‎c-go-interface/go_hello/hello_lib.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package main
2+
3+
import "fmt"
4+
5+
func StringFromGo() string {
6+
return "Hello from Go!"
7+
}
8+
9+
func StringToGo(str string) {
10+
fmt.Printf("StringToGo(): %s\n", str)
11+
}
12+
13+
func ArrayFromGo() []int32 {
14+
array := []int32{1, 2, 3}
15+
return array
16+
}
17+
18+
func ArrayToGo(array []int32) {
19+
fmt.Printf("ArrayToGo():")
20+
for i := range array {
21+
fmt.Printf(" %d", array[i])
22+
}
23+
fmt.Printf("\n")
24+
}
25+
26+
func CallbackInGo(str string) {
27+
fmt.Printf("CallbackInGo(): %s\n", str)
28+
}

‎c-meson-utils-test/c-meson-utils-test.c

+4-22
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,6 @@
1515
#include "tempdir.c/tempdir.h"
1616

1717
//////////////////////////////////////////////
18-
char *RENDER_TEMPLATE_VARS(char *TEMPLATE_s, char *VARS_s, char *COLOR){
19-
struct jinja2_render_template_t *c = jinja2_init_config();
20-
21-
c->template_s = TEMPLATE_s;
22-
c->input_json_string = VARS_s;
23-
c->template_file = NULL;
24-
c->output_file = NULL;
25-
c->debug_mode = (DEBUG_MODE == true) || (getenv("DEBUG_MODE") != NULL);
26-
assert(c->template_s != NULL && strlen(c->template_s) > 0);
27-
assert(c->input_json_string != NULL && strlen(c->input_json_string) > 3);
28-
29-
assert(jinja2_render_template(c) == 0);
30-
assert(c->success == true);
31-
assert(c->output_s != NULL && strlen(c->output_s) > 8);
32-
fprintf(stderr, AC_RESETALL "%s%s" AC_RESETALL, COLOR, c->output_s);
33-
return(c->output_s);
34-
}
35-
3618
#define RENDER_TEST_CASE(TEST_CASE_NAME, TEST_CASE_TEMPLATE, TEST_CASE_VARS, COLOR) \
3719
TEST TEST_CASE_NAME(void){ \
3820
RENDER_TEMPLATE_VARS(TEST_CASE_TEMPLATE, TEST_CASE_VARS, COLOR); \
@@ -58,10 +40,10 @@ char *RENDER_TEMPLATE_VARS(char *TEMPLATE_s, char *VARS_s, char *COLOR){
5840
#define ENCODED_VARS_BASH_SCRIPT "{\"x\":123}"
5941
//////////////////////////////////////////////
6042
#define COLOR_TEST_INCBIN_PYTHON_BINARIES AC_YELLOW
61-
#define ENCODED_VARS_TEST_INCBIN_PYTHON_BINARIES \
62-
"{\"binaries\":[" \
63-
"{\"name\":\"meson\",\"dir\":\"submodules/c_ansi/jinja2-cli/bin\"}" \
64-
",{\"name\":\"jinja2-cli\",\"dir\":\"submodules/c_ansi/jinja2-cli/bin\"}" \
43+
#define ENCODED_VARS_TEST_INCBIN_PYTHON_BINARIES \
44+
"{\"binaries\":[" \
45+
"{\"name\":\"meson\",\"dir\":\"submodules/c_ansi\"}" \
46+
",{\"name\":\"\",\"dir\":\"submodules/c_ansi\"}" \
6547
"],\"inc_embedded_python_binaries_struct\":\"struct python_binary_t { char *name, char *dir, };\"}"
6648

6749
//////////////////////////////////////////////

0 commit comments

Comments
 (0)
Please sign in to comment.