|
|
|
|
SWIG generates wrapper code from C/C++ header files that allows C/C++ functions to be invoked from other languages. This includes
Why would you want to do such a thing? The most common reasons are
Using SWIG reduces the amount of manual coding required to invoke C/C++ functions from other programming languages. In the case Java, JNI can be used directly, but this requires a large amount of tedious coding. Another benefit of using SWIG is that it is less error prone than manual coding. Correct use of JNI is complicated, especially for passing non-primitive types.
SWIG can be downloaded from http://www.swig.org.
In some Linux distributions, SWIG is installed by default,
making these setup steps unnecessary.
If running "which swig" fails to find it,
the following steps will build it.
./configure
make
su root
make install
The Windows version of SWIG comes with a pre-built executable,
so no installation is necessary. After unzipping,
see Doc/Manual/Windows.html for more information.
Let's walk through an example of calling C++ from Java.
#ifndef PERSON_H
#define PERSON_H
// This example uses the Boost date_time library to
// store dates and perform calculations using them.
#include "boost/date_time/gregorian/gregorian.hpp"
#include <string>
class Person {
public:
Person(const std::string& name);
// Call this before calling getAge,
// getBirthday or isOlderThan.
void setBirthday(const std::string& birthday);
int getAge() const;
boost::gregorian::date getBirthday() const;
std::string getName() const;
bool isOlderThan(const Person& person) const;
private:
boost::gregorian::date birthday_;
std::string name_;
};
#endif
#include "Person.h"
using namespace boost::gregorian;
using namespace std;
Person::Person(const string& name) : name_(name) {
}
int Person::getAge() const {
date today(day_clock::local_day());
int days1 = today.day_of_year();
int days2 = birthday_.day_of_year();
int years = today.year() - birthday_.year();
if (days1 < days2) --years;
return years;
}
date Person::getBirthday() const { return birthday_; }
string Person::getName() const { return name_; }
bool Person::isOlderThan(const Person& person) const {
return birthday_ < person.birthday_;
}
void Person::setBirthday(const string& birthday) {
birthday_ = from_string(birthday);
}
%module RubyPerson
%{
#include "Person.h"
%}
%include "std_string.i"
%include "Person.h"
Notes about the above file:
Here's a Unix/Linux script that runs SWIG to generate Java wrapper code that uses JNI.
package=com.ociweb.dates # Create output directory. packageWithSlashes=`echo $package | sed -e 's/\./\//g'` outdir=gen/$packageWithSlashes mkdir --parents $outdir # Generate Java and C++ wrapper files. # This processes Person.i. swig -c++ -java -package $package -outdir $outdir *.i # Compile wrapper code. # JID stands for Java Include Directory. jid=/usr/include/mozilla-1.7.8 gcc -c -fpic *.cpp *_wrap.cxx \ -I. -I$jid -I$jid/nspr -I/usr/local/include/boost_1_33_0 # Link wrapper code. gcc -shared -fpic Person.o *_wrap.o -lstdc++ -o libPerson.so
import com.ociweb.dates.Person;
public class Main {
static {
// Load libPerson.so.
System.loadLibrary("Person");
}
public static void main(String[] args) {
// Note that Person is a C++ class!
Person p1 = new Person("Mark Volkmann");
p1.setBirthday("1961/4/16");
System.out.println(
p1.getName() + " is " + p1.getAge() + " years old.");
Person p2 = new Person("Amanda Volkmann");
p2.setBirthday("1985/7/22");
System.out.println(
p2.getName() + " is " + p2.getAge() + " years old.");
System.out.println(
p1.getName() + " is older than " + p2.getName() +
"? " + p1.isOlderThan(p2));
}
}
# Compile generated Java files. javac gen/com/ociweb/dates/*.java # Compile our Java file. javac -classpath gen Main.java # Run the Java application. java -classpath .:gen -Djava.library.path=. Main
The output from this code is
Mark Volkmann is 44 years old. Amanda Volkmann is 20 years old. Mark Volkmann is older than Amanda Volkmann? true
One of the cool things about SWIG is that it supports many programming languages. Sure, you're reading the Java News Brief, but allow me to show an example for one other language, Ruby.
# Generate C++ wrapper files. # This processes Person.i. swig -c++ -ruby *.i # Compile wrapper code. rubydir=/usr/local/lib/ruby/1.8/i686-linux gcc -c -fpic *.cpp *_wrap.cxx \ -I. -I$rubydir -I/usr/local/include/boost_1_33_0 # Link wrapper code. gcc -shared -fpic Person.o *_wrap.o \ -lboost_date_time-gcc-1_33 -lstdc++ \ -o RubyPerson.so
require 'RubyPerson.so'
include RubyPerson # RubyPerson is a Ruby module generated by SWIG
p1 = Person.new('Mark Volkmann')
p1.setBirthday('1961/4/16')
puts "#{p1.getName()} is #{p1.getAge()} years old."
p2 = Person.new('Amanda Volkmann')
p2.setBirthday('1985/7/22')
puts "#{p2.getName()} is #{p2.getAge()} years old."
puts "#{p1.getName()} is older than #{p2.getName()}? " +
"#{p1.isOlderThan(p2)}"
ruby main.rb
The output is the same as for the Java application.
SWIG greatly simplifies calling C/C++ functions from many programming languages including Java and Ruby. For more information, visit http://www.swig.org. There you'll find a "Tutorial" link and a "Documentation" link that provides a users manual in both HTML and PDF form.
OCI is the leading provider of Object Oriented technology training in the Midwest. More than 3,000 students participated in our training program over the last 12 months. Targeted toward Software Engineers and the development community, our extensive program of over 50 hands-on workshops is delivered to corporations and individuals throughout the U.S. and internationally. OCI's Educational Services include Group Training events and Open Enrollment classes.
For further information regarding OCI's Educational Services programs, please visit our Educational Services section on the web or contact us at training@ociweb.com.
|
|
|