Archive for November, 2009

Improved SWIG C# wrappers for std::vector and std::map

Friday, November 27th, 2009

My previous posts on this topic part 1 and part 2 were posted about half a year ago. Since then SWIG version 1.3.40 has been released and it includes several enhancements in the C# wrapper for std::vector and std::map based on the work that I did, but with several great improvements implemented by William Fulton, the person in charge of the C# wrappers in SWIG.

Since version 1.3.40 wrapping std::vector and std::map in C# is extremely simple. I’ll give a quick overview:

Wrapping std::vector

Lets assume you have a C++ class called MyClass with a method std::vector<int> GetIntVector(); You want to wrap MyClass from  C++ to C# and have the GetIntVector method return an IList<int> in C#. In order to do this, your swig interface file (the .i file) should look something like this:

/* File : MyProject.i */
%module MyProject

%{
#include “MyClass.h”
%}

%include “std_vector.i”
%include “MyClass.h”

%template(Int_Vector) std::vector<int>;

The C# class Int_Vector will implement the IList<int> interface as desired.

Now lets make things a bit trickier by introducing a new class called MyItem and lets add a method to MyClass with the following signature: std::vector<MyItem> GetItems(); In this case you’ll want the C# method to return an IList<MyItem>. One important issue that should be mentioned here is that any class being used in the IList<> generic must overload the == operator. Otherwise, it is only possible to use the IEnumerable<> generic interface.

So if MyItem doesn’t overload the == operator, and you’re content with having the C# method return an IEnumerable<MyItem>, then your swig interface file will look something like this:

/* File : MyProject.i */
%module MyProject

%{
#include “MyClass.h”
#include “MyItem.h”
%}

%include “std_vector.i”
%include “MyClass.h”
%include “MyItem.h”

%template(Int_Vector) std::vector<int>;
%template(Item_Vector) std::vector<MyItem>;

The C# class Item_Vector will implement the IEnumerable<MyItem> interface.

If, however, MyItem overloads the == operator, then you can have the C# Item_Vector implement the IList<MyItem> interface. You’ll need to tell swig that your class can be used with the IList<> interface by using the SWIG_STD_VECTOR_ENHANCED macro. Your swig interface file will look something like this:

/* File : MyProject.i */
%module MyProject

%{
#include “MyClass.h”
#include “MyItem.h”
%}

%include “std_vector.i”
%include “MyClass.h”
%include “MyItem.h”

%template(Int_Vector) std::vector<int>;
SWIG_STD_VECTOR_ENHANCED(MyItem)
%template(Item_Vector) std::vector<MyItem>;

Now the C# class Item_Vector will implement the IList<MyItem> interface.

Wrapping std::map

Thanks to some nifty features added to the SWIG core, it is now possible to wrap C++ std::maps into C# IDictionary<> generic classes very easily.

Lets assume you have a C++ class called MyClass with a method std::map<std::string, int> GetMap(); You want to wrap MyClass from  C++ to C# and have the GetMap method return an IDictionary<string,int> in C#. In order to do this, your swig interface file should look something like this:

/* File : MyProject.i */
%module MyProject

%{
#include “MyClass.h”
%}

%include “std_string.i”
%include “std_vector.i”
%include “MyClass.h”

%template(String_Int_Map) std::map<std::string, int>;

The C# class String_Int_Map will implement the IDictionary<string,int> interface as desired. It’s that simple. No need for any specialization macros or anything.

Offline installation of PEAR packages

Thursday, November 26th, 2009

A few days ago I was trying to set up an offline installation of the FirePHPCore PEAR package on a computer that isn’t connected to the internet. This task wasn’t as easy as I thought it would be.

I downloaded the package (on a computer that has an internet connection) using:

  1. pear channel-discover pear.firephp.org
  2. pear download firephp/FirePHPCore

This gave me a file called FirePHPCore-0.3.1.tgz. Quite pleased with myself I transferred this file to the target machine and ran:

pear install -O FirePHPCore-0.3.1.tgz

This gave me the following error:

Parsing of package.xml from file “/tmp/pear/cache/package.xml” failed
Cannot download non-local package “FirePHPCore-0.3.1.tgz”
Package “FirePHPCore-0.3.1.tgz” is not valid
install failed

