Friday, March 26, 2010

Installing Python 2.6 in Windows 7




Make sure to use the 32-bit version. Currently, while 64-bit version of Python 2.6 (2.6.5) is available, NumPy, SciPy, and possibly other modules (e.g. PyGame) won't install with 64-bit Python since apparently there are only 32-bit versions of them at the moment. Although 64-bit Python 2.6.5 can be successfully installed under Windows 7 (mine's 64-bit), installing 32-bit modules (using the .exe installer) will give "Python 2.6 is not found in the registry".

There is a 64-bit version of NumPy, but it seems to be experimental, and after Google-ing it, there seem to be many reports of 64-bit NumPy not working.

Suggestion:
- Install 32-bit Python (note: in PyGame's website, they say Python 2.5 is currently "the best" for Windows - reasons still unknown).
- Then install all the necessary modules. Currently installed:
- Python 2.6.5 [ Link ] (python.org)
- NumPy 1.4.0 [ Link ] (Sourceforge)
- SciPy 0.7.1 [ Link ] (Sourceforge)
- matplotlib 0.99.1 [ Download ] (matplotlib)
- pyGame 1.9.1 [ Link ] (pygame.org)
- pySerial 2.5 [ Link ]

Tuesday, February 9, 2010

Ubuntu 9.10 - boot always load to Grub prompt

See Ubuntu Forum's thread: here

See a possible solution: here

Other problems:
- the kernel linux-headers-2.6.31-19-generic doesn't work/cannot boot - currently using 2.6.31-17-generic

Wednesday, February 3, 2010

Ubuntu 9.10 cannot update

I had trouble updating my Ubuntu 9.10 (Karmic Koala) using the Update Manager. Everytime I run update, the Update Manager freezes on 'Downloading Files...'. I can Force Quit it, but the next time I tried to run the Update Manager again, it says 'Another Synaptic application is already running' and won't let me launch the Update Manager. When I shutdown or restart, a message appears saying "AT SPI Registry Wrapper is not responding" - everytime.

So I googled the problem, and found several links:
- A bug report for the unable-to-update issue: https://answers.launchpad.net/ubuntu/+question/6719
Here, I used Manu Arya's suggestion to comment out /etc/network/interfaces:
> in Terminal, type: sudo gedit /etc/network/interfaces
> comment the following entries, from:
auto lo
iface lo inet loopback
to:
#auto lo
#iface lo inet loopback
- The issue with 'AT SPI Registry Wrapper not responding': https://bugs.launchpad.net/ubuntu/+source/at-spi/+bug/477978
From this, I disabled the AT (Assistive Technologies):
> From the toolbar: System > Preferences > Assistive Technologies
> uncheck the "Enable assistive technologies" checkbox
- Restart/reboot

Now I was able to run the update.

Note:
1. Before I run the update, I did:
> $ sudo apt-get update
to check for new updates (it doesn't install the updates, just updates the update list)
2. Since I did both changes (commenting the /etc/network/interfaces, and disabling Assistive Technologies) before retrying the update, I cannot tell which change solved the problem - whether it's one of them or both.
3. Note that any features you're using that requires Assistive Technologies will be disabled. So I don't know if or why AT is a problem (i.e. why the AT SPI registry wrapper always said to be not responding).

Monday, December 14, 2009

Ubuntu 9.10 Installation

Installed Ubuntu 9.10 on Lenovo x200 Tablet with Windows 7.
Apparently Wubi automatically installed the 64-bit version on this pc.

Description:
1. Installation: using Wubi.exe
2. Install type: Install under Windows

Process:
1. after selecting drive size, username & password, the installer automatically does everything
2. reboot after prompted
3. in the boot menu, choose Ubuntu
4. Goes into installation process for a couple minutes
5. reboot
6. in the boot menu, choose Ubuntu
7. will take you to the Grub menu. Here's the problem...

Issue:
- Cannot boot Ubuntu. After selecting 'Ubuntu' in the Boot menu, it will take you to Grub prompt "Grub 1.97 beta4" (which is actually Grub 2), and prompt: sh:grub>

Solution:
do the following:
sh:grub> set root=(loop0)
sh:grub> linux /boot/vmlinuz...-generic root=/dev/sda2 loop=/ubuntu/disks/root.disk ro
sh:grub> initrd /boot/initrd...
sh:grub> boot

So far it solved my issue. The PC now has dual boot Windows 7 and Ubuntu 9.10, and does not have to do the grub commands each time loading Ubuntu.

I found the solution in the Ubuntu forum, unfortunately cannot find the exact post again: [link]

Saturday, April 5, 2008

The Idiot's Way of Wrapping C/C++ OpenCV code for Java using SWIG

For the longest time I tried many times to wrap the C/C++ code that I have for face detection and recognition using OpenCV for Java using SWIG with no success. Being the idiot that I am, I finally learned why I couldn't do it after my friend, Martin Lukac, who has been working with the same issue for a while before me, explained that you can't wrap a C/C++ code which has some custom functions and data types/objects (i.e. from OpenCV) just like that. SWIG was only made to work with primitive data types of C/C++ (or other languages like Perl or Python) - which is obvious: you shouldn't expect the guys who made SWIG covers all the custom libraries out there, there are thousands and thousands of them! The only way that I would be able to wrap a C/C++ code which contains OpenCV data types and functions is that I would have to define those OpenCV data types/objects and functions for SWIG (i.e. in the interface file) myself. That would take me weeks even months to figure out! Fortunately, there is an easier way...

My solution: Create a proxy class.

That is, create a C++ class, which accesses the C/C++ functions in the main code which uses the OpenCV data types/objects and/or functions. So it looks like this: C++ class --> main C/C++ code --> OpenCV data types/objects and/or functions. Only the class will be wrapped, so SWIG does not have to deal with the OpenCV data types/objects and functions.

So in the class, I include the main C/C++ code using: #include "...", and for the class' methods, just access the main C/C++ code's functions statically (i.e. directly call the functions). For example:

My main C/C++ code:

/*
* File name: main_capture.cpp
* This program will do a live feed from a webcam and display it, until the ESC key is pressed
*/

#include "cv.h"
#include "highgui.h"

int initate_capture() {

IplImage* frame; // OpenCV data type for images
CvCapture* capture; // OpenCV object for camera capture

// Initialize capture from camera
capture = cvCreateCameraCapture( -1 ); // "-1" -> capture from any detected camera

// If there is no camera connected/detected...
if ( !capture ) {
fprintf( stderr, "ERROR, capture is NULL\n "); // ... show error ...
cvWaitKey(0); // ... wait for any key to be pressed ...
return -1; // ... and quit the program.
}

// If capture is successful, create a window named "Capture" to display the captured image
cvNamedWindow( "Capture", CV_WINDOW_AUTOSIZE );

// Create loop...
while (1) {

frame = cvQueryFrame( capture ); // Capture from camera...
cvShowImage( "Captue", frame ); // Show captured image in the window "Capture"

if ( (cvWaitKey(10) & 255 ) == 27 ) break; // Exit loop when ESC is pressed
}

// Clear some used memory before quitting the program
cvReleaseCapture( &capture );
cvDestroyWindow( "Capture" );
return 0;
}

// End of main_capture.cpp


My C++ proxy class:

/*
* File name: main_capture_class.cc
*/

#ifndef main_capture_class
#define main_capture_class

#include "main_capture.cpp" // Include the main C/C++ program

using std namespace;

class Capture {

// Declare the class methods
public:
void do_capture(); // This one is public

};

void Capture::do_capture() {
initiate_capture(); // Calls the function "initiate_capture()" in main_capture.cpp
}

#endif

// End of main_capture_class.cc


If you want to test if the class works, add this at the end of the class code (before the #endif):

int main() {
Capture c; // Instantiate the class Capture
c.do_capture(); // Call the "do_capture()" method of class Capture
}


Notice a couple of things here:
  1. I don't have a "main()" function in the main program. I don't need to, since the program will be run by some other program, unless I want to test the main program by itself, then I would need the "main()" function. However, I have to have a function that I can easily call from the class (depends on what you define as "easily" - my definition is where I don't have to worry about passing around variables and return types. Eventually, we will need/want to have something returned from the main program, e.g. name, or some other values).
  2. There are no OpenCV stuffs in the class - LEAVE THOSE IN THE MAIN PROGRAM!
  3. I try to keep the functions as simple as possible, i.e. not a lot of variable passing - this will make the functions easier to call from Java. Notice that the class' code has no variable passing, all the return types are void, and is very short (and sweet),
  4. The class' extension is .cc, for some reason SWIG doesn't like it when the extension is .cpp for C++

The next step is to create all the interface file (.i) for the class for SWIG, but first (as it is called in the SWIG tutorial website), I like to use a header file (.h) of the class, and include it in the interface file. So the header file for the class:

// File name: main_capture_class.h

class Capture {
public:
void do_capture();
}

// End of main_capture_class.h


Now the interface file:

// File name: main_capture_class.i
%module capture

%{
#include "main_capture_class.h"
%}

// List of all the methods of the class
%Capture::do_capture();

%include "main_capture_class.h"

// End of main_capture_class.i


So to recap, you need four files:
  1. The main C/C++ code where you use the OpenCV data types/objects and/or functions (main_capture.cpp)
  2. The proxy class that calls the functions in main_capture.cpp (main_capture_class.cc)
  3. The header file for the class (main_capture_class.h)
  4. The interface file for the class (main_capture_class.i)

So now start wrapping up! Using the interface file ... etc. etc. After the whole thing is done, you should have several files such as:
- Capture.java --> this is your usable Java class
- captureJNI.java
- captureJNI.class
- main_capture_class.o
- main_capture_class_wrap.cxx
- main_capture_class_wrap.o
- libcapture.so


Note that 'libcapture.so' is the shared object (hence, the '.so' extension) library, and the name 'libcapture' depends on what you define as the output name when you finally create the shared object after all the compilation steps are done.

If you want to test it, make a test Java file, for example:

// File name: CaptureTest.java

public class CaptureTest {

// CaptureTest constructor
CaptureTest() {
System.out.println("Running CaptureTest...\n");
System.loadLibrary("capture"); // Load the library, i.e. shared object "libcapture.so"
// Notice that the "lib-" and the ".so" extension are omitted
}

// CaptureTest method: doCapture()
public void doCapture() {
Capture c = new Capture(); // Instantiate the Capture object (class)
c.do_capture(); // Call the Capture method "do_capture()"
}

// Main routine
public static void main( String [] args ) {
CaptureTest ct = new CaptureTest(); // Instantiate the CaptureTest class
ct.doCapture(); // Start capturing...
}
}

// End of CaptureTest.java


Now I'm not claiming that this is THE way to do it, or the most elegant way, but it's certainly a sure-fire one. Give it a shot!

For more information, consult:
http://www.swig.org/tutorial.html --> for basic SWIG wrapping tutorial (for other languages as well)
http://www.swig.org/Doc1.3/Java.html --> for details on SWIG wrapping C++ for Java

Monday, December 3, 2007

Ubuntu 6.10 + RebeccaAIML 0.9871 Installation Notes

Here's my experience in installing RebeccaAIML on my Ubuntu 6.10 machine. This notes are being used for my report for my class project.

RebeccaAIML installation notes:

1. For Linux, use the version 0.9871 (Edmonson)

* Why this version?
In the RebeccaAIML website (http://rebecca-aiml.sourceforge.net) the latest version is 1.1tp3(Slatter), but this only works under Windows. So only use this latest version if you are working in Windows. -- The developer is working on the Linux version.
* There are so many options to download, which one is it??
The file to download is: RebeccaAIML-src-9871.* (the * indicates the extension of the file. The file is in compressed format, either: .tar.gz, or .zip, or some other compressed form). Go to: http://rebecca-aiml.sourceforge.net/download.htm to download -- It is IMPORTANT that you download the source package (with a "-src" in the filename), and not any other without it (e.g. RebeccaAIML-9871.zip). The source package one has a build_files directory in it, which contains the necessary configure, and Makefile to install RebeccaAIML. Also, in the source package there are installation guides both for Linux and Windows in the files linuxInstall.txt and windowsInstall.txt, respectively. SAVE YOURSELF A HEADACHE, and don't make the same mistake as me for struggling to try to install the non-source version of the package (cause of headache: couldn't find the linuxInstall.txt, configure file, and Makefile file).
* Why use RebeccaAIML? There are some other AIML programs that's available...
I am working on this program/assignment in C++, RebeccaAIML is one of the AIML packages that is written in C++, which means, I can (relatively) easily integrate it with my program. There are other AIML packages that are also written in C++ (go to http://www.alicebot.org/downloads/programs.html to check), but from what I've seen so far, RebeccaAIML has the most comprehensive documentation, and besides, the person who developed RebeccaAIML is very nice, and was very helpful when I e-mailed him asking questions about my trouble installing RebeccaAIML. If you have trouble with RebeccaAIML which are not covered in this notes, or that you cannot find any answer to your RebeccaAIML-related problem/questions (please don't come to him with your personal questions -- talk to Rebecca instead :)) after trying, and/or searching/discussing it in the web, forums, etc., e-mail him at: foreverlinux@yahoo.com

2. Dependencies

* What are dependencies?
Dependencies are other things that need to be installed in order for RebeccaAIML to work. This is a potential headache source as well, so this is IMPORTANT as well. You have been warned.
* Why is this important?
Because unless you have these dependencies installed, you won't get past the ./configure step. You need to do: ./configure, make, and make install to install RebeccaAIML.
* Okay, so what dependencies do I need to run RebeccaAIML?
The dependencies you'll (or RebeccaAIML) need are:
o Boost - some kind of extended C++ library
o XercesC - a C++ - based XML Parser (a program that can interpret XML)
o Qt4.1.1 or Qt4.*
* If you are using Ubuntu like me (I used Ubuntu 6.10) and are inexperienced in UNIX/Linux (like me), I would strongly suggest installing the dependencies through the Synaptic Package Manager. Why? For some reason, I almost could never got anything I install manually in Ubuntu 6.10 (without Synaptic Package Manager) to work properly.
* OK, here's some more details on the dependencies that you'll need:
o Boost
+ The latest version from the website (www.boost.org) is 1.34.7. In the Synaptic Package Manager, however, there is only version 1.33.1 (use the search tool, and enter the keyword: boost).
+ Just tell me which Boost files I need to get it on with RebeccaAIML!
There should be several files that are Boost-related in the list. You will need (at least, these are what I installed which are sufficient to allow me to install RebeccaAIML):
# libboost-dev
# libboost-doc
# libboost-date-time1.33.1
# libboost-date-time-dev
# libboost-filesystem1.33.1
# libboost-filesystem-dev
# libboost-regex1.33.1
# libboost-regex-dev

+ I don't know if the -doc or the -dev files (except for libboost-dev) are necessary for RebeccaAIML to work or not.
+ NOTE: IF YOU ARE NOT INTERESTED IN THE REASONING BEHIND THOSE FILES, AND JUST WANT TO GET RIGHT INTO USING RebeccaAIML, SKIP THE FOLLOWING BULLETS AND GO STRAIGHT TO THE XercesC POINT.
+ What are these files for? Why so many?
I have no idea. I could not find any explanation in any of the documentation why any of these dependencies are necessary (except for XercesC, because it is obvious we'll need some kind of XML parser since the AIML is in XML).
+ But there are other libboost stuff not being installed, e.g. libboost-graph, libboost-iostream...
Yes, it's because only those three were asked during the ./configure. So what happened with my experience was, I did not have Boost installed, and so at a certain point in the ./configure step, it checks for Boost functionalities, and gave an error asking for Boost to be installed. After I installed Boost, then it asked for Boost filesystem. After I installed Boost filesystem, it then asked for Boost date-time. After I installed Boost date-time, it then asked for Boost regex. ONLY after I installed those, the ./configure was able to proceed past checking Boost functionalities.
# A side note to this, let me tell a little more detail on how my experience installing Boost manually went:
* As I said before, in the Boost website (www.boost.org), the latest version is 1.34.7. So, that's what I downloaded.
* I first did a ./configure with specifying a directory for the installation, i.e.:

./configure --prefix=/boost/1_34_7/

* After the ./configure, the make and make install step was not a problem.
* I found the installed Boost header (.h) files in my /usr/include/boost directory. I could not find the libboost-*.* in any of the /lib directories though. Maybe I've overlooked it if they were scattered with the other lib- files in the /usr/lib directory.
* When I went back to the RebeccaAIML directory(/directory_where_it_was_extracted/RebeccaAIML-src-9871/build_files/autoconf) and did the ./configure for RebeccaAIML, it still could not find the Boost files. I tried including the directory where the Boost files are during ./configure, but it didn't work either.
* I decided to uninstall Boost before re-installing it. According to several posts in some forums (search Google: boost uninstall) the way to uninstall Boost is to just delete the Boost installation directory.
* And so I did, and I re-installed Boost, but this time I did not use the --prefix at ./configure. This time, the ./configure failed. Maybe I have to be in super-user mode (in the terminal, type: sudo su)...
* So I re-install Boost under a shallower directory: i.e. /boost, which worked fine as before.
* Then I did ./configure for RebeccaAIML again, and still it asked for Boost. This time I noticed that it was asking for a Boost filesystem functionalities, and I noticed in the directory I specified with --prefix at the Boost ./configure (/boost), there is a directory named filesystem. So I tried copying the folder (from the terminal using:

cp -rf )


into the /usr/lib/boost directory.
* This time, the RebeccaAIML ./configure found the Boost Filesystem functionality, YAY. But, unfortunately, it then asked for another Boost functionality and at this point, I had a splitting headache and decided to rely on Synaptic Package Manager instead to install Boost and the other dependencies (source of headache: errors keep popping up during ./configure).
o Xerces-C
+ What is Xerces-C and why do we need it?
It is a C++ -based XML parser necessary to understand (parse) AIML. AIML is represented in XML form, and so to be able to extract the information represented in AIML, we need the parser to do it.
+ So which Xerces-C package or version should I get?
The latest version of Xerces-C at the point this note is written is 2.8, but in Synaptic Package Manager (in my list, at least), there are only version 2.6, and 2.7. I chose version 2.6 (see reason in the second bullet after this). Save a headache, install through Synaptic Package Manager -- never fails.
+ So which Xerces files should I install? There are several of them in the list.
Here are the files I have installed:
# libxerces26c2
# libxerces26-dev
# libxerces2-java
+ Note: the RebeccaAIML developer (foreverlinux@yahoo.com) told me that Xerces 2.7 is "badly broken", so he recommended using 2.6 or 2.8 instead. In my Synaptic Package Manager, there are only 2.6, and 2.7, so I used 2.6 instead.
# A side note: initially I had 2.7 installed, and had some error messages during make install and loading RebeccaAIML, but it still ran. After uninstalling 2.7 as recommended, and installing 2.6, I still get the same error message in make install. So, I don't know if that makes any difference
o Qt4.1.1
+ What is Qt for?
Your guess is as good as mine.
+ Any particular reason why version 4.1.1?
I don't know. Maybe that's what was used at the time this version of RebeccaAIML was developed. RebeccaAIML ./configure asked for version 4.1.1, but that version doesn't seem to be around anymore, either on Qt's website (www.trolltech.com) nor in the Synaptic Package Manager (at least, according to my list). The ones available in my Synaptic list are versions 3, and 4.2. I installed 4.2, which seems to be sufficient.
+ Show me the files I need, please.
Certainly. Here are the files I installed:
# libqt4-core
# libqt4-dev
# libqt4-gui
# libqt4-qt3support
# libqt4-sql
# libqthreads-12
# in addition, before qt4, I had libqt3-mt

* Once you have those dependencies installed (all hail Synaptic Package Manager), configuring and installing RebeccaAIML is a breeze. Well, there are still some minor coughs, but nothing serious, or so it seems.

3. FINALLY - INSTALLING RebeccaAIML

* How do I go about and install RebeccaAIML on my machine?
First, be aware all the steps explained in this note is for installing RebeccaAIML on an Ubuntu 6.10 machine like mine. I cannot guarantee it will work for other platforms/OS of Linux or even a different Ubuntu release (e.g. 6.06, 7.04). For installation under Windows there's a whole different process altogether.
o For Windows, don't use version 0.9871, instead use the latest one: 1.1tp3 (Slatter); it comes with a Windows installer. Go to http://rebecca-aiml.sourceforge.net/userGuide.htm for a step-by-step explanation for the installation in Windows.
o For Ubuntu Linux 6.10: assuming you already installed all the required dependencies and downloaded the RebeccaAIML version 0.9871 source package:

1. Extract the RebeccaAIML-src-9871.* package into some directory (you choose).
2. In the extracted directory, you should have the following contents:
1. aiml (directory)
2. bin (directory)
3. build_files (directory)
4. conf (directory)
5. doc (directory) -- (the linuxINSTALL.txt & windowsINSTALL.txt are located in here)
6. include (directory)
7. resources (directory)
8. src (directory)
9. Authors.txt
10. dev-todo.txt
11. INSTALL.txt
12. license.txt
13. README.txt
14. rebecca.spec
15. ReleaseNotes.txt

3. Go to the build_files/autoconf sub-directory.
4. In this directory is where you will be doing all the ./configure, make, and make install, or make clean (to uninstall). So, in the terminal/shell/console do:

./configure


If for some reason it does not recognize your installed Qt location, you can specify it by doing (it should give you a hint on the parameter):

./configure --with-qt-dir=


If there is a doxygen error, just ignore it -- it's some documentation on the RebeccaAIML API, but you already have it in the directory where you extract RebeccaAIML under /doc). After the ./configure is successful, do:

make


Sit back, sip your coffee, and let the system do its thing. After it is done with make, first login as a super-user, if you haven't done so:

sudo su
(then type in your password)

After that, do:

make install


Again, sit back and take another sip of your coffee, and wait until it is done. Now here's where I had some error messages -- at the end of make install, it says:

blah blah blah install blah blah blah

...

Making install in regression
make[1]: Entering directory `//RebeccaAIML-src-9871/build_files/autoconf/regression'
make[2]: Entering directory `//RebeccaAIML-src-9871/build_files/autoconf/regression'
test -z "@datadir@/Rebecca/bin/release" || mkdir -p -- "@datadir@/Rebecca/bin/release"
/bin/sh ./libtool --mode=install /usr/bin/install -c 'regression' '@datadir@/Rebecca/bin/release/regression'
libtool: install: `@datadir@/Rebecca/bin/release' must be an absolute directory name
Try `libtool --help --mode=install' for more information.
make[2]: *** [install-binPROGRAMS] Error 1
make[2]: Leaving directory `//RebeccaAIML-src-9871/build_files/autoconf/regression'
make[1]: *** [install-am] Error 2
make[1]: Leaving directory `//RebeccaAIML-src-9871/build_files/autoconf/regression'

make: *** [install-recursive] Error 1


and that's the end of the line of the make install.


4. TESTING RebeccaAIML (Ooh, this is getting exciting!)

* The first way -- and probably the easiest way, to test RebeccaAIML is to:
o Go to your RebeccaAIML installation directory (mine is at): /usr/local/share/Rebecca
o From there, go to /bin/release
o You should see a console executable. Run it: in the terminal/shell/console type:

./console

o and it should start loading a bunch of .aiml categories
o If everything goes well, you should see something like this:

[Rebecca now fully loaded]
[Number of categories loaded: 46105]
[Type /exit to exit]

Symbolic reduction: SET PREDICATES OM
[Warning star Tag Size Exceeded]
Rebecca says: Hello!
You say> hello

Internal information:
=====================
hello : Hello : *
=====================

Rebecca says: Hi there!

o And VOILA! You're chatting with Rebecca!
* The second way, which I had a less than successful experience, is to try the code from the RebeccaAIML's Sourceforge website: http://rebecca-aiml.sourceforge.net/userGuide.htm#cpp_programming
o If you are NOT using Windows, ignore the first sample code which uses

#include
using namespace rebecca;


on the top. The network thing is something that comes with the Windows installation, and not with the Linux version. Use the second example called the "embedded" variant by the guide. However, I was not successful in trying the code as-is (with some modifications to the paths). If you want to start implementing RebeccaAIML into your program, I would suggest taking a look at the console sample source code (mine is located in: /usr/local/share/Rebecca/src/samples/console).
o If you ARE doing this from Windows, then by all means, use that first example as reference. The guide says that it will save you many lines of codes of initiating the AIML components. What I understand so far about this method is that it is using the Internet Communications Engine that comes with the Windows installation of RebeccaAIML, that enables your machine to be a server and do the XML (or AIML) parsing like it was done on a web server (i.e. like browsing the internet).

And Finally, UNINSTALLING RebeccaAIML

* In the directory //RebeccaAIML-src-9871/build_files/autoconf do:

make clean

Thursday, November 8, 2007

Experience with SWIG + C/C++ = Java

Wrappers! Oh, joy.

Do you know how to be able to call C/C++ functions from Java? Wrappers...you have to create these things called "wrappers". Basically what it does is connects your C/C++ codes and your Java codes through some shared objects. "Shared objects? What in the world is that?? How am I supposed to know how to make 'shared objects'??" you ask? I had the same question. Luckily, there are some very nice fellows out there that provide us with a piece of software that is called an interface compiler, which... you guessed it, CREATES THOSE SHARED OBJECTS (and other necessary files) for us to use. Salute to them, I say! One good example of it (and the one I am using) is called SWIG (www.swig.org).

Unfortunately, I don't remember how to install SWIG on my Ubuntu 6.10 system. But I would like to share the problem I experienced in getting my Java code to call the C/C++ functions using SWIG.

To test, I used the example in the SWIG website tutorial page (www.swig.org/tutorial.html). So here goes:

You will have to write the codes for 3 files:
1. The C/C++ code (*.c) which contains the functions you wish to call from another language (in my case, Java).
2. The interface file (*.i) which is the input file for SWIG.
3. The other language code (in my case, *.java) which will call the C/C++ functions in *.c file in 1.
All the other files (shared objects, additional .c files, .java files) will be generated by SWIG. Please refer to the SWIG tutorial page for other languages, as I don't have any experience with SWIG and Python or Perl for example.

First, create your C/C++ file example.c:
/* File : example.c */

#include
double My_variable = 3.0;

int fact(int n) {
if (n <= 1) return 1; else return n*fact(n-1); } int my_mod(int x, int y) { return (x%y); } char *get_time() { time_t ltime; time(&ltime); return ctime(&ltime); }
Ok, nothing specific to point out there. It's just a straight forward C code, copied directly from the SWIG tutorial page. In fact, I'm pretty sure there's nothing in there that's specified for preparing it for the SWIG compilation. This next file, however, IS important; it is the interface file that SWIG will use to create the files necessary to make the wrapper.

/* example.i */
%module example
%{
/* Put header files here or function declarations like below */
extern double My_variable;
extern int fact(int n);
extern int my_mod(int x, int y);
extern char *get_time();
%}

extern double My_variable;
extern int fact(int n);
extern int my_mod(int x, int y);
extern char *get_time();
So, if I understand it correctly, the interface file (example.i) declares all the variables and functions used in the C/C++ file (example.c). Another way to do it, is to write the header file there instead of the variables and functions one-by-one. So here's another example for the interface file using header file from the same SWIG tutorial page:

/* example.i */
%module example
%{
/* Includes the header in the wrapper code */
#include "header.h"
%}

/* Parse the header file to generate wrappers */
%include "header.h"
So, you can use either type of interface file (depends on whether or not you have the header (*.h) file). As you can see, in both formats, you have to declare the variables/functions or header file twice: once within the % and curly brackets ({}), and another just preceded with the % sign (for the one with the header file). Note that when declaring the variables/functions, they must be preceded with the extern keyword. Here's a little thing about the extern keyword...

According to one definition:

External References: extern

  • If a variable is declared (with global scope) in one file but referenced in another, the extern keyword is used to inform the compiler of the variable's existence:
    • In declare.c:
      int farvar;
    • In use.c:
      {
      extern int farvar;
      int a;
      a = farvar * 2;
      }
  • Note that the extern keyword is for declarations, not definitions
    • An extern declaration does not create any storage; that must be done with a global definition
(from: http://icecube.wisc.edu/~dglo/c_class/vstorage.html)

And another:

extern

The extern keyword is used to inform the compiler about variables declared outside of the current scope. Variables described by extern statements will not have any space allocated for them, as they should be properly defined elsewhere.

Extern statements are frequently used to allow data to span the scope of multiple files.

(from: http://www.cppreference.com/keywords/extern.html)


So, it has got something to do for variables that are being used in one code (e.g. iUseVariableA.c), which are declared in another code (e.g. iDeclareVariableA.h or iDeclareVariableA.i). Is it something like "universal" (across several codes/files) variable for the codes that are being compiled? I don't know how to explain it appropriately, so if anyone can help me explain it in plain english, that'll be awesome.

Ok, let's move on to the SWIG-ing (note to self: got to find a better way to say it... that sounded weird). So, the third, and final file you have to make is the other language (in my case, Java) where you have to call the C/C++ functions.

/* main.java */
public class main {
public static void main(String argv[]) {
System.loadLibrary("example");
System.out.println(example.getMy_variable());
System.out.println(example.fact(5));
System.out.println(example.get_time());
}
}
See how you kind of calls the getMy_variable(), fact(int), and get_time() functions that were defined in the example.c by doing example.getMy_variable(), example.fact(5), example.get_time()? Seems pretty straightforward.

Now come the exciting part... compilation!

Here's how it was explained in SWIG tutorial page for compiling for Java module (all these are done in Terminal):

$ swig -java example.i
$ gcc -c example.c example_wrap.c -I/c/jdk1.3.1/include -I/c/jdk1.3.1/include/win32
$ gcc -shared example.o example_wrap.o -mno-cygwin -Wl,--add-stdcall-alias -o example.dll
Uh-oh... yeah, after reading more carefully, I realized that this example was for Cygwin/Windows. You can figure it out by the .../win32 include directory. And more importantly, see the third line, where the output is example.dll, a Windows Dynamic Linked Library (you know it's the output file because it was preceded by the '-o' command). So, what about for Ubuntu (Linux) users like me? Fear not! There is salvation, yet.

After digging deeper into the SWIG website (and unfortunately, couldn't find exactly what I was looking for through searching the forums), I found this documentation for Linux:

$ swig -java example.i
$ gcc -fpic -c example.c example_wrap.c -I/usr/java/j2sdk1.4.2/include -I/usr/java/j2sdk1.4.2/include/linux
$ gcc -shared example.o example_wrap.o -o libexample.so
$ javac main.java
$ java main
(from: http://www.dabeaz.com/cgi-bin/wiki.pl?SwigFaq/Java)

So, first you do (everything here are done in Terminal):

$ swig -java example.i

which tells the SWIG compiler to create a Java module, with the input interface file: example.i
Cool. If it works, SWIG then creates several files in the same directory:

example.java
example.class
example.o
exampleJNI.java
exampleJNI.class
example_wrap.c
example_wrap.o

For the most part, you won't be modifying these files. You can try, but DO IT AT YOUR OWN RISK; make sure you know what you're doing :) As a side note: if you've never done Java programming, the *.class files are the compiled *.java files. So the source codes are in *.java files.

Allrighty, next let's compile the *.c files that we have: example.c and example_wrap.c (one of the result files from SWIG compilation).

$ gcc -fpic -c example.c example_wrap.c -I/usr/java/j2sdk1.4.2/include -I/usr/java/j2sdk1.4.2/include/linux

I don't know if it will make any difference if you use g++ or other C/C++ compiler rather than gcc. I used gcc and it worked fine. So, the thing to keep in mind is the -I include paths; you have to find for yourself where those java***/include and java***/include/linux are located. Mine are located in: /usr/lib/jvm/java-1.5.0-sun/include and /usr/lib/jvm/java-1.5.0-sun/include/linux, respectively, since I used Java SDK 1.5 (which I installed through Synaptic Package Manager). So my actual command looked like this:

$ gcc -fpic -c example.c example_wrap.c -I /usr/lib/jvm/java-1.5.0-sun/include -I /usr/lib/jvm/java-1.5.0-sun/include/linux

Don't forget the .../linux include directory, otherwise it will give some nasty errors. OK, that should compile nicely. Next step, compile and create the shared object.

$ gcc -shared example.o example_wrap.o -o libexample.so
Nothing to be changed here. So basically the compiler will take the object file (note the .o extension) example.o and example_wrap.o, and creates the output file which is the shared object libexample.so (i.e. library -- hence the .so extension). IMPORTANT: Note that for Linux, the output file must start with lib*** (in this case: lib+example = libexample.so), otherwise it won't work.

So now you'll have these files:

example.java
example.class
example.o
exampleJNI.java
exampleJNI.class
example_wrap.c
example_wrap.o
libexample.so

Can you see where we're going with this? We now have a example.class.... which means, now we can have a main Java routine (method, function, whatever) that instantiates (creates) the object named 'example' and thus can access the variables and/or functions (methods) of the object 'example', which variables and functions are actually defined in example.c.

So, let's create that Java routine that calls those lovely functions in example.c (again, this is from the SWIG tutorial page):

/* main.java */
public class main {
public static void main(String argv[]) {
System.loadLibrary("example");
System.out.println(example.getMy_variable());
System.out.println(example.fact(5));
System.out.println(example.get_time());
}
}
In case you're wondering, yeah, I already shown this code. But now it should be clearer; you can notice that we're calling the example functions by: "example." there. So now you just need to compile this main.java file by:

$ javac main.java
Now, here's one part where I had some problems. I got these error messages:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no example in java.library.path

Unfortunately, I didn't do the troubleshooting systematically, that I couldn't really tell which steps fixed the problem, and which don't. But, there is one more step that was not explicitly said in the SWIG tutorial. There are some conversations in some forums (alas, I forgot the link) that said you HAVE TO set the LD_LIBRARY_PATH to where your .so file is. You can do:

export LD_LIBRARY_PATH=:$LD_LIBRARY_PATH

(Don't use the brackets "<>") Apparently, that error is one that most commonly occurs. I think it should be safe to set that path before you compile the .java file, but my experience with it is that I set that path AFTER I compiled the example.i with swig, gcc the *.c files, and the gcc -shared stuff, and I kept getting error messages during compilation. So I deleted all the files that were generated by SWIG, and recompiled the whole thing from scratch. After the javac compilation was successful, I ran the main.class with:

$ java main
And it worked!

$ java main
3.0
120
Fri Nov 9 00:17:37 2007

Hooray!!! Unfortunately, I'm still not sure what's the proper procedure for an error-free, trouble-free, headache-free compilation.

Another thing I want to add is, be careful when you're writing your Java program in packages. I gave packages names on my main.java, example.java, and exampleJNI.java, and here's the error that I got:

$ javac main.java
main.java:8: cannot find symbol
symbol : variable example
location: class facerecognition.main
System.out.println(example.getMy_variable());
^
main.java:9: cannot find symbol
symbol : variable example
location: class facerecognition.main
System.out.println(example.fact(5));
^
main.java:10: cannot find symbol
symbol : variable example
location: class facerecognition.main
System.out.println(example.get_time());
^
3 errors

Unfortunately, I have limited knowledge in compiling Java from the Terminal (I've been using Eclipse). I think if using packages, compiling requires additional arguments:

$ javac -package [package name] [main program].java

I think. If anyone can fill me in on that, I'll really appreciate it.

So there you have it, my experience making wrappers for C/C++ for Java using SWIG. Now I have to create a GUI in Java for application using OpenCV...

Some useful links:
http://www.swig.org/Doc1.3/Java.html
http://www.dabeaz.com/cgi-bin/wiki.pl?SwigFaq/Java