1

I am trying to build a Python wrapper around a C++ code using SWIG on Linux and I am not sure if the wrapper is being created correctly. As an example, here is a mini-problem (within my larger project).

Suppose I have a file called message.cpp

message.cpp

#include <iostream>

#include "message.hpp"

void warning (std::string message) {
  using std::cout;
    cout << "\n!! WARNING!  " << message << " !!\n";
}

The corresponding header file is:

message.hpp

#include <string> 
#include <fstream>   // file I/O
#include <sstream>
#include <iostream>

void warning (const std::string message);

To pass this through SWIG, I have the following SWIG input file:

message.i

%module message

%{
#include "message.hpp"
%}

%include "message.hpp"

From Linux terminal, I create the wrapper using the following commands:

$ swig -c++ -python message.i

$ g++ -fpic -c message.hpp message_wrap.cxx message.cpp -I/usr/include/python2.7/ -I/usr/include

$ gcc -shared message_wrap.o message.o -o _message.so -lstdc++

All the 3 steps at the command prompt pass without any errors on the terminal and the following files are produced without any complaints:

message_wrap.cxx
message_wrap.o
message.o
message.py
message.hpp.gch
_message.so

I then try to test out the Python wrapper by entering the following commands on Linux terminal (staying in the same directory):

$ python
Python 2.7.17
[GCC 7.4.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import _message
>>> _message.warning("SampleMessage")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: in method 'warning', argument 1 of type 'std::string const'

I was expecting it to simply display the line WARNING! SampleMessage on the terminal, but instead it crashes. So it appears something has gone wrong. Can someone guide me where the problem lies please?

1 Answers1

1

Your declaration and implementation don't match (missing const) and you should import message not _message. All that said, what you are missing is:

%include "std_string.i"

in your .i before the include of message.hpp. That will provide the typemaps needed to convert Python str to C++ std::string.

Wim Lavrijsen
  • 3,453
  • 1
  • 9
  • 21
  • Brilliant! That worked, thank you. On digging a bit deeper, it appears all the possible SWIG libraries are stored at `/usr/local/share/swig/4.0.1/` and its subdirectories on my PC. Since my project has lots of large C++ files linked in a complex manner, it would be highly time-consuming to tell which particular SWIG libraries I should include while wrapping a particular C++ file. Silly question: Would it be harmless if I included **all** the SWIG libraries installed on my PC? Or is there a smarter way of going about it, so that the required libraries are picked up automatically? – Curious Leo Jan 08 '20 at 18:38
  • 1
    Yes, mostly harmless. That is, typemaps are code snippets that get placed in-line only if used. And if helper routines are placed in the wrapper file, then these are declared static and duplicated across module anyway (but again only if used). Your biggest cost is swig running slower, but I doubt that's an issue relative to total compilation time. Actual problems with swig at scale are of a different nature: you need to recompile and relink the wrapper for every version of python and take care not to duplicate classes. It's not my thing for binding large C++ projects (but I'm biased). – Wim Lavrijsen Jan 08 '20 at 20:47