Welcome, guest | Sign In | My Account | Store | Cart

A simple python function to automate using the swig process for creating C modules for use inside Python.

Python, 121 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import commands


def swigit(modulename, Csources, Cheaders,
           SwigExtra ="",
           Libs = ['-lm'],
           PythonIncludePath='/usr/local/include/python2.4/',
           verbose=False):
    """
    Creates a shared C module for inclusion in Python.
    
    Arguments 
       modulename -  name of module to create (no extension).
       Cheaders   -  list of header files.
       Csources   -  list of source files.
       SwigExtra  -  additional swig declarations as a string.
       Libs       -  list of extra libs to link.
       PythonIncludePath - Python's include directory.
       verbose    -  set to True for informative message printing.

    In the current version, all header and source files are assumed to be
    in the current directory.
    """
    
    """
    1. Create the swig interface file modulename.i
    """
    s = ""
    s = "%module " + "%s\n" % modulename
    s = s + "%{\n"
    for header in Cheaders:
        s = s + '#include "%s"\n' % header
    s = s + "%}\n\n"

    # Modify recipe to handle particular cases.
    s = s + SwigExtra

    for header in Cheaders:
        s = s + "%%include %s \n" % header
    if verbose:
        print "Creating swig interface file with contents:\n", s
    str2file(s, "%s.i" % modulename)

    """
    2. Create the shared dll.
    """
    s = "swig -python %s.i" % modulename
    if verbose:
        print "Processing interface file:"
        print " ", s
    status, output = commands.getstatusoutput(s)
    if status != 0:
        if verbose:
            print output
        return status

    """
    3. Compile wrapper file.
    """
    s = "gcc -Wall -I%s -fpic -c %s_wrap.c" % (PythonIncludePath, modulename)
    status, output = commands.getstatusoutput(s)

    s = "gcc -Wall -fpic -c "
    for source in Csources:
        s = s + " %s " % source
    print "Compiling wrapper and source files to object files."
    print " ", s
    status, output = commands.getstatusoutput(s)
    if status != 0:
        if verbose:
            print output
        return status

    """
    4.  Create the shared module file.
    """
    s = "gcc -Wall -O3 "
    for lib in Libs:
        s = s + " %s "  % lib
    s = s + " -shared %s_wrap.o" % modulename
    for source in Csources:
        s = s + " %s.o" % source.split(".")[0]
    s = s + " -o _%s.so" % modulename
    if verbose:
        print "\nCreating module file."
        print " ", s
    status, output = commands.getstatusoutput(s)
    if status != 0:
        if verbose:
            print output
    return status

def str2file(s, filename):
    """
    Dumps string to file.
    """
    f = open(filename, "wt")
    for lines in s.split("\n"):
        print >> f, lines
    f.close()


if __name__ == "__main__":

    extra = """
%include "carrays.i"
%array_class(double, doubleArray)
%array_class(int, intArray)
"""

    modulename = "mymodule"
    if swigit(modulename, ["sphere.c"], ["sphere.h"], SwigExtra = extra, verbose=True) != 0:
        print "There is an error in processing ", modulename
    else:
        import mymodule
        
        x    = mymodule.doubleArray(2)
        x[0] = 2.0
        x[1] = 1.0

        print mymodule.sphere(2, x)

Simplifies creation of C shared modules for importing inside Python. Current version is for Linux platforms. To run the simple example, create the "sphere.c" file with contents

include <math.h>

include "sphere.h"

double sphere(int n, double x[]) { double s = 0.0; int i; for (i = 0; i < n; i++) { s += x[i] * x[i]; } return sqrt(s); }

The include file "sphere.h" contains

double sphere(int n, double x[]);

When the program runs, it outputs on my machine

[toto@localhost swig]$ python cswig.py Creating swig interface file with contents: %module mymodule %{

include "sphere.h"

%}

%include "carrays.i" %array_class(double, doubleArray) %array_class(int, intArray) %include sphere.h

Processing interface file: swig -python mymodule.i Compiling wrapper and source files to object files. gcc -Wall -fpic -c sphere.c

Creating module file. gcc -Wall -O3 -lm -shared mymodule_wrap.o sphere.o -o _mymodule.so 2.2360679775 [toto@localhost swig]$

The recipe is designed to handle simple cases of swigging. Modify the recipe for more complex requirements.

2 comments

Keith Briggs 17 years, 11 months ago  # | flag

Example broken. The example is corrupted. What is in sphere.h?

Ernesto Adorio (author) 17 years, 11 months ago  # | flag

Fixed the recipe's example discussion.