Below is an example how to dynamically load a C++ shared library on Linux.
This is the project structure.
|-- include
| |-- Hello.h
| `-- IHello.h
|-- src
| |-- Hello.cpp
| `-- Main.cpp
`-- wscript
IHello.h
#ifndef IHELLO_H_
#define IHELLO_H_
class IHello {
public:
virtual void SayHello() const = 0;
virtual ~IHello() {};
};
typedef IHello* (*CreateFunc)();
typedef void (*DestroyFunc)(IHello*);
#endif /* IHELLO_H_ */
First, we need to create C-like functions for creating an instance of Hello and destroying it. This is a kind of factory class. Second, we need to add extern "C" to avoid C++ name mangling.
Hello.h
#ifndef HELLO_H_
#define HELLO_H_
#include "IHello.h"
class Hello : public IHello {
public:
Hello();
void SayHello() const;
virtual ~Hello();
};
#endif /* HELLO_H_ */
Hello.cpp
#include <iostream>
#include "Hello.h"
using namespace std;
Hello::Hello() {
cout << "Creating Hello" << endl;
}
Hello::~Hello() {
cout << "Destroying Hello" << endl;
}
void Hello::SayHello() const {
cout << "Hello World" << endl;
}
extern "C" IHello* CreateHello() {
return new Hello;
}
extern "C" void DestroyHello(IHello* h) {
delete h;
}
Main.cpp
#include <iostream>
#include <dlfcn.h>
#include "IHello.h"
using namespace std;
int main() {
void* helloLib = dlopen("./libhello.so", RTLD_LAZY);
if (!helloLib) {
cerr << "Error loading libhello.so" << endl;
return 1;
}
CreateFunc cf = (CreateFunc) dlsym(helloLib, "CreateHello");
IHello* hello = cf();
hello->SayHello();
DestroyFunc df = (DestroyFunc) dlsym(helloLib, "DestroyHello");
(df)(hello);
if (dlclose(helloLib)) {
cerr << "Error closing libhello.so" << endl;
return 1;
}
return 0;
}
As you can see in the Main.cpp, we only include IHello.h and not Hello.h (the implementation), which is a pure virtual class. This is something like an interface in Java/C#.
wscript
#!/usr/bin/env python
top = '.'
out = 'build'
def options(opt):
opt.load('compiler_cxx')
def configure(ctx):
ctx.load('compiler_cxx')
def build(ctx):
ctx.shlib(source='src/Hello.cpp', cxxflags=['-g', '-Wall'],
target='hello', includes=['include'])
ctx.program(source='src/Main.cpp', cxxflags=['-g', '-Wall'],
lib=['dl'], includes=['include'], target='main')
Let's build it now.
waf configure build
cd build
./main
Below is the output.
Creating Hello
Hello World
Destroying Hello
No comments:
Post a Comment