CSC/ECE 517 Fall 2013/ch1 1w04 y

From Expertiza_Wiki
Jump to navigation Jump to search

Use SWIG to improve the performance of Ruby code


Introduction

What is SWIG

SWIG (Simplified Wrapper and Interface Generator) is a actually a compiler and a tool that allows programmers to mix C/C++ programs and libraries with several dynamic or high level languages, including Tcl, Perl, Python, Ruby,and PHP. It has been developed since 1995. In 1996, the first alpha released and the latest version is 2.0.10, which means it is still maintained/in progress and used widely.

As a great tool, SWIG can be used in many ways, like:

Building more powerful C/C++ programs, system integration, etc. More details about that can be found here

Why we use SWIG

We all know that computer programming languages can be compiled or interpreted to execute instructions, and these languages can be divided into two basic groups: dynamic and static language.

As far as Ruby is concerned, it is a kind of dynamic language, which is high-level and useful for nearly everything as well as more flexible. On the other hand, Ruby also has many disadvantages as a script language. While using C/C++ code can do a support in many tasks to improve the memory usage and execution speed, we can not help thinking of combine these two kinds of languages and make the best use of them. That’s SWIG’s function, “cooperating” with C/C++ header files and using them to generate the wrapper code that script languages like Ruby need to access the underlying C/C++ code. What is more, SWIG provides many kinds of customization features and individual preferences that let you cut the wrapping process to suit your application. It is designed to work with existing C/C++ code, and turn common C/C++ libraries into components for use in popular script languages. In this way, we can manage to run the program in a more efficient and practical way.

The primary purpose,or goal, of using SWIG is to simplify the task of integrating C/C++ code with other programing languages, allowing people to focus on the underlying C program and using the high-level language interface, but not the tedious and complex task of making the two languages talk to each other.

Besides, we can easily write test scripts to our code.

With the help and advantages of SWIG, we can make the program more robust and efficient, as well as convenient for users and programmers.

Installation

Installation can be found here, and you may need the software of SWIG and the PCRE on your own computer to complete your installation.

A SWIG example

We will take a look at how we can use SWIG with respect to Ruby by using an example to illustrate. We will begin from creating a .c file.

The C code

Here we create a C code file named example.c :

/* File : example.c */
/* Compute the least common multiple of positive integers */
int lcm(int x, int y) {
 int g;
 g = y;
 while (x > 0) {
   g = x;
   x = y % x;
   y = g;
 }
 return x * y / g;
}

The SWIG interface

Then we create the SWIG interface file example.i:

/* File : example.i */
%module example
%inline %{
extern int lcm(int x, int y);
%}

Running SWIG

Next we should start the SWIG we have, using the following command(Typically on the Unix System):

$ swig -ruby example.i

if you build a C++ extension, the command should be:

$ swig -c++ -ruby example.i

In this way, SWIG create a file example_wrap.c (in C++ it should be example_wrap.cpp) that should be combined with to build a Ruby extension file. Just link this file with the rest of the program to finish your compiling.

Acquire the right header files

To compile the example_wrap.c on your machine, you need to get the right Ruby header file ruby.h for use. If you do not know the location of your header file and take account into the situation that different machines have different locations of ruby programs and files, you can input the following command:

$  ruby -e 'puts $:.join("\n")'
/usr/local/rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby/1.9.1
/usr/local/rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby/1.9.1/x86_64-darwin12.5.0
/usr/local/rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby
/usr/local/rvm/rubies/ruby-1.9.3-p448/lib/ruby/vendor_ruby/1.9.1
/usr/local/rvm/rubies/ruby-1.9.3-p448/lib/ruby/vendor_ruby/1.9.1/x86_64-darwin12.5.0
/usr/local/rvm/rubies/ruby-1.9.3-p448/lib/ruby/vendor_ruby
/usr/local/rvm/rubies/ruby-1.9.3-p448/lib/ruby/1.9.1
/usr/local/rvm/rubies/ruby-1.9.3-p448/lib/ruby/1.9.1/x86_64-darwin12.5.0

It is easy to run Ruby to find out the correct information.

Compile your own dynamic module with SWIG

You can do this by taking following steps/commands:

