There is no doubt that C is faster than Python then how do Python library like Numpy perform huge number crunching job so fast and efficiently? Actually, libraries like Numpy are not completely written in Python instead, some parts of the library are written in C which provides performance boost. After writing code in C, we wrap them in Python code which acts like an interface for those C codes. We can then call C functions using Python syntax where actual processing is done in C behind the scene and the result is returned back as Python object. In this article, we will see how to create Python wrapper for our C program on Linux systems using a software called SWIG.
What is SWIG
In a nutshell, SWIG is a compiler that takes C/C++ declarations and creates a wrapper needed to access those declarations from other languages like Python, Tcl, Ruby etc.
It normally required no changes in existing code and create an interface within a minute.
Reasons for creating wrapper
In many occasions we need wrappers, following are few of them –
- Building interpreted interface for existing C programs.
- Building high-performance C modules for scripting languages
- It’s huge pain to test huge C programs, so we write wrappers in some scripting languages like Python, where it’s very easy to write test. etc
Installing SWIG
For downloading SWIG directly from apt repository type following commands –
sudo apt-get update sudo apt-get install swig
Writing Wrapper using SWIG
Consider this piece of C code, having two functions and one global variable –
/* file : gfg.c */ #include <stdio.h> #include <math.h> //our header file #include "gfg.h" #define ll long long double myvar = 3.4; // calculate factorial ll int fact(ll int n) { if (n <= 1) return 1; else return (n * fact(n-1)); } //find mod int my_mod( int n, int m) { return (n % m); } |
Here is our header file gfg.h –
long long int fact( long long int n); int my_mod( int n, int m); |
First, we have to create a SWIG Interface file. This file contains ANSI C function prototypes and variable declaration. Here –
- The %module directive specifies the name of the module we will use in Python.
- %{ .. %} block provides a location to insert additional code such as C header files or additional C declaration into the generated wrapper code.
- %include directive let us include additional files like header files.
/* file : gfg.i */ /* name of module to use*/ %module gfg %{ /* Every thing in this file is being copied in wrapper file. We include the C header file necessary to compile the interface */ #include "gfg.h" /* variable declaration*/ double myvar; %} /* explicitly list functions and variables to be interfaced */ double myvar; long long int fact( long long int n1); int my_mod( int m, int n); /* or if we want to interface all functions then we can simply include header file like this - %include "gfg.h" */ |
Now we will create wrapper code using the command like $ swig -target_language interface_file.i
$ swig -python gfg.i
After executing this command a wrapper code with name “gfg_wrap.c” is created. This files contains a bloated version of our original C code with various error handling code etc. Another file “gfg.py” is generated which is the module we will import in our python script.
After this, we have to generate position-independent code which will be used in shared library by compiling “gfg_wrap.c” and “gfg.c” using 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 generate two object files
“gfg_wrap.o” and “gfg.o”. In above command –
- -fpic generate position-independent code (PIC) suitable for use in a shared library, if supported for the target machine. Such code accesses all constant addresses through a global offset table (GOT)
Note: If you get error something like “… ‘Python.h’ file not found” then following might be possible causes –
- You might not have ‘Python.h’ file or
- You are providing wrong location of ‘Python.h’ file to compiler
To get ‘Python.h’ You must install Python-dev using following command –
$ sudo apt-get install python-dev
To find the correct path of ‘Python.h’ execute following command –
$ python-config --cflags
This will output something like this –
Now replace the path in compilation command with this one for python2.7 or change the version as python3.5 for Python 3.5.
Now, at last, we have to link generated objects files together to create a shared object which is analogous to dll files in windows. Use the following command, this will generate a “_gfg.so” shared object file –
$ gcc -shared gfg.o gfg_wrap.o -o _gfg.so
Now we are ready to test out python wrapper by importing it. Make sure you are in directory having this wrapper file.
>>> import gfg >>> res = fact(5) >>> res 120 >>> res = my_mod(5,2) >>> res 1 >>> gfg.cvar.myvar 3.4
Here C variables are accessed as module.cvar.var_name.
Compiling and Linking using distutils
Instead of typing in commands and figuring out what compilation options are needed to compile files, we can automate this using distutils. Create a setup.py as below –
# File : setup.py from distutils.core import setup, Extension #name of module name = "gfg" #version of module version = "1.0" # specify the name of the extension and source files # required to compile this ext_modules = Extension(name = '_gfg' ,sources = [ "gfg.i" , "gfg.c" ]) setup(name = name, version = version, ext_modules = [ext_modules]) |
Now write following commands to compile and install module –
$ python setup.py build_ext --inplace
It should look something like this on terminal –
Possible Alternatives
Obviously, SWIG is not the only way for creating wrappers, one can consider following alternatives based on their requirements –
- Manual Wrapping
- pyrex
- ctypes (Built in module)
- SIP
In next article, we will see how to create wrapper for C++ code (OPP)
References
This article is contributed by Atul Kumar. If you like Lazyroar and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the Lazyroar main page and help other Geeks.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.