Sunday, October 16, 2011

Removing packages not supported by the Repository

Here's a small tip for rpm based systems (like fedora, centos etc) to remove all the obsolete packages that are not supported by the current repository.

  • List all packages not supported by the repository.
    $ package-cleanup --orphans


  • One can use xargs with the above command to remove them.
    $ package-cleanup --orphans | xargs yum remove -y
    

Monday, October 3, 2011

Calling C++ library function from C code

Recently one of my friend asked this question. I had done this in past but I had to struggle to do this again. So I am documenting this in case i need this again in future.

Let's first create a C++ shared library containing the functions we need.
Since, I am not good with names so I'll call it the "Person" class.


Person.h
#ifndef __PERSON_H__
#define __PERSON_H__

void globalMethod();

class Person
{
 public:
 void instanceMethod();
 static void classMethod();
};

#endif


Person.cpp
#include "Person.h"
#include <iostream>
using namespace std;

void globalMethod()
{
 cout<<"Global method"<<endl;
}

void Person::instanceMethod()
{
 cout<<"Instance method"<<endl;
}

void Person::classMethod()
{
 cout<<"Class method"<<endl;
}


After creating the source files we need to compile them into shared object.

$ g++ -fPIC -c Person.cpp
$ g++ -shared -o libPerson.so Person.o
$


At this point we have our C++ shared library.
A simple client in C++ for this library looks like this.

Client.cpp
#include "Person.h"

int main()
{
 Person p;
 p.instanceMethod();
 Person::classMethod();
 globalMethod();
}


We can compile and run this small program as such. We need to export LD_LIBRARY_PATH before running the binary, so that the loader can find the shared object.

$ g++ Client.cpp -o Client -L. -lPerson
$ export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH
$ ./Client
Instance method
Class method
Global method
$


Till here we know that everything works.
Now, lets call these methods from C code. But, as we know that C++ does name mangling we cannot directly call these methods from the C code. We first have to write some kind of wrapper over the existing library using C naming convention so that the names are not mangled.

Here is what the wrapper class looks like

Wrapper.cpp
#include "Person.h"

extern "C" void GlobalMethod()
{
 globalMethod();
}

extern "C" void InstanceMethod(Person *p)
{
 p->instanceMethod();
}

extern "C" void ClassMethod()
{
 Person::classMethod();
}

Note the InstanceMethod() takes a pointer to Person object. Why ??? Remember the *this* pointer in C++; since this method will be called from C code, we need to manually pass this variable.

This will be our wrapper shared library over the libPerson.so library. lets compile and create the library.

$ g++ -fPIC -c Wrapper.cpp
$ g++ -shared -o libWrapper.so Wrapper.o
$


Now, its time to write our Client in C; it looks like this

Client.c
struct Person
{
};

int main(){
 GlobalMethod();
 struct Person p;
 InstanceMethod(p);
 ClassMethod();
}

Pay attention that we have to create a Struct for the Person class. We need to link this binary against the wrapper library (libWrapper.so) and the actual library(libPerson.so), since the Wrapper depends upon it.


$ gcc Client.c -o C_Client -L. -lWrapper -lPerson
$ ./C_Client
Global method
Instance method
Class method
$


And, we're done !!

Any comments/suggestions are welcomed !!