1 Create a file called “extconf.rb”

 require 'mkmf'
 create_makefile('example')

2 Build the extension:

 $ ruby extconf.rb
 $ make
 $ make install

There may be some errors during this process and if you want to add your own make rules to the extconf.rb, you can go through by doing this at the end of the file:

 open("Makefile", "a") { |mf|
   puts <<EOM
   # Your make rules go here
   EOM
 }

We have almost done the process, and usually a typical series of commands that used in Linux platform looks like this:

 $ swig -ruby example.i
 $ gcc -c example.c
 $ gcc -c example_wrap.c -I/usr/local/lib/ruby/1.6/i686-linux
 $ gcc -shared example.o example_wrap.o -o example.so

For other platforms, you may need to add -fPIC to generate position independent code. In Mac OS x system, click here for more details.

Run your program

Since we have example.so, the shared object file here, we can next use ruby to access the function and variables declared in the SWIG interface file (You can also use the command line to generate .bundle file to work as the library file of Ruby.).

unix > irb
unix > require ‘example’
unix > true
unix > Example.lcm(10,45)
unix > 90

In our example, our Ruby module has been compiled into a shared library that can be loaded into Ruby.

Also, SWIG Tutorial gives us more examples using other languages, like python,Tcl.

Using your own module

Given the situation that the Ruby module names begin with capitalized letters, but the feature names are usually lowercase, you should always use a lowercase module name with %module directive in SWIG. If you do this following, a SWIG file beginning with this:

 %module example

will result in a extension file with the Ruby module name ”Example” and a feature name “example”.

Static linking

The usual way of adding a new module to Ruby involves the following ways: finding the Ruby source, adding an entry to the ext/Setup file, adding your directory to the list of extensions in the file, and finally rebuilding Ruby. Avoid using static linking unless you have no other choice, since the dynamic loading support situation has improved greatly and you can easily and efficiently work out certain problems.

SWIG disadvantages

Up to now we have introduced why and how we can use SWIG to improve our program, but there are still some problems of using SWIG that should be kept an eye on. Such disadvantages of using SWIG include:

1. Extra creation of format specific header files or hand-written wrapper codes that may confuse of interfere us with code/program.

2. Addition of inefficient shadow class layer which means that the number of internal function calls increases quickly.

3. Use of expression-based approximation without true semantic information for wrapper code.

Such problems or disadvantages remind us of being cautious when using SWIG.

Conclusion

SWIG is a great tool in a lot of sceneries. It can be used to provide a scripting interface to C/C++ code, making it easier for users and add extensions to your Ruby code or replacing existing modules with high-performance alternatives. In practice, SWIG precompiles the C/C++ code into a .so shared object file, thereby increasing speed. As a tool, SWIG is most commonly used to create high-level interpreted or compiled programming environments, user interfaces, and as a tool for testing and prototyping C/C++ software. It is typically used to parse C/C++ interfaces and generate the 'glue code' required for the above target languages to call into the C/C++ code. With the help of SWIG, we can simply let Ruby(as well as other script language) to call the function of C/C++ code. In this way, we can combine the advantages of both languages, and run our programs more efficiently and safely.

Some unpleasant but minor problems still exist, but no one would doubt that SWIG is a great tool for us to use as to improve our code.

Further reading

There are also gem files which can call Ruby code within C++ code and vice versa, such as Cplus2Ruby. For more details and more help as well as tutorials, just go through here.

For Windows 95/NT, we can also create Ruby extensions and make them work for us. Take a look at here

Mixing dynamic and static languages is under discussion and research by many people, and it is really a lively topic. You can find more background information and development details regarding mixed-language combination here

References

[1] The introduction to SWIG http://en.wikipedia.org/wiki/SWIG

[2] SWIG Tutorial http://www.swig.org/tutorial.html

[3] What is Ruby and its feature http://en.wikipedia.org/wiki/Ruby_(programming_language)

[4] SWIG Ruby examples http://www.goto.info.waseda.ac.jp/~fukusima/ruby/swig-examples/index.html

[5] https://github.com/swig/swig

[6] http://www.swig.org

[7] Ruby C extensions PDF http://java.ociweb.com/mark/NFJS/RubyCExtensions.pdf