Kyle McClintick
Kyle McClintick

Reputation: 43

Wrapping a C++ file as a Python file using SWIG

I'm new to using SWIG and a bit out of my depth as a programmer. I would like to be able to call the functions of a C++ class in python 2 by importing the wrapped class as a module 'import C++_file' and then call it within my python class with something like 'C++_file.function(inputs)'.

Following http://intermediate-and-advanced-software-carpentry.readthedocs.io/en/latest/c++-wrapping.html, I am wrapping the header file multiplyChannel.h:

#include <vector>
#include <complex>

using namespace std;

class MultiplyChannel {
    public:
        MultiplyChannel(double in_alpha);
        void applyToVector(vector<complex<double> > *in_signal);
    private:
        double alpha;
};

which corresponds to my example C++ file multiplyChannel.cpp:

#include "multiplyChannel.h"
#include <vector>
#include <complex>

using namespace std;

MultiplyChannel::MultiplyChannel(double in_alpha){
    this->alpha = in_alpha;
}

void MultiplyChannel::applyToVector(vector<complex<double> > *in_signal){
    unsigned int size = in_signal->size();
    for (int i = 0; i < size; i++) {
        in_signal->at(i).real() = in_signal->at(i).real() * this->alpha;
        in_signal->at(i).imag() = in_signal->at(i).imag() * this->alpha;
    }
}

With the makefile:

all:
    swig -python -c++ -o mult.cpp swigdemo.i
    python setup.py build_ext --inplace

the wrapper file swigdemo.i:

%module swigdemo

%{
#include <stdlib.h>
#include "multiplyChannel.h"
%}

%include "multiplyChannel.h"

and setup.py build file:

from distutils.core import setup, Extension

extension_mod = Extension("_swigdemo", ["mult.cpp"])

setup(name = "swigdemo", ext_modules=[extension_mod])

by typing in my Ubuntu command window:

$ make
swig -python -c++ -o multiplyChannel.cpp swigdemo.i
python setup.py build_ext --inplace
running build_ext
$ python setup.py build
running build
running build_ext

Testing the import using C++_tester.py, I try to multiply the vector [1, 2, 3] into [5, 10, 15] using the MultiplyChannel object 'demo' with instance variable 'in_alpha' of 5x, multiplying all inputs by 5:

#!/usr/bin/python

import swigdemo

if __name__ == '__main__':
    demo = swigdemo.MultiplyChannel(in_alpha=5)
    out = demo.applyToVector(in_signal=[1, 2, 3])
    print(out)

I am not getting past even the import line, receiving the following error:

$ python C++_tester.py
ImportError: ./_swigdemo.so: undefined symbol: _ZN15MultiplyChannelC1Ed

And am unsure what to do as I cannot even gedit or vim into the .so file. I'm guessing my error lies in wrapping incorrectly in my wrapper, build, or makefile, as pretty much everything in the C++_tester.py file auto-completed in my Pycharm IDE.

Many thanks!

Upvotes: 4

Views: 4006

Answers (1)

CristiFati
CristiFati

Reputation: 41116

The problem was indeed related to extension build:

  • swigdemo.i - generates SWIG wrappers (mult.cpp)

  • MultiplyChannel class implementation is in multiplyChannel.cpp

  • When building the extension, since it's a shared object (.so), the linker (by default) doesn't complain about undefined symbols (like the 2 MultiplyChannel methods (as it doesn't know anything about them) - and others), but creates it, considering that the symbols could be available at runtime (when the .so will be loaded)

In short, modify setup.py by adding multiplyChannel.cpp to the extension source flies list:

extension_mod = Extension("_swigdemo", ["mult.cpp", "multiplyChannel.cpp"])

Might also want to check:

Upvotes: 2

Related Questions