Home > front end >  How can i use a single C function through SWIG?
How can i use a single C function through SWIG?

Time:11-01

i have a SWIG C-python interface. I want to make individual functions from test.c available in my python interface. I feel like i am wasting hrs on the documentation without finding the simple way to do it. The only options i know are to either:

%module test
%{
#include "test.h"
//#include "test.c"
%}

%include "stdint.i"  # Add support for uint8_t, int32_t, etc...

/** Keep test immutable for now because we have const struct members in the
 *  header file which can not be reassigned.
 */
%immutable;
%include test.h // Test header for interface debugging
//%include test.c
//%import test.h
%mutable;

I tried either #including 'test.c' in the %{} section of my interface (This section just copies the file content into the target interface), %include 'test.c' or %import 'test.c'

But i have a whole bunch of other functions in 'test.c' that have dependencies to other files and i cannot import the generated interface in python (ImportError: Undefined symbol:)

#include "test.h"
#include "someotherfunctions.h"
#include "specialdefines.h"


int testFunc(int n, int m) // The function i want to use
{
    int res = n   m;
    return res;
}

int otherFunc(void)
{
    otherDifferentFunc(); // Stuff from other header/c files which my interface doesnt know
}

SPECIALMACRO(X) // More stuff from other headers that i dont want in my interface
int foo = someOtherOperation(500);

The header file test.h:

/* Functions ----------------------------------------------------------------*/

int testFunc(int n, int m);

I feel like i am not having the right approach to make single functions available in my Python interface without including all the unwanted stuff from all the headers in my source file. In reality, my 'test.c' is quite large and includes a whole bunch of header for all sorts of symbols and external functions used. If i dont #include all oft those in my %{} interface section, i get the import error. But if i include them, they again require other headers (its a large project) and i am starting a messy chain of includes for just a tiny function, unnecessary bloating my interface. This can't be the SWIG way to go guys?

If someone knows a good way to solve this, please let me know.

CodePudding user response:

%module test

%{
// Whatever goes here is directly copied to the generated wrapper code.
// Put what you need here for the wrapper to build, typically just
// your public headers.
#include "test.h"
%}

// Anything you declare or %import is processed to make the SWIG interface.
// You can %import "test.h" and  all the functions *directly* in
// the header (not other #include in the header), are exposed to Python.
//
// If you only want one function, just put its prototype, like:
int testFunc(int n, int m);

When you build the wrapper, swig the .i file to generate test_wrap.c, then compile test.c and test_wrap.c and link them together at the link step.

An example:

test.i

%module test

%{
#include "test.h"
%}

// uncomment to bring in func1 and func2 (not func3, but it's still used by func2)
//%include "test.h"

// only exposes func1
int func1();

test.h

int func1();
int func2();

test.c

#include "test.h"

int func3() { return 3; }
int func2() { return func3() - 1; }
int func1() { return func2() - 1; }

makefile (Windows, Microsoft compiler)

all: _test.pyd

test_wrap.c test.py: test.i test.h
    echo swigging...
    swig -python test.i

_test.pyd: test_wrap.c test.c test.h
    cl /nologo /LD /MD /W3 /Fe_test.pyd /Id:\dev\python310\include test_wrap.c test.c -link /libpath:d:\dev\python310\libs

Output (built as above, only func1() exposed):

>>> import test
>>> test.func1
<function func1 at 0x000001CF6DEF7F40>
>>> test.func1()
1
>>> test.func2()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'test' has no attribute 'func2'. Did you mean: 'func1'?

Output (built uncommenting the %include and commenting the prototype):

>>> import test
>>> test.func1()
1
>>> test.func2()
2
>>> test.func3()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'test' has no attribute 'func3'. Did you mean: 'func1'?
  • Related