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 !!