4

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!

1 Answers1

2

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"])

Check [SO]: SWIG: How to pass list of complex from c++ to python for the next problem you're going to run into.

CristiFati
  • 38,250
  • 9
  • 50
  • 87
  • thank you. I have a new message: "error: command 'c++' failed with exit status 1", "makefile:2: recipe for target 'all' failed", which describe an error on the line: "swig -python -c++ -o multiplyChannel.cpp swigdemo.i", within my makefile. I have followed https://askubuntu.com/questions/685380/encountered-error-command-c-failed-with-exit-status-1-while-trying-to-ins and https://stackoverflow.com/questions/36127987/error-command-c-failed-with-exit-status-1 but the error message persists, and don't see any relevant issues in the link you posted (although ill need that later for sure) – Kyle McClintick Mar 28 '18 at 19:09
  • The failed step is before the original question. That means you modified some of the files (most likely it's *swigdemo.i*). But the error doesn't make any sense, and the 2 links don't seem to have anything to do here. are you sure the "*-c++*" argument doesn't contain a space (after "-")? – CristiFati Mar 28 '18 at 20:04
  • everything I have quoted is copy pasted, there is no space after the hyphen. When I remove the fix you pointed out in setup.py this error is not there, and make occurs like in my OP, so it looks like this error is related to the fix somehow, although I don't see how – Kyle McClintick Mar 28 '18 at 20:20
  • If I delete mult.cpp from setup.py the error goes away but then I'm back to the undefined symbol error – Kyle McClintick Mar 28 '18 at 20:27
  • Are you saying that applying the fix I proposed to the question (the code posted **as it is at this point** (2nd edit)) yields this behavior? That doesn't make any sense. My fix targets the compile phase (`python setup.py`) while your error happens before (`swig`). It's smth else generating this behavior (you updated libraries on your system, or modified the files?). Btw, you accepted the answer before testing it? For me it builds, the *.so* is imported, but when calling the func because you didn't define the conversion protocol right (the URL I included). Include the output in the question. – CristiFati Mar 28 '18 at 20:54