Golang interop with C/C++

Whether we're willing to admit it or not, sometimes using legacy code is just preferable to re-writing code with all the latest shiny bells and whistles. This is even more prevalent when that legacy code is well proven over years of battle tested production use.
When I began investigating how to use Windows integrated authentication (SSPI) inside Golang I found the resources available unsurprisingly sparse; a few undocumented repositories here and there, the odd blog post and the occasional speculative GitHub issue.
I knew existing SSPI code samples existed in C++ so I decided to see what the interop between the 2 languages was like.


cgo allows you to embed C directly in your .go files and build simply using the existing go tool chain go build. Go build will actually use gcc so make sure you have that installed. I had to install this version of gcc on Windows 64-bit as it supported both 32-bit and 64-bit builds.

package main

int add(int x, int y) {  
    return x + y;
import "C"  
import "fmt"

func main() {  
    sum := C.add(3, 5)
    fmt.Printf("Sum = %v", sum)
        // Output: Sum = 8

As you can see, I'm writing the C code in a commented section just above an import of a special package "C". You can even pull in additional external header files using #include and set compiler flags like so // #cgo CFLAGS: -DPNG_DEBUG=1. The "C" package also brings in a bunch of helper functions for working with C types such as C.CString which is effectively a char*.
This is all well and good but I wanted to be able to run C++ and not just vanilla C. After looking around a little more I realised it is actually not supported due to C++'s inconsistent ABI and name mangling... bummer.


However, all is not lost! You can use swig to generate the required glue code for our C++ interface to allow us to call it from go. In actual fact, that clue code is another layer of redirection; rather than calling directly into C++ you are proxying via a layer of C code. This C code is generated by swig by introspecting your C++ interface files.
To use it, simply install swig on your machine from the previous link. Then create a folder structure somewhere under your $GOPATH as you would for any go package and add the following files.

  - world.cxx
  - world.hxx
  - world.go
  - world.swigcxx

This is your C++ implementation file - just like any other C++ project.

#include "world.hxx"

using namespace std;

World::World() {  
    // empty default constructor

World::~World() {  
    // empty default destructor

void World::Hello(const char* cname) const {  
    string name = "";
    for (int i = 0; cname[i] != '\0'; ++i) {
        name += cname[i];
    cout << "Hello " << name << " from C++" << endl;

This is your C++ header file, again just like any other C++ project.

#ifndef WORLD_H
#define WORLD_H
#include <string>
#include <iostream>

class World  
    void Hello(const char* cname) const;

The go compiler won't recognise this as a go module unless there is a .go file with a package declaration in it, so let's add one!

package world  

This is the swig magic file. This is where you tell swig what interface you want to expose to the go code. You can define individual variables, functions or just point it to a header file as I have done here.

%module world
/* Includes the header in the wrapper code */
#include "world.hxx"

/* Parse the header file to generate wrappers */
%include "world.hxx"

For more information on how to write your swig interface file, visit the swig docs.


This is going to be the client of the C++ library we've just defined above. As we've defined the C++ code as a go package we can simply import from our go path like any other package. Notice, swig converts constructors into NewObject() calls, there are a few conventions like this you should probably lookup on their docs.

Types are not consistent between C, C++ and Go so make sure to use strict types (uint32) and lowest common denominator (c-strings)

package main

import (  


func main() {  
    name := "dotjson"
    fmt.Printf("Hello %v from Go!\n", name)
    w := world.NewWorld()
        // Output: Hello dotjson from Go!
        //         Hello dotjson from C++

And there you have it ladies and gents, leveraging C++ code from inside your Golang code. You can extend this method to bring in standard libraries such as OpenCV or your own existing libraries. It's not all good news though - using cgo should be used sparingly if at all, you will not get any performance gains over writing the code directly in go and it will drastically slow down your compilation. However, for situations where it's unavoidable this is an option.

This post is clearly not a deep dive into the internals of swig, cgo or the differences between the languages etc. but hopefully it gives you enough of an introduction to get started!