index.html :: rss :: github :: telegram :: email

calling Go code from C

03 Nov 2024

Let's call some Go code from C! Why? Because I'm too lazy^Wdumb to write robust enough network code with tls and requests pool using C.

First, we need to make Go's symbols exportable, pay attention to import "C" and //export Name (no space!):

package main

import "C"

//export Echo
func Echo(s string) {
	log.Printf("go: echo: %q", s)
}

//export Ints
func Ints(is []int) {
	log.Printf("go: ints: got %d values %v", len(is), is)
}

//export Strings
func Strings(ss []string) {
	log.Printf("go: strings: %s", strings.Join(ss, ", "))
}

// we need an empty main in package main.
func main() {} 

Then, build this module as shared library:

CGO_ENABLED=1 go build -o libwtf.so -buildmode=c-shared .

You'll get libwtf.so and libwtf.h. The header file contains all exportable types and functions from Go code.

Now we can these functions from C:

// Go's exportable symbols are defined in libwtf.h
#include "libwtf.h"
#include <stdio.h>
#include <string.h>

int main() {
  // pass C strings into Go:
  char *c = "this is a C string\0";
  GoString gs = {.p = c, .n = strlen(c)};
  Echo(gs);

  // build and use Go's []int:
  GoInt numbers[5] = {42, 13, 8, 1989, 0};
  GoSlice intSlice = {.data = numbers, .len = 5, .cap = 5};
  Ints(intSlice);

  // build and use Go's []string
  char *strings_to_pass[3] = {
      "foo",
      "barrr",
      "lorem ipsum dolor sit amet",
  };

  // build slice of Go strings from an array of C strings:
  GoString goStrings[3] = {};
  for (int i = 0; i < 3; i++) {
    goStrings[i].p = strings_to_pass[i];
    goStrings[i].n = strlen(strings_to_pass[i]);
  }

  GoSlice strSlice = {.data = goStrings, .len = 3, .cap = 3};
  Strings(strSlice);
}

Fat pointers... do you feel it?

Finally, we need to link against our "libwtf":

cc -o main_c -lwtf -L./ -I./ main.c

Options explanation:

-I tells CC to look for includes (our "libwtf.h") in a current directory.

-L tells linker to look for object (our "libwtf.so") in a current directory.

-lwtf (which is lowercase L followed by wtf) specifies the lib to link against, without the "lib" prefix and ".so" suffix.


This repo contains a lot of Go FFI examples for popular languages.

An example of calling Go code from Python.