Introduction
SWIG is a great tool to generate wrappers very easily in various scripting languages of C/C++ libraries. But if you develop a C/C++ library and its wrapper at the same time, it has a significant flow: the necessity to create input files distinct from the source code of your library. The more extensive the library is, the biggest issue is to have to maintain virtually two sets of header files.
With PySwig, the source header files are annotated, allowing the automatic generation of the input files needed by Swig. With those input files, Swig can then create the sources of the wrapper. In this way, the maintenance effort is reduced to its minimum, since only one set of header files is needed.
Furthermore, PySwig can also take care of calling Swig to generate the wrapper. The result is a Python script, importing PySwig, and defining the operations to carry out. In the end, one just has to call this Python script to generate the Swig input files and call Swig to create the wrapper source files in one step.
Annotations
The basic principle is to add XML-like annotations in comments to various effects: to comment out a line, or a block of code; to include some lines in the input files used by Swig; to add automatically include files.
Add source include file
//<swig_inc/>
Automatically add the include file to the Swig input file. As an example of usage of this annotation, the result in the Swig input file would be:
//<swig_inc>
%{
#include "simple/object.h"
%}
//</swig_inc>
Commenting out a block of code
Often a block of code needs to be commented out. It can be done in this way.
//<swig_out>
int m_value = 0;
…
//</swig_out>
The result in the Swig input file is:
/* //<swig_out>
int m_value = 0;
…
//</swig_out> */
Add code specific to Swig
Often, it’s required to add code specific to Swig to handle templates, typemaps, director, etc. It can be done as follow:
/*<swig>
%apply std::string &OUTPUT …
//</swig>*/
It will result in the following line in a Swig input file:
//<swig>
%apply std::string &OUTPUT …
//</swig>
To add only one line, a simpler form is also possible:
//<swig/> %apply std::string &OUTPUT …
In the Swig input file, the line will look like the following:
%apply std::string &OUTPUT …
Build script
As mentioned earlier, PySwig can also be used to automate the creation of the wrapper by directly calling Swig. See the examples in the git repo:
pysimple.py (Python wrapper)
cssimple.py (C# wrapper)
There are two Python classes to be aware of:
FileConfig — configuration for a set of annotated source headers (input dir, output dir, source list, include base path). Call
set_script_path(__file__)so relative paths resolve correctly.PySwig — orchestrates parsing annotations, writing Swig
.hhinterface files, and optionally invoking Swig. UsePySwig(parse_cli=False)when configuring everything from a script.
Typical workflow:
Create one or more
FileConfiginstances and register them onPySwig.Set module name, output directories, typemaps, and includes.
Call
generate()to write Swig input files from annotated headers.Configure language options and call
run_swig()to produce wrapper sources.
The lower-level Swig class locates the Swig executable and runs it with
cwd= set to the output directory. ProcessSrcFile parses annotations
in a single header; you rarely instantiate it directly.
For command-line use, pyswig accepts optional header paths via
PySwig.set_input_files(); paths are resolved without changing the
process working directory.
Comment out one line
This annotation is to comment out one line of source code in the Swig input file. See the line below as an example one line in a header file of a library.
This same line will be transformed to the following line in the Swig input file: