C / C ++ Packaging for Python Using SWIG — Set 1



There is no doubt that Numpy, executes a huge amount of tasks ? In fact, libraries like Numpy are not written entirely in Python, some parts of the library are written in C, which provides better performance. After writing the C code, we wrap them in Python code, which acts as an interface for those C codes. We can then call C functions using Python syntax, where the actual processing is done in C behind the scenes, and the result is returned back as a Python object. In this article, we will see how to create a Python wrapper for our C program on Linux systems using SWIG software.

What is SWIG

In a nutshell, SWIG — it is a compiler that accepts C / C ++ declarations and wraps it up to access those declarations from other languages ​​like Python, Tcl, Ruby, etc.
Usually this does not require any changes to existing code and creates an interface within a minute.

Reasons for creating a wrapper

In many cases we need wrappers, the following are —

  • Building an interpreted interface for existing C programs.
  • Building high-performance C modules for scripting languages ​​
  • Testing huge C programs is very difficult, so we write wrappers in some scripting languages ​​like Python where it is very easy to write tests. etc

Installing SWIG

To download SWIG directly from the apt repository, enter the following commands —

 sudo apt-get update sudo apt-get install swig 

Writing a Wrapper using SWIG

Let`s look at this piece of code at C with two functions and one global variable —

/ * file: gfg.c * /

 
# include & lt; stdio.h & gt; 
# include & lt; math.h & gt; 

 
// our header file
# include "gfg.h"
# define ll long long

 

double myvar = 3.4; 

 
// calculate factorial

ll int fact (ll int n)

{

if (n & lt; = 1)

return 1; 

else

  return (n * fact (n-1)); 

}

 
// find the mod

int my_mod ( int n, int m )

{

return (n% m); 

}

Here is our header file —

long long int fact ( long long int n); 

int my_mod ( int n, int m); 

First we have to create the SWIG interface file . This file contains prototypes of ANSI C functions and variable declarations. Here —

  • The % module directive specifies the name of the module we will use in Python.
  • % {. .% } provides a place to insert additional code, such as C header files or additional C declarations, into the generated wrapper code.
  • The % include directive allows us to include additional files such as header files.

/ * file: gfg.i * /

 
/ * name of the used module * /
% module gfg
% {

/ * Every thing in this file is copied into the

wrapper file. Include the C header file required

compile the interface * /

# include "gfg.h"

  

/ * variable declaration * /

double myvar; 

%}

 
/ * explicitly list functions and variables for interaction * /

double myvar; 

long long int fact ( long long int n1); 

int my_mod ( int m, int n); 

 
/ * or if we want to link all the functions, then we can just

include a header file like this -

% include & quot; gfg.h & quot;

* /

Now we will create the wrapper code using a command like

 $ swig -python gfg.i 

This command generates wrapper code named “gfg_wrap.c” . These files contain a bloated version of our C source with different error handling code, etc. Generated another file “gfg.py”, which is the module we are importing into our python script.

After that we have to generate position-independent code to be used in the shared library by compiling “gfg_wrap.c” and “gfg.c” with the following command:

 $ gcc -c -fpic gfg_wrap.c gfg.c -I / use / include / python2.7 

Replace python2.7 with your Python version. This will create two object files
“Gfg_wrap.o” and “gfg.o” . In the above command —

  • generate position independent code (PIC) suitable for use in the shared library if supported for the target machine. This code accesses all permanent addresses through the Global Offset Table (GOT)

Note: if you receive an error message such as the following possible causes —

  • You may not have the & # 39; Python.h & # 39; or
  • You are entering the wrong location for the & # 39; Python.h & # 39; for the compiler

To get & # 39; Python.h & # 39; you have to install Python-dev, using the following command —

 $ sudo apt-get install python-dev 

To find the correct path to Python.h, run the following command —

 $ python-config --cflags 

This will output something like this —

Now replace the path in the compile command with this one for python2.7 or change the version to python3.5 for Python 3.5.

Now, finally, we have to link the generated object files together to create a shared object, which is similar to the DLL files on Windows. Use the following command, this will generate a shared object file “_gfg.so”

 $ gcc -shared gfg.o gfg_wrap.o -o _gfg.so  

We are now ready to test the Python shell by importing it. Make sure you are in the directory with this shell file.

 & gt; & gt; & gt; import gfg & gt; & gt; & gt; res = fact (5) & gt; & gt; & gt; res 120 & gt; & gt; & gt; res = my_mod (5,2) & gt; & gt; & gt; res 1 & gt; & gt; & gt; gfg.cvar.myvar 3.4 

Here C variables are available as.

Compiling and linking using distutils

Instead of typing commands and figuring out what compilation options are needed to compile files, we can automate this with distutils. Create as shown below —

# File: setup.py

 

from distutils.core import setup, Extension

# module name

name  = "gfg"

 
# module version

version = "1.0"

 
# specify extension name and source files
# required for compilation

ext_modules = Extension (name = `_gfg` , sources = [ " gfg.i " , " gfg.c " ] )

 

setup (name = name,

version = version,

  ext_modules = [ext_modules])

Now write the following commands to compile and install the module —

 $ python setup.py build_ext --inplace 

This should look like do something like this on the terminal —

Possible alternatives

Obviously, SWIG — not the only way to create wrappers, the following alternatives could be considered based on their requirements —

In the next article we will see how to wrapper C ++ (OPP) code

Links

This article courtesy of Atul Kumar . If you are as Python.Engineering and would like to contribute, you can also write an article using contribute.python.engineering or by posting an article contribute @ python.engineering. See my article appearing on the Python.Engineering homepage and help other geeks.

Please post comments if you find anything wrong or if you`d like to share more information on the topic discussed above.