Lluís Alemany-Puig
Lluís Alemany-Puig

Reputation: 1243

SWIG wrapper of C++ library for Python - submodules

I'm trying to wrap a C++ library into a Python3 interface using SWIG, and there is a problem I can't quite fix. This library has several namespaces, and I would like to make them modules of the library when wrapped in Python. Assume the following minimal example:

lib_class.hpp lib_class.cpp
lib_ops.hpp   lib_ops.cpp
io_ops.hpp    io_ops.cpp

The files lib_class define a very small class:

#pragma once
namespace lib {
class dummy {
    private:
        int a;
    public:
        dummy();
        dummy(int t_a);
        ~dummy();
        void asdf();
};
}
#include "lib_class.hpp"
namespace lib {
dummy::dummy() {}
dummy::dummy(int t_a) : a(t_a) {}
dummy::~dummy() {}
void dummy::asdf() { a = 3; }
}

The files lib_ops.hpp and lib_ops.cpp define a only one function:

#pragma once
namespace lib {
void lib_operation();
}
#include "lib_ops.hpp"
#include <iostream>
using namespace std;
namespace lib {
void lib_operation() {
    cout << "LIBRARY TOP LEVEL" << endl;
}
}

and, finally, the files io_ops.hpp io_ops.cppdefine another function, this time within the namespacelib::io```:

#pragma once
#include "lib_class.hpp"
namespace lib {
namespace io {
void io_operation(dummy& a);
}
}

#include "io_ops.hpp"

#include <iostream>
using namespace std;

namespace lib {
namespace io {
void io_operation(dummy& a) {
    cout << "LIBRARY SUBMODULE" << endl;
    a.asdf();
}
}
}

I would like to wrap these files into a Python interface so that I can:

import lib
d = lib.dummy(10)
lib.ioop.io_operation(d)
lib.lib_operation()

In other words, I would like the organization of the Python wrapper to be:

lib.dummy              # class
lib.lib_operation      # function
lib.ioop               # submodule
lib.ioop.io_operation  # function within submodule

I've written the following *.i files:

%module lib
%import ioop.i
%{
#include "lib_ops.hpp"
#include "lib_class.hpp"
%}
%include "lib_ops.hpp"
%include "lib_class.hpp"
%module ioop
%{
#include "io_ops.hpp"
using namespace lib;
%}
%include "io_ops.hpp"

This compiles without errors with:

g++ -c -fPIC io_ops.cpp
g++ -c -fPIC lib_ops.cpp
g++ -c -fPIC lib_class.cpp
swig -c++ -python -py3 lib.i
swig -c++ -python -py3 ioop.i
g++ -fPIC -c lib_wrap.cxx -I /usr/include/python3.6
g++ -fPIC -c ioop_wrap.cxx -I /usr/include/python3.6
g++ -fPIC -shared -o _lib.so lib_wrap.o lib_ops.o lib_class.o
g++ -fPIC -shared -o _ioop.so ioop_wrap.o io_ops.o lib_class.o

however, the python script above gives the following error:

Traceback (most recent call last):
  File "test.py3", line 5, in <module>
    lib.ioop.io_operation(d)
  File "/home/lluis/Desktop/example.i/ioop.py", line 66, in io_operation
    return _ioop.io_operation(a)
TypeError: in method 'io_operation', argument 1 of type 'dummy &'

Although I managed to "insert" the namespace lib::io into the "main" module lib as a submodule ioop, it looks as though it didn't know anything about the class lib::dummy.

Is it possible to do this? If so, how can I do it?

Thanks to all of you for your time (and sorry for such a lengthy post).

Upvotes: 1

Views: 790

Answers (1)

Llu&#237;s Alemany-Puig
Llu&#237;s Alemany-Puig

Reputation: 1243

As @Flexo pointed out in one of the comments, the file ioops.i needs an %import. The correct contents of the file are:

%module ioop
%import lib.i
%{
#include "io_ops.hpp"
using namespace lib;
%}
%include "io_ops.hpp"

Upvotes: 1

Related Questions