C Extension with Python

Goal

Python allows you to call a library developed in C/C++.


Requisite

  • GCC compiler to compile C code
  • Swig to compile C into C wrapper for python


Create a project directory.

$ mkdir project && cd project

Create a c header file - example.h (just one line)

int fact(int n);


Create a definition file - example.c

#include "example.h"
#include "stdio.h"

int fact(int n) {
    if (n < 0){ /* This should probably return an error, but this is simpler */
        return 0;
    }
    if (n == 0) {
        return 1;
    }
    else {
        /* testing for overflow would be a good idea here */
        return n * fact(n-1);
    }
}


int main(void){
    int v = fact(10);
    printf("Result: %d", v);
}


Create an interface file for Swig

%module example
%{
#define SWIG_FILE_WITH_INIT
#include "example.h"
%}

int fact(int n);


Lastly create a python distutils setup file - setup.py

#!/usr/bin/env python
"""
setup.py file for SWIG example
"""
from distutils.core import setup, Extension
# Underscore in the extension name is requirement of Swig.
example_module = Extension('_example', sources=['example_wrap.c', 'example.c'])
setup (name = 'example',
       version = '0.1',
       author      = "SWIG Docs",
       description = """Simple swig example from docs""",
       ext_modules = [example_module],
       py_modules = ["example"])


Check swig version

$ swig -version
SWIG Version 3.0.12
Compiled with clang++ [x86_64-apple-darwin18.0.0]
...


Check gcc version

$ gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/c++/4.2.1
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
Target: x86_64-apple-darwin18.2.0
...


Check python version

$ python --version
Python 3.6.6 :: Anaconda custom (64-bit)


Run swig utility to create the wrapper c files.

$ swig -python example.i


Run python dist setup tool to build the module

$ python setup.py build_ext --inplace


Call factorial function from python

$ python -c "import example; print(example.fact(10))"
3628800