Calling C++ Code From Go With SWIG
http://zacg.github.io/blog/2013/06/06/calling-c-plus-plus-code-from-go-with-swig/
Recently while working on a Go based project I needed to use some functionality from another large C++ library. The library’s size and complexity made re-writing it in Go unfeasible. After some research I decided to use the popular SWIG (Simplified Wrapper and Interface Generator) framework to enable interop between my two projects.
The following is a brief tutorial to guide you through wrapping a C++ class with a Go package which can be called from any Go program.
Start by installing GO and SWIG if not already installed
|
|
Update: The debian package is out of date and lacking many go related fixes, it is best to install current SWIG release from SWIG website: http://swig.org
I also recommend installing golang from source as some of the following commands only work with go 1.1 and up. http://golang.org/doc/install/source
Once everything in installed the first step is to define a module file which will tell the SWIG tool what code in the C++ project to expose in the resulting GO package. We’ll assume your project is object oriented with cpp/header files for each class, when this is the case we can just include the desired header files in our SWIG module.
We will pretend our C++ project is a dynamically linked shared library called “simplelib” and contains the following files:
|
|
|
|
|
|
We will add a module file called simplelib.swig. Inside we include the simpleclass.h header, this will instruct the SWIG tool to generate wrapping code for this class allowing us to use it in GO.
|
|
If your wrapped class(es) are simple and use primitive types the above swig file should suffice, SWIG will translate the following primitive types to the specified Go types
C/C++ type | Go type |
---|---|
bool | bool |
char | byte |
signed char | int8 |
unsigned char | byte |
short | int16 |
unsigned short | uint16 |
int | int |
unsigned int | uint |
long | int32 or int64, depending on -long-type-size |
unsigned long | uint32 or uint64, depending on -long-type-size |
long long | int64 |
unsigned long long | uint64 |
float | float32 |
double | float64 |
char * char [] |
string |
If your target code contains non-primitive types you have a bit more work to do. SWIG includes headers to help with common non primitive types like string and vector from the standard library. Vectors bring up another issue because they use templates, template types have to be explicitly defined in your SWIG mapping file. A class that uses std::string and std::vector might look like the following:
|
|
The following definitions are included with the SWIG library, go here for full reference
C++ class | C++ Library file | SWIG Interface library file |
---|---|---|
std::deque | deque | std_deque.i |
std::list | list | std_list.i |
std::map | map | std_map.i |
std::pair | utility | std_pair.i |
std::set | set | std_set.i |
std::string | string | std_string.i |
std::vector | vector | std_vector.i |
Next we need to generate the necessary C++ wrapper code to allow Go to bind to it.
Update: With the official release of Go 1.2, the go build tool now recognizes SWIG files. The following steps are not necessary but may still be useful for users with more complicated build systems.
If you are using Go 1.2 simply include the .swig module file in your package directory along with the relevant c++ code files and run “go build” or “go install”
|
|
Common optional parameters you may need to use:
- “-soname” for specifying the name of your compiled shared library which is dynamically linked at runtime. e.g. -soname libSimpleLib.so.1
- “-intgosize” Depending on which version of go you are using 1/1.1 and which platform you are targeting you may need to explicitly set the Go int size (note the documentation for this is currently out of date). e.g. -intgosize 64
The above SWIG command should generate 3 new files in your project directory. Your project directory should now look something like the following:
|
|
Now we need to include these 3 new files in our projects. Simplelib.cxx contains the C++ wrapper code allowing your C++ project to interop with CGO. simplelib_gc.c contains the C code designed to be called from CGO. simplelib.go contains the GO code stubs for the resulting GO package, it uses cgo to call into the simplelib_gc.c interfaces.
Add the simplelib.cxx file to the C++ project and build with the projects C++ compiler (I have only tested this process with GCC). Simply add it to your makefile or build script.
simplelib_gc.c and simplelib.go need to be included in the go package using the following 5/6/8c and 5/6/8g commands.
|
|
The last step is installation: first install your compiled C++ shared library, then run go install on the package created in the last step.
|
|
If the installation was successful you should see simplelib.a file in /go/pkg//
That’s it! you should now be able to import “simplelib” in your go projects and call the wrapped C++ code.
Setting up Build Scripts
To recap the steps required are:
- Run SWIG tool (generate wrapper code)
- Compile C++ project (including new wrapper code)
- Copy the built C++ library and files generated in step 1 to a directory in your go path
- Link and package the generated files into a Go Package
- Run Go install to make the new package available in your applications
And here is an example makefile:
|
|
Feel free to leave your comments below.