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!
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:
[SO]: SWIG: How to pass list of complex from c++ to python (for the next problem you're going to run into)