Using SWIG to wrap C++ for Python


Intro

In order to be able to access the C++ code from Python (or other languages) I have wrapped some of the functionality using SWIG (Simple Wrapper Interface Generator). There is a short tutorial on this page which covers some of the basics, however this is not enough. I am going to want to wrap far more complex data types and classes.


Getting started

Starting with some code



 /* File : example.c
  * Created by Glen Berseth
  * Date: Oct 25, 2015
  *
  * */
#include



/*
 * Word.h
 *
 *  Created on: 2015-10-25
 *      Author: gberseth
 */
#ifndef WORD_H_
#define WORD_H_

#include

class Word
{
public:
    Word(std::string the_word);
    virtual ~Word();

    virtual void updateWord(std::string word);
    virtual std::string getWord();

private:
    std::string _the_word;
};

#endif /* WORD_H_ */



/*
 * Word.cpp
 *
 *  Created on: 2015-10-25
 *      Author: gberseth
 */
#include "Word.h"

Word::Word(std::string the_word) :
    _the_word(the_word)
{
    // TODO Auto-generated constructor stub
}

Word::~Word() {
    // TODO Auto-generated destructor stub
}

void Word::updateWord(std::string word)
{
    this->_the_word = word;
}

std::string Word::getWord()
{
    return this->_the_word;
}

There are some global methods, some global variables and a class that uses a non C-like class std::string.

Create an Interface File

An interface file is kind of like a header file but to be used specifically by swig. In the file you should include all of the methods/attributes/variables/header file you want to be exported. For example:



/* example.i */
%module example
 %{
 /* Put header files here or function declarations like below */
 #include "example.h"
 #include "Word.h"
 %}

 %include "std_string.i"
 %include "example.h"
 %include "Word.h"

Note: to be able to use std::string properly you need to include the interface file for the class (std_string.i).This interface file includes both the header files for the methods and class(es) I want to be able to use in Python.



Generating and Compiling

I found this part to be the most confusing and difficult. SWIG can generate a enormous wrapper file that is almost unreadable and then you need to compile it. The errors you get from this process may not seem simple.




  1. First generate the wrapper code

    swig3.0 -c++ -python example.i

    Note: The **-c++** help because it tells SWIG what language is being wrapped, I think it might be C be default. 
  2. Compile the code

    g++ -fpic -c example.h example_wrap.cxx Word.cpp -I/usr/include/python2.7/

    You need to add the include directory to that the compilation can find "Python.h". 
  3. Link and Build

    gcc -shared example_wrap.o Word.o -o _example.so -lstdc++

Linking gave me a rather difficult time. I was getting ImportError: ImportError: undefined symbol: _ZTVN10__cxxabiv117__class_type_infoE errors in python when importing the library. This turned out to be caused by not including the stdc++ link file linking. After adding that link everthing works very nicely.  

Use in Python

Using the library in python not might needs be so straightforward. In a more customary Python manner the first argument to a class method is the class object itself. This method is done manually in when using the generated Python code.



Python 2.7.6 (default, Mar 22 2014, 22:59:56)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import _example
>>> _example.new_Word("meat")
>>> w = _example.new_Word("meat")
>>> _example.Word_getWord(w)
'meat'
>>> _example.Word_updateWord(w,"beef")
>>> _example.Word_getWord(w)
'beef'
>>>



References 

  1. http://web.mit.edu/svn/src/swig-1.3.25/Examples/python/class/index.html2. http://swig.10945.n7.nabble.com/Wrapping-static-library-in-Linux-td5112.html3. http://www.swig.org/tutorial.html4. http://intermediate-and-advanced-software-carpentry.readthedocs.org/en/latest/c++-wrapping.html