Linux SWIG - A little nice glue tool

SWIG is a little nice glue tool that connects programs written in C and C++ with a variety of high-level programming languages like Javascript, Perl, PHP, Python, Tcl, Ruby, Java etc… It is similar to JNI in Java world.

Linux SWIG

It is available in most linux distribution. In ubuntu, it can be installed using “ sudo apt-get install swig”.

By looking the following example, you will see it is pretty straightford to make the service implemented in C, C++ available to TCL, Python, Java.

Assume you have services implemented in the following C file

See below services.c:

/* File services.c */
#include <time.h>
#include <math.h>

double temperature = 27.5; /* Celcius */

/* Find the current time and return as ASCII text */
char *get_time() {
    time_t localTime;

    time(&localTime);

    return ctime(&localTime);
}

double square_root( double a) {

    return sqrt(a);

}

Define the services interface in SWIG way: services.i

/* services.i */
%module services
%{
  /* Put header files here */
  extern double temperature;
  extern char *get_time();
  extern double square_root(double a);
%}

extern double temperature;
extern char *get_time();
extern double square_root(double a);

Now we have the following:

weng@weng-u1604:~/swig/python$ ls -l
total 8
-rw-rw-r-- 1 weng weng 308 Aug  6 16:57 services.c
-rw-rw-r-- 1 weng weng 256 Aug  6 16:57 services.i
weng@weng-u1604:~/swig/python$ 

1. Access the services from Python

First make sure you have python-dev package installed (sudo apt-get install python-dev)

1.1 Compiling the interface to generate the stub for python:

weng@weng-u1604:~/swig/python$ swig -python services.i
weng@weng-u1604:~/swig/python$ ls -l
total 128
-rw-rw-r-- 1 weng weng    308 Aug  6 16:57 services.c
-rw-rw-r-- 1 weng weng    256 Aug  6 16:57 services.i
-rw-rw-r-- 1 weng weng   2746 Aug  6 17:13 services.py
-rw-rw-r-- 1 weng weng 114799 Aug  6 17:13 services_wrap.c
weng@weng-u1604:~/swig/python$

After compilation of interface file, a file named “services_wrap.c” and “services.py” are generated.

1.2 Build into object files to create shareable library

weng@weng-u1604:~/swig/python$ gcc -fPIC -c services.c services_wrap.c -I/usr/include/python2.7
weng@weng-u1604:~/swig/python$ ld -shared services.o services_wrap.o -o _services.so
weng@weng-u1604:~/swig/python$ ls -l
total 232
-rw-rw-r-- 1 weng weng    308 Aug  6 16:57 services.c
-rw-rw-r-- 1 weng weng    256 Aug  6 16:57 services.i
-rw-rw-r-- 1 weng weng   1824 Aug  6 17:20 services.o
-rw-rw-r-- 1 weng weng   2746 Aug  6 17:13 services.py
-rwxrwxr-x 1 weng weng  48968 Aug  6 17:20 _services.so
-rw-rw-r-- 1 weng weng 114799 Aug  6 17:13 services_wrap.c
-rw-rw-r-- 1 weng weng  51544 Aug  6 17:20 services_wrap.o
weng@weng-u1604:~/swig/python$ 

Now “_services.so” is available to be used for Python. It is loaded by services.py file, and it is assumed to be in the same directory as services.py file for it to be loaded properly.

We can test it.

1.3 Testing

eng@weng-u1604:~/swig/python$ python
Python 2.7.12 (default, Jul  1 2016, 15:12:24) 
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import services
>>> services.get_time()
'Sat Aug  6 17:25:11 2016\n'
>>> services.square_root(4)
2.0
>>> services.square_root(100.1)
10.00499875062461
>>>

2. Access the services from TCL

First make sure you have python-dev package installed (sudo apt-get install tcl-dev)

2.1 Compiling the interface to generate the stub for TCL:

weng@weng-u1604:~/swig/tcl$ ls -l
total 8
-rw-rw-r-- 1 weng weng 308 Aug  6 17:34 services.c
-rw-rw-r-- 1 weng weng 256 Aug  6 17:34 services.i
weng@weng-u1604:~/swig/tcl$ swig -tcl services.i
weng@weng-u1604:~/swig/tcl$ ls -l
total 72
-rw-rw-r-- 1 weng weng   308 Aug  6 17:34 services.c
-rw-rw-r-- 1 weng weng   256 Aug  6 17:34 services.i
-rw-rw-r-- 1 weng weng 65520 Aug  6 17:35 services_wrap.c
weng@weng-u1604:~/swig/tcl$ 

2.2 Build into object files to create shareable library

weng@weng-u1604:~/swig/tcl$ gcc -fPIC -c services.c services_wrap.c -I/usr/include/tcl
weng@weng-u1604:~/swig/tcl$ ld -shared services.o services_wrap.o -o services.so

