Calling Go Functions from Other Languages
Tags: go, programming, goprogramming, golangprogramming
Published: 2017-02-27 19:05:26

---
title: Calling Go Functions from Other Languages
published: true
description: Expose your Go APIs to languages such as Python, Node, Java, etc
cover_image: https://lh4.googleusercontent.com/JTDBuQyIhtws0oSIOUP9ba3VoGM93Fx5fpFpiLi2PsPWV-r-O4Cv1BcIHzk5iFiiinmMqo8SVmlf7JI=w1393-h748-rw
tags: go, programming, go programming, golang, golang programming
---

Starting with version 1.5, the Go compiler introduced support for several build modes via the `-buildmode` flag. Known as the [*Go Execution Modes*](https://docs.google.com/document/d/1nr-TQHw_er6GOQRsF6T43GGhFDelrAP0NqSS_00RgZQ/edit), these build modes extended the go tool to compile Go packages into several formats including Go archives, Go shared libraries, C archives, C shared libraries, and (introduced in 1.8) Go dynamic plugins.

This post is about compiling Go packages into C shared libraries. With this build mode, the compiler outputs a standard shared object binary file (`.so`) exposing Go functions as a C-style APIs. Here we discuss how to create Go libraries that can be called from *C*, *Python*, *Ruby*, *Node*, and *Java*.

All source code discussed here can be found on [GitHub](https://github.com/vladimirvivien/go-cshared-examples).

## The Go Code
First, let us write the Go code. Assume that we have written an `awesome` Go library that we want to make available to other languages. There are four requirements to follow before compiling the code into a shared library: 

* The package must be a `main`  package. The compiler will build the package and all of its dependencies into a single shared object binary.
* The source must import the pseudo-package `"C"`.
* Use the `//export` comment to annotate functions you wish to make accessible to other languages.
* An empty `main` function must be declared.

The following Go source exports four functions `Add`, `Cosine`, `Sort`, and `Log`. Admittedly, the awesome library is not that impressive. However, its diverse function signatures will help us explore type mapping implications.

File [awesome.go](https://github.com/vladimirvivien/go-cshared-examples/blob/master/awesome.go)

```
package main

import "C"

import (
	"fmt"
	"math"
	"sort"
	"sync"
)

var count int
var mtx sync.Mutex

//export Add
func Add(a, b int) int {
	return a + b
}

//export Cosine
func Cosine(x float64) float64 {
	return math.Cos(x)
}

//export Sort
func Sort(vals []int) {
	sort.Ints(vals)
}

//export Log
func Log(msg string) int {
	mtx.Lock()
	defer mtx.Unlock()
	fmt.Println(msg)
	count++
	return count
}

func main() {}
```

The package is compiled using the `-buildmode=c-shared` build flag to create the shared object binary:

```
go build -o awesome.so -buildmode=c-shared awesome.go
```
Upon completion, the compiler outputs two files: `awesome.h`, a C header file and `awesome.so`, the shared object file, shown below:

```
-rw-rw-r –    1362 Feb 11 07:59 awesome.h
-rw-rw-r – 1997880 Feb 11 07:59 awesome.so
```
Notice that the `.so` file is around 2 Mb, relatively large for such a small library. This is because the entire Go runtime machinery and dependent packages are crammed into a single shared object binary (similar to compiling a single static executable binary).

### The header file
The header file defines C types mapped to Go compatible types using [cgo](https://golang.org/cmd/cgo/) semantics. 

```
/* Created by “go tool cgo” – DO NOT EDIT. */
...
typedef long long GoInt64;
typedef unsigned long long GoUint64;
typedef GoInt64 GoInt;
typedef double GoFloat64;
...
typedef struct { const char *p; GoInt n; } GoString;
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
...
#endif
...
extern GoInt Add(GoInt p0, GoInt p1);
extern GoFloat64 Cosine(GoFloat64 p0);
extern void Sort(GoSlice p0);
extern GoInt Log(GoString p0);
...
```

### The shared object file
The other file generated by the compiler is a `64-bit ELF` shared object binary file. We can verify its information using the `file` command. 

```
$> file awesome.so
awesome.so: ELF 64-bit LSB shared object, x86–64, version 1 (SYSV), dynamically linked, BuildID[sha1]=1fcf29a2779a335371f17219fffbdc47b2ed378a, not stripped
```

Using the `nm` and the `grep` commands, we can ensure our Go functions got exported in the shared object file.

```
$> nm awesome.so | grep -e "T Add" -e "T Cosine" -e "T Sort" -e "T Log"
00000000000d0db0 T Add
00000000000d0e30 T Cosine
00000000000d0f30 T Log
00000000000d0eb0 T Sort
```

## From C
There are two ways to use the shared object library to call Go functions from C. First, we can statically bind the shared library at compilation, but dynamically link it at runtime. Or, have the Go function symbols be dynamically loaded and bound at runtime.

### Dynamically linked
In this approach, we use the header file to statically reference types and functions exported in the shared object file. The code is simple and clean as shown below (some print statements omitted):

File [client1.c](https://github.com/vladimirvivien/go-cshared-examples/blob/master/client1.c)

```
#include <stdio.h>
#include "awesome.h"

int main() {
    printf("Using awesome lib from C:\n");
  
    GoInt a = 12;
    GoInt b = 99;
    printf("awesome.Add(12,99) = %d\n", Add(a, b)); 
    printf("awesome.Cosine(1) = %f\n", (float)(Cosine(1.0)));

    GoInt data[6] = {77, 12, 5, 99, 28, 23};
    GoSlice nums = {data, 6, 6};
    Sort(nums);
    ...
    GoString msg = {"Hello from C!", 13};
    Log(msg);
}
```

Next we compile the C code, specifying the shared object library:

```
$> gcc -o client client1.c ./awesome.so
```

When the resulting binary is executed, it links to the awesome.so library, calling the functions that were exported from Go as the output shows below.

```
$> ./client
awesome.Add(12,99) = 111
awesome.Cosine(1) = 0.540302
awesome.Sort(77,12,5,99,28,23): 5,12,23,28,77,99,
Hello from C!
```

### Dynamically Loaded
In this approach, the C code uses the dynamic link loader library (`libdl.so`) to dynamically load and bind exported symbols. It uses functions defined in `dhfcn.h` such as `dlopen` to open the library file, `dlsym` to look up a symbol, `dlerror` to retrieve errors, and `dlclose` to close the shared library file.

Because the binding and linking is done in your source code, this version is lengthier. However, it is doing the same thing as before, as highlighted in the following snippet (some print statements and error handling omitted).

File [client2.c](https://github.com/vladimirvivien/go-cshared-examples/blob/master/client2.c)

```
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>

// define types needed
typedef long long go_int;
typedef double go_float64;
typedef struct{void *arr; go_int len; go_int cap;} go_slice;
typedef struct{const char *p; go_int len;} go_str;

int main(int argc, char **argv) {
    void *handle;
    char *error;

    handle = dlopen ("./awesome.so", RTLD_LAZY);
    if (!handle) {
        fputs (dlerror(), stderr);
        exit(1);
    }
    
    go_int (*add)(go_int, go_int)  = dlsym(handle, "Add");
    if ((error = dlerror()) != NULL)  { ... }
    go_int sum = (*add)(12, 99); 
    printf("awesome.Add(12, 99) = %d\n", sum);

    go_float64 (*cosine)(go_float64) = dlsym(handle, "Cosine");
    go_float64 cos = (*cosine)(1.0);
    printf("awesome.Cosine(1) = %f\n", cos);

    void (*sort)(go_slice) = dlsym(handle, "Sort");
    go_int data[5] = {44,23,7,66,2};
    go_slice nums = {data, 5, 5};
    sort(nums);
    
    go_int (*log)(go_str) = dlsym(handle, "Log");
    go_str msg = {"Hello from C!", 13};
    log(msg);
    
    dlclose(handle);
}
```

In the previous code, we define our own subset of Go compatible C types `go_int`, `go_float`, `go_slice`, and `go_str`. We use `dlsym` to load symbols `Add`, `Cosine`, `Sort`, and `Log` and assign them to their respective function pointers. Next, we compile the code linking it with the `dl` library (not the awesome.so) as follows:

```
$> gcc -o client client2.c -ldl
```

When the code is executed, the C binary loads and links to shared library awesome.so producing the following output:

```
$> ./client
awesome.Add(12, 99) = 111
awesome.Cosine(1) = 0.540302
awesome.Sort(44,23,7,66,2): 2,7,23,44,66,
Hello from C!
```

## From Python
In Python things get a little easier. We use the `ctypes` [foreign function library](https://docs.python.org/3/library/ctypes.html) to call Go functions from the the awesome.so shared library as shown in the following snippet (some print statements are omitted).

File [client.py](https://github.com/vladimirvivien/go-cshared-examples/blob/master/client.py)

```
from ctypes import *

lib = cdll.LoadLibrary("./awesome.so")
lib.Add.argtypes = [c_longlong, c_longlong]
print "awesome.Add(12,99) = %d" % lib.Add(12,99)

lib.Cosine.argtypes = [c_double]
lib.Cosine.restype = c_double 
cos = lib.Cosine(1)
print "awesome.Cosine(1) = %f" % cos

class GoSlice(Structure):
    _fields_ = [("data", POINTER(c_void_p)), 
                ("len", c_longlong), ("cap", c_longlong)]

nums = GoSlice((c_void_p * 5)(74, 4, 122, 9, 12), 5, 5)
lib.Sort.argtypes = [GoSlice]
lib.Sort.restype = None
lib.Sort(nums)

class GoString(Structure):
    _fields_ = [("p", c_char_p), ("n", c_longlong)]
    
lib.Log.argtypes = [GoString]
msg = GoString(b"Hello Python!", 13)
lib.Log(msg)
```

Note the `lib` variable represents the loaded symbols from the shared object file. We also defined Python classes `GoString` and `GoSlice` to map to their respective C struct types. When the Python code is executed, it calls the Go functions in the shared object producing the following output:

```
$> python client.py
awesome.Add(12,99) = 111
awesome.Cosine(1) = 0.540302
awesome.Sort(74,4,122,9,12) = [ 4 9 12 74 122 ]
Hello Python!
```

## From Ruby
Calling Go functions from Ruby follows a similar pattern as above. We use the the [FFI gem](https://github.com/ffi/ffi) to dynamically load and call exported Go functions in the awesome.so shared object file as shown in the following snippet.

File [client.rb](https://github.com/vladimirvivien/go-cshared-examples/blob/master/client.rb)

```
require 'ffi'

module Awesome
  extend FFI::Library

  ffi_lib './awesome.so'

  class GoSlice < FFI::Struct
    layout :data,  :pointer,
           :len,   :long_long,
           :cap,   :long_long
  end
  
  class GoString < FFI::Struct
    layout :p,     :pointer,
           :len,   :long_long
  end

  attach_function :Add, [:long_long, :long_long], :long_long
  attach_function :Cosine, [:double], :double
  attach_function :Sort, [GoSlice.by_value], :void
  attach_function :Log, [GoString.by_value], :int
end

print "awesome.Add(12, 99) = ",  Awesome.Add(12, 99), "\n"
print "awesome.Cosine(1) = ", Awesome.Cosine(1), "\n"

nums = [92,101,3,44,7]
ptr = FFI::MemoryPointer.new :long_long, nums.size
ptr.write_array_of_long_long  nums
slice = Awesome::GoSlice.new
slice[:data] = ptr
slice[:len] = nums.size
slice[:cap] = nums.size
Awesome.Sort(slice)

msg = "Hello Ruby!"
gostr = Awesome::GoString.new
gostr[:p] = FFI::MemoryPointer.from_string(msg)
gostr[:len] = msg.size
Awesome.Log(gostr)
```

In Ruby, we must extend the `FFI` module to declare the symbols being loaded from the shared library. We use Ruby classes `GoSlice` and `GoString` to map the respective C structs. When we run the code it calls the exported Go functions as shown below:

```
$> ruby client.rb
awesome.Add(12, 99) = 111
awesome.Cosine(1) = 0.5403023058681398
awesome.Sort([92, 101, 3, 44, 7]) = [3, 7, 44, 92, 101]
Hello Ruby!
```

## From Node
For Node, we use a foreign function library called [node-ffi](https://github.com/node-ffi/node-ffi) (and a couple dependent packages) to dynamically load and call exported Go functions in the awesome.so shared object file as shown in the following snippet:

File [client.js](https://github.com/vladimirvivien/go-cshared-examples/blob/master/client.js)

```
var ref = require("ref");
var ffi = require("ffi");
var Struct = require("ref-struct");
var ArrayType = require("ref-array");

var LongArray = ArrayType(ref.types.longlong);

var GoSlice = Struct({
  data: LongArray,
  len:  "longlong",
  cap: "longlong"
});

var GoString = Struct({
  p: "string",
  n: "longlong"
});

var awesome = ffi.Library("./awesome.so", {
  Add: ["longlong", ["longlong", "longlong"]],
  Cosine: ["double", ["double"]],
  Sort: ["void", [GoSlice]],
  Log: ["longlong", [GoString]]
});

console.log("awesome.Add(12, 99) = ", awesome.Add(12, 99));
console.log("awesome.Cosine(1) = ", awesome.Cosine(1));

nums = LongArray([12,54,0,423,9]);
var slice = new GoSlice();
slice["data"] = nums;
slice["len"] = 5;
slice["cap"] = 5;
awesome.Sort(slice);

str = new GoString();
str["p"] = "Hello Node!";
str["n"] = 11;
awesome.Log(str);
```

Node uses the `ffi` object to declare the loaded symbols from the shared library . We also use Node struct objects `GoSlice` and `GoString` to map to their respective C structs. When we run the code it calls the exported Go functions as shown below:

```
awesome.Add(12, 99) =  111
awesome.Cosine(1) =  0.5403023058681398
awesome.Sort([12,54,9,423,9] =  [ 0, 9, 12, 54, 423 ]
Hello Node!
```

## From Java
To call the exported Go functions from Java, we use the [Java Native Access library](https://github.com/java-native-access/jna) or JNA as shown in the following code snippet (with some statements omitted or abbreviated):

File [Client.java](https://github.com/vladimirvivien/go-cshared-examples/blob/master/Client.java)

```
import com.sun.jna.*;

public class Client {
  public interface Awesome extends Library {
    public class GoSlice extends Structure {
      ...
      public Pointer data;
      public long len;
      public long cap;
    }
  
    public class GoString extends Structure {
      ...
      public String p;
      public long n;
    }

    public long Add(long a, long b);
    public double Cosine(double val);
    public void Sort(GoSlice.ByValue vals);
    public long Log(GoString.ByValue str);
  }
  
  static public void main(String argv[]) {
    Awesome awesome = (Awesome) Native.loadLibrary(
      "./awesome.so", Awesome.class);
      
    System.out.printf(... awesome.Add(12, 99));
    System.out.printf(... awesome.Cosine(1.0));

    long[] nums = new long[]{53,11,5,2,88};
    Memory arr = new Memory(... Native.getNativeSize(Long.TYPE));
    Awesome.GoSlice.ByValue slice = new Awesome.GoSlice.ByValue();
    slice.data = arr;
    slice.len = nums.length;
    slice.cap = nums.length;
    awesome.Sort(slice);

    Awesome.GoString.ByValue str = new Awesome.GoString.ByValue();
    str.p = "Hello Java!";
    str.n = str.p.length();
    awesome.Log(str);
  }
}
```

To use JNA, we define Java interface `Awesome` to represents the symbols loaded from the awesome.so shared library file. We also declare classes `GoSlice` and `GoString` to map to their respective C struct representations. When we compile and run the code, it calls the exported Go functions as shown below:

```
$> javac -cp jna.jar Client.java
$> java -cp .:jna.jar Client
awesome.Add(12, 99) = 111
awesome.Cosine(1.0) = 0.5403023058681398
awesome.Sort(53,11,5,2,88) = [2 5 11 53 88 ]
Hello Java!
```

## Conclusion
This post showed how to create a Go library that can be used from other languages. By compiling their Go packages into C-style shared libraries, Go programmers can easily make their projects work with C, Python, Ruby, Node, Java, etc. using in-process integration of shared object binaries. So, next time you create that killer API in Go, remember to shared with non-Go developers.

Follow Vladimir on Twitter [@vladimirvivien](https://twitter.com/VladimirVivien)!

If you are learning Go, checkout Vladimir Vivien's book on Go, titled [*Learning Go Programming*](https://www.packtpub.com/application-development/learning-go-programming) from Packt Publishing.

[![Learning Go Programming Book](https://vladimirvivien.github.io/learning-go/front-cover-small-243x300.jpg)](https://www.packtpub.com/application-development/learning-go-programming)

This post was originally published on Medium by its author Vladimir Vivien as [*Calling Go Functions from other Languages*](https://medium.com/learning-the-go-programming-language/calling-go-functions-from-other-languages-4c7d8bcc69bf#.bwzvuz988).