.. _swig: ============================================= Simplified Wrapper Interface Generator (SWIG) ============================================= The `SWIG Project`_ develops the ``swig`` software tool which simplifies the task interfacing different languages to C/C++ programs. SWIG is a compiler that takes C/C++ declarations and creates the wrappers needed to access those declarations from other languages including including Python, Perl, Tcl, Ruby, Guile, and Java. OpenMOC uses SWIG to wrap C/C++ source code to create a user interface for Python. This section serves as a brief introduction to SWIG with a focus on those features most applicable to OpenMOC. The following sections describe how to write SWIG interface files, the output generated by SWIG, the use of typemaps, and more. The online documentation for SWIG is extensive and the reader is recommended to the following tutorials for more in-depth information: * `SWIG Basics Tutorial`_ * `SWIG C++ Tutorial`_ .. _swig_example: --------------------- SAXPY in SWIG Example --------------------- This introduces SWIG through an example of "Single-Precision A :math:`\cdot` X Plus Y" ("saxpy" for for short). The example uses SWIG to wrap a C/C++ file to create a `C/C++ extension module`_ for Python. C/C++ Source Code ----------------- The following is the C++ header file for the SAXPY source code (:download:`download <../../img/saxpy.h>`). The function prototypes are defined and will be wrapped by SWIG as described in the next section. .. code-block:: c /* File saxpy.h */ #include #include /* Define function prototypes */ void set_array_length(int n); void initialize_data(); void free_data(); void print_data(); void saxpy(); The corresponding function implementations for the SAXPY example are given in the C++ source file :file:`saxpy.cpp` below (:download:`download <../../img/saxpy.cpp>`). .. code-block:: c /* File saxpy.cpp */ #include "saxpy.h" /* Define global variables */ int length; double a; double* x; double* y; void set_array_length(int n) { length = n; } void initialize_data() { /* Allocate memory for arrays */ x = (double*)malloc(length*sizeof(double)); y = (double*)malloc(length*sizeof(double)); /* Initialize data with random numbers in [0,1] */ a = float(rand()) / RAND_MAX; for (int i=0; i < length; i++) { x[i] = float(rand()) / RAND_MAX; y[i] = float(rand()) / RAND_MAX; } } void free_data() { free(x); free(y); } void print_data() { printf("a = %f\n", a); for (int i=0; i < length; i++) printf("x[%d] = %f\ty[%d] = %f\n", i, x[i], i, y[i]); } void saxpy() { for (int i=0; i < length; i++) y[i] = a * x[i] + y[i]; } .. _swig_input: SWIG Interface File ------------------- SWIG requires the use of **interface files** for input. A `SWIG interface file`_ is required for each `C/C++ extension module`_ generated for Python. The primary purpose for SWIG interface file(s) in OpenMOC is to expose the C/C++ source code to SWIG. This is done by including the header files which contain all of the function prototypes, class definitions, etc. for SWIG to wrap. In addition, the name of the module must be included at the top of the interface file. The following illustrates :file:`saxpy.i` interface file (:download:`download <../../img/saxpy.i>`) for the SAXPY example. .. code-block:: none %module saxpy %{ #include SWIG_FILE_WITH_INIT #include "saxpy.h" %} %include "saxpy.h" .. note:: The reader is encouraged to reference the online documentation for the many options which may be used in SWIG interface files. Wrapping the C/C++ Source Code ------------------------------ SWIG is provided as the ``swig`` executable and is called on the command line to wrap C/C++ source code given a SWIG interface file. The call to ``swig`` produces a SWIG wrap file, which is designated following the :option:`-o` argument. The language used for the input source files (*e.g.*, C/C++) as well as the language targeted for the bindings (*e.g.*, Python) must be specified as flags to the ``swig`` executable. The following is an example of how to issue a command from the shell to wrap the source code in the :file:`saxpy.i` SWIG interface file: .. code-block:: none $ swig -python -c++ -o saxpy_wrap.cpp saxpy.i One output from the ``swig`` command to wrap C/C++ source code is a new C/C++ source file which contains all of the wrapper code needed to build an extension module. For example, the interface file :file:`saxpy.i` will be transformed into an output :file:`saxpy_wrap.cpp` file. To build the final extension module, the SWIG output file is compiled and linked with the rest of the C/C++ program to create a shared library as discussed in the following sections. Another output from a ``swig`` command to wrap C/C++ source code is a new file in the scripting language targeted by SWIG. In the case of OpenMOC, the target scripting language is Python and hence a Python file containing the wrapped routines is created. For example, the interface file :file:`saxpy.i` will be transformed into an output :file:`saxpy.py` file. This is the file which is imported when a user imports the ``saxpy`` module into Python and which interfaces with the shared library created for the module. Creating the Extension Module ----------------------------- The next step is to compile both the the C/C++ source files as well as the wrap file generated by SWIG. The wrap file includes :file:`Python.h` which is included with the Python development package provided by most package managers (*i.e.*, ``python-dev`` for Ubuntu's ``apt-get`` package manager). The C/C++ source **MUST** be compiled with the :option:`-fpic` option to produce "position independent code" for the shared library. The following two commands may be used to compile the source ``saxpy.cpp`` and ``saxpy_wrap.cpp`` files for this example: .. code-block:: none $ gcc -c saxpy.cpp -o saxpy.o -fpic -std=c++0x $ gcc -I/usr/include/python2.7 -c saxpy_wrap.cpp -o saxpy_wrap.o -fpic -std=c++0x The final step is to link the object files into a shared library which will serve as the extension module. It is standard practice for C/C++ extension modules to begin with an underscore "_" prefix. The object files for the SAXPY example can be linked into the :file:`_saxpy.so` shared libary file as follows: .. code-block:: none $ g++ saxpy_wrap.o saxpy.o -o _saxpy.so -shared -Wl,-soname,_saxpy.so Using the Extension Module -------------------------- Finally, the shared library extension module can be imported into Python and used as follows: .. code-block:: none $ python Python 2.7.3 (default, Sep 26 2013, 16:35:25) [GCC 4.7.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import _saxpy as module >>> module.set_array_length(10) >>> module.initialize_data() >>> module.saxpy() >>> module.print_data() a = 0.840188 x[0] = 0.394383 y[0] = 1.114455 x[1] = 0.798440 y[1] = 1.582487 x[2] = 0.197551 y[2] = 0.501203 x[3] = 0.768230 y[3] = 0.923232 x[4] = 0.553970 y[4] = 0.942836 x[5] = 0.628871 y[5] = 0.893154 x[6] = 0.513401 y[6] = 1.383583 x[7] = 0.916195 y[7] = 1.405488 x[8] = 0.717297 y[8] = 0.744267 x[9] = 0.606969 y[9] = 0.526268 >>> module.free_data() .. _numpy_typemaps: -------------- NumPy Typemaps -------------- It is often useful to input/return NumPy data structures to/from C/C++ routines. The `NumPy C API`_ makes this functionality possibility through **array conversions**. In addition, it is possible to automatically *embed* the NumPy C API directly into the source code with the use of `NumPy typemaps`_. Typemaps are a mechanism to match **function signatures** through a list of of function arguments. When SWIG finds a function which matches the typemap, it will target and subsequently modify the function to include the NumPy C API in order to input/output NumPy data arrays. Two types of parameters must be specified in the C/C++ function(s) of interest in order to match a NumPy typemap: * **Array Pointer** - The data type and pointer to the array * **Array Dimensions** - An integer for each array dimension The :file:`numpy.i` interface file (:download:`download <../../img/numpy.i>`) defines the typemaps and is shipped with OpenMOC in the :file:`/OpenMOC/openmoc` directory. In order to utilize NumPy typemaps, the following should be appended to the SWIG interface file used for the C/C++ extension module of interest: .. code-block:: none %include "numpy.i" %init %{ import_array(); %} The following sections overview the basic steps to utilize NumPy typemaps to input NumPy data from Python into C/C++ routines, and return data from C/C++ routines as NumPy arrays. Input NumPy Data Arrays ----------------------- The :file:`numpy.i` interface file provides two particular typemaps for inputting a NumPy data array into a C/C++ routine. The :envvar:`IN_ARRAY*` defines an array which is passed into a routine but is not modified in-place by the C/C++ function and is not returned to the user. The :envvar:`INPLACE_ARRAY*` typemap defines arrays that are modified in-place. In each case, the :envvar:`*` represents the number of dimensions for the input array. For example, in order to input a 3D array to be modified in-place, one would use the :envvar:`INPLACE_ARRAY3` typemap. The array dimension(s) are included in each typemap through the use of the :envvar:`DIM*` parameter. The following is an example C/C++ in which which we wish to wrap some function ``sum_array(...)`` with SWIG and provide the capability to input a NumPy array as a function parameter. Note that the function prototype includes a first paramter for the pointer to the input double array and a second parameter for the length of the array (which together form the function signature). The function prototype is given below in the :file:`sum_array.h` file below file (:download:`download <../../img/sum_array.h>`): .. code-block:: c /* File sum_array.h */ /* Define function prototype to take in a NumPy array */ double sum_array(double* input_array, int length); One possible implementation of the ``sum_array(...)`` routine is given in the :file:`sum_array.cpp` file below (:download:`download <../../img/sum_array.cpp>`): .. code-block:: c /* File sum_array.cpp */ /* Define function implementation */ double sum_array(double* input_array, int length) { /* Initialize sum */ double sum = 0.; /* Compute sum of array elements */ for (int i=0; i < length; i++) sum += input_array[i]; return sum; } The following would be the required SWIG interface file :file:`sum_array.i` (:download:`download <../../img/sum_array.i>`) to wrap :file:`sum_array.h` into the ``_sum_array`` C/C++ extension module for Python. The second-to-last line defines the NumPy typemap - the first tuple is a pair of the typemap (array type and dimension) while the second is the function signature to match using that typemap. .. code-block:: none %module sum_array %{ #define SWIG_FILE_WITH_INIT #include "sum_array.h" %} /* Include the NumPy typemaps library */ %include "numpy.i" %init %{ import_array(); %} /* Typemap for the sum_list(double* input_array, int length) C/C++ routine */ %apply (double* IN_ARRAY1, int DIM1) {(double* input_array, int length)}; %include "sum_array.h" The source code can be wrapped and compiled in similar fashion to that shown before using the following commands from the console: .. code-block:: none $ swig -python -c++ -o sum_array_wrap.cpp sum_array.i $ gcc -c sum_array.cpp -o sum_array.o -fpic -std=c++0x $ gcc -I/usr/include/python2.7 -c sum_array_wrap.cpp -o sum_array.o -fpic -std=c++0x $ g++ sum_array_wrap.o sum_array.o -o _sum_array.so -shared -Wl,-soname,_sum_array.so Finally, the shared library extension module may be imported into Python and the routine used with a NumPy array as follows: .. code-block:: none $ python Python 2.7.3 (default, Sep 26 2013, 16:35:25) [GCC 4.7.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from numpy.random import rand >>> from _sum_array import * >>> input_array = rand(5) >>> sum = sum_array(input_array) >>> print 'The sum of the array is %d' % (sum) The sum of the array is 2 .. note:: More detailed information on :envvar:`IN_ARRAY` and :envvar:`INPLACE_ARRAY` typemaps is provided in the official `NumPy.i`_ documetation. Return NumPy Data Arrays ------------------------ The :file:`numpy.i` interface file (:download:`download <../../img/numpy.i>`) also provides two typemaps for returning a NumPy data array from a C/C++ routine. The :envvar:`ARGOUT_ARRAY*` used in situations where you would allocate an array on the heap and call the function to fill the array values. In Python, the arrays are allocated for you and returned as new array objects. As was the case for array input, the :envvar:`*` represents the number of dimensions for the input array. For example, in order to input a 3D array to be modified in-place, one would use the :envvar:`ARGOUT_ARRAY3` typemap. The array dimension(s) are included in each typemap through the use of the :envvar:`DIM*` parameter. The following is an example C/C++ in which which we wish to wrap some function ``get_rand_array(...)`` with SWIG and provide the capability to convert a C/C++ array into an output NumPy array. Based on the function signature, it would appear that the output array is input into the function and nothing is returned. Instead, SWIG will modify the source code with the NumPy C API such that a NumPy array is initialized and input as a C/C++ array and subsequently returned as a NumPy array. The function prototype is given below in the :file:`get_rand_array.h` file below (:download:`download <../../img/get_rand_array.h>`): .. code-block:: c /* File get_rand_array.h */ #include /* Define function prototype to take in a NumPy array */ void get_rand_array(double* output_array, int length); One possible implementation of the ``get_rand_array(...)`` routine is given in the :file:`get_rand_array.cpp` file below (:download:`download <../../img/get_rand_array.cpp>`): .. code-block:: c /* File get_rand_array.cpp */ #include "get_rand_array.h" /* Define function implementation */ void get_rand_array(double* output_array, int length) { /* Populate input NumPy array with random numbers */ for (int i=0; i < length; i++) output_array[i] = ((double) rand()) / RAND_MAX; return; } The following would be the required SWIG interface file :file:`get_rand_array.i` (:download:`download <../../img/get_rand_array.i>`) to wrap :file:`get_rand_array.h` into the ``_get_rand_array`` C/C++ extension module for Python. The second-to-last line defines the NumPy typemap - the first tuple is a pair of the typemap (array type and dimension) while the second is the function signature to match using that typemap. .. code-block:: none %module get_rand_array %{ #define SWIG_FILE_WITH_INIT #include "get_rand_array.h" %} /* Include the NumPy typemaps library */ %include "numpy.i" %init %{ import_array(); %} /* Typemap for the get_rand_array(double* output_array, int length) C/C++ routine */ %apply (double* ARGOUT_ARRAY1, int DIM1) {(double* output_array, int length)}; %include "get_rand_array.h" The source code can be wrapped and compiled in similar fashion to that shown before using the following commands from the console: .. code-block:: none $ swig -python -c++ -o get_rand_array_wrap.cpp get_rand_array.i $ gcc -c get_rand_array.cpp -o get_rand_array.o -fpic -std=c++0x $ gcc -I/usr/include/python2.7 -c get_rand_array_wrap.cpp -o get_rand_array.o -fpic -std=c++0x $ g++ get_rand_array_wrap.o get_rand_array.o -o _get_rand_array.so -shared -Wl,-soname,_get_rand_array.so Finally, the shared library extension module may be imported into Python and the routine used with a NumPy array as follows: .. code-block:: none $ python Python 2.7.3 (default, Sep 26 2013, 16:35:25) [GCC 4.7.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from _get_rand_array import * >>> output_array = get_rand_array(10) >>> print output_array [ 0.84018773 0.39438292 0.78309923 0.79844004 0.91164738 0.19755137 0.33522275 0.7682296 0.27777472 0.55396998] >>> type(output_array) .. note:: More detailed information on the :envvar:`ARGOUT_ARRAY` typemap is provided in the official `NumPy.i`_ documetation. ------------- SWIG Typemaps ------------- On some machines - such as some leadership class supercomputing clusters - NumPy may not be available. As a result it may be preferable to input/output data from Python using standard Python data structures (*e.g.*, lists, tuples). SWIG provides it's own library of typemaps for this purpose in the :file:`typemaps.i` file which is included in the standard SWIG installation. In order to utilize `SWIG typemaps`_, the following include should be appended to the SWIG interface file used for the C/C++ extension module of interest: .. code-block:: none %include "typemaps.i" The following sections overview the basic steps to utilize SWIG typemaps to input data from Python lists into C/C++ routines, and return data from C/C++ routines as Python lists. .. note:: The reader is encouraged to reference the online documentation for `SWIG typemaps`_ for more in-depth information and examples. Input Python Lists ------------------ This section introduces the SWIG typemaps for inputting Python lists into C/C++ routines with a simple example. The example uses SWIG to wrap a C/C++ file to create a routine which takes in a list of floating point data and prints it to the console. The following is the C++ header file :file:`sum_list.h` for the example code (:download:`download <../../img/sum_list.h>`). .. code-block:: c /* File sum_list.h */ #include /* Define function prototype */ double sum_list(double* input_list, int length); The corresponding function implementation for this example is given in the C++ source file :file:`sum_list.cpp` below (:download:`download <../../img/sum_list.cpp>`). .. code-block:: c /* File sum_list.cpp */ #include "sum_list.h" double sum_list(double* input_list, int length) { /* Initialize sum */ double sum = 0.; /* Compute sum of array elements */ for (int i=0; i < length; i++) sum += input_list[i]; return sum; } The following would be the required SWIG interface file :file:`sum_list.i` (:download:`download <../../img/sum_list.i>`) to wrap :file:`sum_list.h` into the ``_sum_list`` C/C++ extension module for Python. Writing an interface file using `SWIG typemaps`_ is more involved than it is for NumPy typemaps and requires some familiarity with the `Python/C API`_. .. code-block:: none %module sum_list %{ #define SWIG_FILE_WITH_INIT #include "sum_list.h" %} /* Include the SWIG typemaps library */ %include typemaps.i /* Typemap the sum_list(double* input_list, int length) C/C++ routine */ %typemap(in) (double* input_list, int length) { /* Check that the input is a Python list data structure */ if (!PyList_Check($input)) { PyErr_SetString(PyExc_ValueError,"Expected a Python list of values\n"); return NULL; } /* Set the second parameter to the length of the Python list input */ $2 = PySequence_Length($input); /* Allocate memory to convert the list into a C/C++ array */ $1 = (double*) malloc($2 * sizeof(double)); /* Loop over the values in the list */ for (int i = 0; i < $2; i++) { /* Extract the value from the list at this location */ PyObject *o = PySequence_GetItem($input,i); /* If the value is a number, cast it as an int and set the * input array value */ if (PyNumber_Check(o)) { $1[i] = (double) PyFloat_AsDouble(o); } else { free($1); PyErr_SetString(PyExc_ValueError,"Expected a list of numbers\n"); return NULL; } } } %include "sum_list.h" The source code can be wrapped and compiled in similar fashion to that shown before using the following commands from the console: .. code-block:: none $ swig -python -c++ -o sum_list_wrap.cpp sum_list.i $ gcc -c sum_list.cpp -o sum_list.o -fpic -std=c++0x $ gcc -I/usr/include/python2.7 -c sum_list_wrap.cpp -o sum_list_wrap.o -fpic -std=c++0x $ g++ sum_list_wrap.o sum_list.o -o _sum_list.so -shared -Wl,-soname,_sum_list.so Finally, the shared library extension module can be imported into Python and used as follows: .. code-block:: none $ python Python 2.7.3 (default, Sep 26 2013, 16:35:25) [GCC 4.7.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from _sum_list import * >>> input_list = [2.,4.,8.,16.,32.] >>> sum = sum_list(input_list) >>> print 'The sum of the array is %d' % (sum) The sum of the array is 62 Return Python Lists ------------------- The :file:`std_vector.i` interface file provides `SWIG templates`_ for returning a Python tuple from a function returning a `C++ STL`_ ``std::vector`` data structure. The following is an example C/C++ in which we wish to wrap some function ``get_rand_list(...)`` with SWIG and provide the capability to convert a C++ ``std::vector`` into an output Python list. SWIG will modify the source code with the `Python/C API`_ such that a Python tuple is returned with the data, which will then be converted to a Python list. The function prototype is given below in the :file:`get_rand_list.h` file below (:download:`download <../../img/get_rand_list.h>`): .. code-block:: c /* File sum_list.h */ #include #include /* Define function prototype */ std::vector get_rand_list(int length); One possible implementation of the ``get_rand_list(...)`` routine is given in the :file:`get_rand_list.cpp` file below (:download:`download <../../img/get_rand_list.cpp>`): .. code-block:: c /* File get_rand_list.cpp */ #include "get_rand_list.h" /* Define function implementation */ std::vector get_rand_list(int length) { /* Allocate memory for the C++ STL vector */ std::vector output_list(length); /* Populate vector with random numbers */ for (int i=0; i < length; i++) output_list[i] = ((double) rand()) / RAND_MAX; return output_list; } The following would be the required SWIG interface file :file:`get_rand_list.i` (:download:`download <../../img/get_rand_list.i>`) to wrap :file:`get_rand_list.h` into the ``_get_rand_list`` C/C++ extension module for Python. The interface file includes the :file:`std_vector.i` file and defines a SWIG template to match C++ STL vectors. .. code-block:: none %module get_rand_list %{ #define SWIG_FILE_WITH_INIT #include "get_rand_list.h" %} %include "std_vector.i" /* SWIG template for get_rand_list(int length) C++ routine */ namespace std { %template(DoubleVector) vector; } %include "get_rand_list.h" The source code can be wrapped and compiled in similar fashion to that shown before using the following commands from the console: .. code-block:: none $ swig -python -c++ -o get_rand_list_wrap.cpp get_rand_list.i $ gcc -c get_rand_list.cpp -o get_rand_list.o -fpic -std=c++0x $ gcc -I/usr/include/python2.7 -c get_rand_list_wrap.cpp -o get_rand_list_wrap.o -fpic -std=c++0x $ g++ get_rand_list_wrap.o get_rand_list.o -o _get_rand_list.so -shared -Wl,-soname,_get_rand_list.so Finally, the shared library extension module can be imported into Python and used as follows: .. code-block:: none $ python Python 2.7.3 (default, Sep 26 2013, 16:35:25) [GCC 4.7.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from _get_rand_list import * >>> output_list = list(get_rand_list(10)) >>> print output_list [0.8401877171547095, 0.39438292681909304, 0.7830992237586059, 0.7984400334760733, 0.9116473579367843, 0.19755136929338396, 0.335222755714889, 0.768229594811904, 0.2777747108031878, 0.5539699557954305] >>> type(output_list) ------------------ Default Parameters ------------------ It is highly recommended that developers make use of `default parameters`_ for routines when possible. Default arguments in a C++ routine are wrapped by ``swig`` given the :option:`-keyword` command line option to provide `keyword arguments`_ (also known as named parameters) in the Python binding for that routine. There are several benefits for defining default arguments in the C/C++ source code: * **Readability** - Keyword arguments make code more readable, especially in example input files for users new to OpenMOC * **Ordering** - Keyword arguments can be provided in any order, lessening the burden to the user to remember a specific ordering * **Flexibility** - Function parameters with useful default values are not required at runtime, making Python scripts easier to comprehend An example of function parameters with default values and the use of keyword arguments to override the default values in Python is given below: .. code-block:: python # Define a function with two arguments with default values def multiverseHelloWorld(count=5, greeting='Hello'): for i in range(count): print '%s from World %d!' % (greeting, i) # Call routine and override default keyword arguments # The keyword arguments can be provided in any order multiverseHelloWorld(greeting='Hola', count=7) Likewise, an example of how to define default values for function parameters - which will be provided through the Python interface as `SWIG default arguments`_ - in C/C++ is given below: .. code-block:: c /* Define a function prototype with two arguments with default values */ void multiverseHelloWorld(int count=5, char* greeting="Hello"); /* Function implementation doesn't include default values in C++ */ void multiverseHelloWorld(int count, char* greeting) { for (int i=0; i < count; i++) printf("%s from World %d!", greeting, i) } ------ Macros ------ SWIG provides preprocessing_ capabilities for interface files. `Macro expansions`_ may be defined in the interface file using the traditional syntax for C/C++: .. code-block:: c #ifndef PI #define PI 3.14159 #endif SWIG also includes special `SWIG macros`_ with more enhanced capabilities for interface files. -------- Typedefs -------- SWIG provides functionality to define typedefs_ in interface files. `SWIG typedefs`_ can be defined using the same syntax as in C/C++. As discussed in the SWIG online documentation, the typedef must be defined twice in the interface file for in order for it to be propagated to the generated wrapper file: .. code-block:: c %{ /* Include in the generated wrapper file */ typedef unsigned int size_t; %} /* Tell SWIG about it */ typedef unsigned int size_t; .. _SWIG Project: http://www.swig.org/ .. _NumPy typemaps: http://docs.scipy.org/doc/numpy/reference/swig.interface-file.html .. _Numpy.i: http://docs.scipy.org/doc/numpy/reference/swig.interface-file.html .. _NumPy C API: http://docs.scipy.org/doc/numpy/reference/c-api.html .. _SWIG typemaps: http://www.swig.org/Doc1.3/Typemaps.html .. _SWIG Basics Tutorial: http://www.swig.org/Doc1.3/SWIG.html .. _SWIG C++ Tutorial: http://www.swig.org/Doc1.3/SWIGPlus.html .. _SWIG default arguments: http://www.swig.org/Doc1.3/SWIGPlus.html#SWIGPlus_default_args .. _default parameters: http://www.learncpp.com/cpp-tutorial/77-default-parameters/ .. _keyword arguments: http://en.wikipedia.org/wiki/Named_parameter .. _preprocessing: http://en.wikipedia.org/wiki/C_preprocessor .. _Macro expansions: http://www.swig.org/Doc1.3/Preprocessor.html#Preprocessor_nn5 .. _SWIG macros: http://www.swig.org/Doc1.3/Preprocessor.html#Preprocessor_nn6 .. _typedefs: http://en.wikipedia.org/wiki/Typedef .. _SWIG typedefs: http://www.swig.org/Doc1.3/SWIG.html#SWIG_nn20 .. _SWIG interface file: http://www.swig.org/Doc2.0/SWIGDocumentation.html#SWIG_nn47 .. _C/C++ extension module: http://docs.python.org/2/extending/extending.html .. _SWIG exception handling: http://www.swig.org/Doc1.1/HTML/Exceptions.html .. _Python/C API: http://docs.python.org/2/c-api/ .. _SWIG STL vector typemap: http://www.swig.org/Doc2.0/SWIGDocumentation.html#Library_std_vector .. _C++ STL: http://en.wikipedia.org/wiki/Standard_Template_Library .. _SWIG templates: http://www.swig.org/Doc1.3/SWIGPlus.html#SWIGPlus_nn30