The GNU Modula-2 front end to GCC

How to produce swig interface files

This section describes how your Modula-2 implementation modules can be called from Python (and other scripting languages such as TCL and Perl). GNU Modula-2 can be instructed to create a swig interface when it is compiling an implementation module. Swig then uses the interface file to generate all the necessary wrapping to that the desired scripting language may access your implementation module.

Here is an example of how you might call upon the services of the Modula-2 library module NumberIO from Python. This example can be found in the directory gm2/examples/swig/full-strlib and can be run using the commands:

$ cd gcc-4.7.3/gcc/gm2/examples/swig/full-strlib
$ make numberio

If you wanted to do this step by step without the Makefile then firstly you should compile the NumberIO module as a shared library. This can be achieved by using the following commands:

$ cd gcc-4.7.3/gcc/gm2/examples/swig/full-strlib
$ gm2 -fshared -I. -c -fPIC -g -fswig -I../../../gm2-libs \
    ../../../gm2-libs/NumberIO.mod

The example assumes that the source code for NumberIO.mod can be found in directory ../../../gm2-libs. The first command produces two files: NumberIO.i and NumberIO.o. The file NumberIO.o is a position independant code object file whereas the file NumberIO.i is a swig interface file and contains a swig interpretation of the NumberIO.def. GNU Modula-2 uses the same mechanism for handling exceptions as GNU C++. The file NumberIO.i contains exception handling information therefore we need to ask swig to generate C++ wrappers for NumberIO.mod. This is achieved by:

$ swig -c++ -python NumberIO.i
$ gcc -c -fPIC NumberIO_wrap.cxx -I/usr/include/python2.4

The swig command line generates the necessary Python and C++ interface files using the interface file. The C++ interface file is also compiled into position independant code. Finally the module NumberIO is linked with all its dependants and NumberIO_wrap.o.

$ gm2 -fonlylink -shared -fshared -fPIC -g \
     ../../../gm2-libs/NumberIO.mod NumberIO_wrap.o -o _NumberIO.so

Now it is possible to run the following Python script (called testnum.py):

import NumberIO

print "1234 x 2 =", NumberIO.NumberIO_StrToInt("1234")*2

like this:

$ python testnum.py
1234 x 2 = 2468

Limitations of automatic generated of Swig files

This section discusses the limitations of automatically generating swig files. From the previous example we see that the module NumberIO had a swig interface file NumberIO.i automatically generated by the compiler. If we consider three of the procedure definitions in NumberIO.def we can see the success and limitations of the automatic interface generation.

PROCEDURE StrToHex (a: ARRAY OF CHAR; VAR x: CARDINAL) ;
PROCEDURE StrToInt (a: ARRAY OF CHAR; VAR x: INTEGER) ;
PROCEDURE ReadInt (VAR x: CARDINAL) ;

Below are the swig interface prototypes:

extern void NumberIO_StrToHex (char *_m2_address_a,
                               int _m2_high_a, unsigned int *OUTPUT);
/*  parameters: x is known to be an OUTPUT */
extern void NumberIO_StrToInt (char *_m2_address_a,
                               int _m2_high_a, int *OUTPUT);
/*  parameters: x is guessed to be an OUTPUT */
extern void NumberIO_ReadInt (int *x);
/*  parameters: x is unknown */

In the case of StrToHex it can be seen that the compiler detects that the last parameter is an output. It explicitly tells swig this by using the parameter name OUTPUT and in the following comment it informs the user that it knows this to be an output parameter. In the second procedure StrToInt it marks the final parameter as an output, but it tells the user that this is only a guess. Finally in ReadInt it informs the user that it does not know whether the parameter, x, is an output, input or an inout parameter.

The compiler decides whether to mark a parameter as either: INPUT, OUTPUT or INOUT if it is read before written or visa versa in the first basic block. At this point it will write output that the parameter is known. If it is not read or written in the first basic block then subsequent basic blocks are searched and the result is commented as a guess. Finally if no read or write occurs then the parameter is commented as unknown. However, clearly it is possible to fool this mechanism. Nevertheless automatic generation of implementation module into swig interface files was thought sufficiently useful despite these limitations.

In conclusion it would be wise to check all parameters in any automatically generated swig interface file. Furthermore you can force the automatic mechanism to generate correct interface files by reading or writing to the VAR parameter in the first basic block of a procedure.