That can’t be good. I tried to fix this problem in several ways. I ended up with the following solution:

  1. Extract the contents of the tar file using: tar xzf FirePHPCore-0.3.1.tgz. This creates a file called package.xml and a directory called FirePHPCore-0.3.1 with some files in it.
  2. Edit the package.xml file and change the contents of the “channel” tag (line 4) from pear.firephp.org to pear.php.net
  3. Recreate the tgz file using: tar czf FirePHPCore-0.3.1.tgz package.xml FirePHPCore-0.3.1/*
  4. You are now the proud owner of a FirePHPCore-0.3.1.tgz file that can be installed offline.

Running pear install -O FirePHPCore-0.3.1.tgz on the new tgz file now results in:

install ok: channel://pear.php.net/FirePHPCore-0.3.1

Much better.

Building ACE on Windows using Visual Studio

Monday, November 16th, 2009

The Adaptive Communication Environment (ACE)  framework is an extensive set of cross-platform tools in C++. In this post I will describe in detail the steps required to set up the ACE framework on Windows using Visual Studio, and to set up a project using the ACE framework. The process is not complicated, but there are several pitfalls that one should be aware of.

Here we go!

Note: Steps 1-6 are partially covered in the ACE Build Guide. I give them here with some extra hints and tips.

  1. Download the ACE framework from here. We will be using the full version of ACE.zip (last line under “Latest Micro Release Kit”).
  2. Unzip this file into the directory where you want your ACE files to be located. I put my ACE files under C:\Programming\C++. Unzipping the file creates an ACE_Wrappers directory (C:\Programming\C++\ACE_Wrappers in my case). We’ll call this directory the ACE_ROOT directory.
  3. Go to the ACE_ROOT\ace directory (C:\Programming\C++\ACE_Wrappers\ace in my case) and create a file called “config.h”. Edit this file with notepad or any other text editor and put the following text in the file:
    #include “ace/config-win32.h”
  4. In the ACE_ROOT directory there are several solutions for different versions of Visual Studio and for different types of libraries. In this tutorial I will be using Visual C++ 2008 Express Edition (which is also called vc9) and building ACE as a static library. So the solution I  need is ‘ACE_wrappers_vc_9_Static.sln’. Select the solution that fits your needs.
  5. Select your configuration (Debug or Release) and build the ACE project in your solution. In my case this is ‘ACE_vc9_Static’.
    Building the ACE library
  6. After a few minutes of building, you should have the ACE library file in your ACE_ROOT\lib directory. I built using the Debug configuration, so the file that was created is c:\Programming\C++\ACE_Wrappers\lib\ACEsd.lib
  7. We are now ready to create our first ACE project! Create an empty C++ solution and then edit the project properties.
  8. In “Properties”–”C/C++”–”General”–”Additional Include Directories” add the ACE_ROOT directory.
    Additional Include Directories

  9. In “Properties”–”C/C++”–”Preprocessor”–”Preprocessor Definitions” set the following:
    ACE_AS_STATIC_LIBS
    _CRT_SECURE_NO_WARNINGS
    WIN32

    Preprocessor Definitions

  10. In “Properties”–”C/C++”–”Code Generation”–”Runtime Library” set to Multi-Threaded debug (/MTd) for the Debug configuration and Multi-Threaded (/MT) for the Release configuration.
    Code Generation
  11. In “Properties”–”Linker”–”General”–”Additional Library Directories” add the ACE_ROOT\lib directory.
    Additional Library Directories
  12. In “Properties”–”Linker”–”Input”–”Additional Dependencies” add ACEsd.lib for the Debug configuration and ACEs.lib for the Release configuration.
    Linker Input
  13. Your project is now configured to work with ACE. You can create your project code and start using the ACE framework. Following is a simple example program that runs a thread to perform some work.
    ACE Test Program

That’s all folks!

Loading Perl Modules from a Dynamic or Unknown Location

Friday, November 13th, 2009

Perl modules are sometimes located in non-standard directories. There are several ways to use these modules:

  • Add the directory to the PERL5LIB environment variable.
  • Run the script using the perl -l.
  • Within the script ‘use lib‘ with the directory name.

These methods are quite common and handle most of the cases perfectly.

For example:

#!/usr/bin/perl -w
use strict;

use lib (”/home/users/yuval/perl/modules”);
use MyModule;

This works fine as long as you know that you need to search in /home/users/yuval/perl/modules to find MyModule.

But what happens if you don’t know the location of the module ahead of time?
None of the methods mentioned above can handle this situation. Consider the following code:

#!/usr/bin/perl -w
use strict;

my $user = GetCoolestUser();
use lib (”/home/users/$user/perl/modules”);
use MyModule;

sub GetCoolestUser()
{
return “yuval”;
}

Running this code gives a bunch of really scary compilation errors.

Yes – compilation errors. Yes – in Perl. What gives you ask?

The reason is that the Perl compiler tries to locate all of the modules that are going to be loaded before running the script. It does this before values are given to any variables, and before any functions are evaluated. Therefore the $user variable is undefined when it is evaluated in the parameters to the ‘use lib‘ statement, and then MyModule isn’t found in any of the directories that Perl searches.

There are two ways around this:

1. Push the directory name directly into the @INC array in the BEGIN function

#!/usr/bin/perl -w
use strict;

BEGIN
{
sub GetCoolestUser()
{
return “yuval”;
}

my $user = GetCoolestUser();
push(@INC, “/home/users/$user/perl/modules”);
}
use MyModule;

You may notice that this code doesn’t use the elegant ‘use lib‘ but rather the tasteless pushing of the directory into the @INC array. Also – the GetCoolestUser function has to be defined within the BEGIN block in order to be used.

2. Use the eval function

#!/usr/bin/perl -w
use strict;

my $user = GetCoolestUser();
eval “use lib qw(/home/users/$user/perl/modules);
use MyModule;”;
if ($@) {
die “Error loading module MyModule:\n$@\n”;
}

sub GetCoolestUser()
{
return “yuval”;
}

This method “tricks” Perl compiler and allows loading the module from any location you wish. This method is stronger than the previous method mentioned because the module loading occurs during run time and the location can be calculated dynamically during run time as well.