weng@weng-u1604:~/swig/tcl$ ls -l
total 144
-rw-rw-r-- 1 weng weng   308 Aug  6 17:34 services.c
-rw-rw-r-- 1 weng weng   256 Aug  6 17:34 services.i
-rw-rw-r-- 1 weng weng  1824 Aug  6 17:39 services.o
-rwxrwxr-x 1 weng weng 30864 Aug  6 17:39 services.so
-rw-rw-r-- 1 weng weng 65520 Aug  6 17:35 services_wrap.c
-rw-rw-r-- 1 weng weng 34280 Aug  6 17:39 services_wrap.o
weng@weng-u1604:~/swig/tcl$ 

Now “services.so” is available to be used for TCL. We can test it.

2.3 Testing

weng@weng-u1604:~/swig/tcl$ tclsh
% load ./services.so services     
% puts $temperature
27.5
% get_time
Sat Aug  6 17:46:11 2016

% square_root 10.1
3.1780497164141406
% weng@weng-u1604:~/swig/tcl$ 

3. Access the services from Java

First make sure you have JDK package installed.

3.1 Compiling the interface to generate the stub for Java:

weng@weng-u1604:~/swig/java$ ls -l
total 8
-rw-rw-r-- 1 weng weng 308 Aug  6 17:50 services.c
-rw-rw-r-- 1 weng weng 256 Aug  6 17:50 services.i
weng@weng-u1604:~/swig/java$ swig -java services.i
weng@weng-u1604:~/swig/java$ l s-l
ls: cannot access s-l: No such file or directory
weng@weng-u1604:~/swig/java$ ls -l
total 24
-rw-rw-r-- 1 weng weng  308 Aug  6 17:50 services.c
-rw-rw-r-- 1 weng weng  256 Aug  6 17:50 services.i
-rw-rw-r-- 1 weng weng  752 Aug  6 17:50 services.java
-rw-rw-r-- 1 weng weng  633 Aug  6 17:50 servicesJNI.java
-rw-rw-r-- 1 weng weng 7697 Aug  6 17:50 services_wrap.c
weng@weng-u1604:~/swig/java$ 

3.2 Build into object files to create shareable library

weng@weng-u1604:~/swig/java$ gcc -fPIC -c services.c services_wrap.c -I /opt/jdk18/include/ -I /opt/jdk18/include/linux/
weng@weng-u1604:~/swig/java$ ls -l
total 32
-rw-rw-r-- 1 weng weng  308 Aug  6 17:50 services.c
-rw-rw-r-- 1 weng weng  256 Aug  6 17:50 services.i
-rw-rw-r-- 1 weng weng  752 Aug  6 17:50 services.java
-rw-rw-r-- 1 weng weng  633 Aug  6 17:50 servicesJNI.java
-rw-rw-r-- 1 weng weng 1824 Aug  6 17:52 services.o
-rw-rw-r-- 1 weng weng 7697 Aug  6 17:50 services_wrap.c
-rw-rw-r-- 1 weng weng 3464 Aug  6 17:52 services_wrap.o
weng@weng-u1604:~/swig/java$ gcc -shared services.o services_wrap.o -o services.so
weng@weng-u1604:~/swig/java$ ls -l
total 48
-rw-rw-r-- 1 weng weng   308 Aug  6 17:50 services.c
-rw-rw-r-- 1 weng weng   256 Aug  6 17:50 services.i
-rw-rw-r-- 1 weng weng   752 Aug  6 17:50 services.java
-rw-rw-r-- 1 weng weng   633 Aug  6 17:50 servicesJNI.java
-rw-rw-r-- 1 weng weng  1824 Aug  6 17:52 services.o
-rwxrwxr-x 1 weng weng 12896 Aug  6 17:52 services.so
-rw-rw-r-- 1 weng weng  7697 Aug  6 17:50 services_wrap.c
-rw-rw-r-- 1 weng weng  3464 Aug  6 17:52 services_wrap.o
weng@weng-u1604:~/swig/java$ pwd
/home/weng/swig/java
weng@weng-u1604:~/swig/java$

3.3. Testing

weng@weng-u1604:~/swig/java$ cat Main.java 
public class Main {
   public static void main(String argv[]) {
     String p= System.getProperty("java.library.path");
     System.out.println(p);
     System.load("/home/weng/swig/java/services.so");
     System.out.println(services.square_root(9));
     System.out.println(services.get_time());
   }
 }
weng@weng-u1604:~/swig/java$ javac Main.java 
weng@weng-u1604:~/swig/java$ java Main
:/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
3.0
Sat Aug  6 18:09:01 2016

weng@weng-u1604:~/swig/java$