Skip to content

Instantly share code, notes, and snippets.

@max630
Last active August 29, 2015 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save max630/9a54b947f211b33258bb to your computer and use it in GitHub Desktop.
Save max630/9a54b947f211b33258bb to your computer and use it in GitHub Desktop.
dynamic c++ calls
#pragma once
#include <boost/any.hpp>
#include <dlfcn.h>
namespace impl {
inline void* gate(const char* libname, const char* name, const char** err)
{
dlerror();
void* lib = dlopen(libname, RTLD_NOW);
if (lib == nullptr) {
*err = dlerror();
return nullptr;
}
void* sym = dlsym(lib, name);
*err = dlerror();
if (*err != nullptr) return nullptr;
return sym;
}
}
template <class Def>
class Dynamic {
typedef decltype(Def::Default) ResultType;
public:
static ResultType* Get()
{
static ResultType* Result = nullptr;
if (Result == nullptr) {
Dynamic<Def> worker;
if (!worker.Resolve(Def::Libname(), Def::Name()))
Def::Error(worker.Error());
Result = worker.Result;
}
return Result;
}
bool Resolve(const std::string& libname, const std::string& name)
{
const char* err_c = nullptr;
boost::any* res1 = static_cast<boost::any*>(impl::gate(libname.c_str(), name.c_str(), &err_c));
if (res1 == nullptr) {
error = err_c;
Result = Def::Default;
return false;
}
auto res2 = boost::any_cast<ResultType*>(res1);
if (res2 == nullptr) {
error = std::string("Bad cast: ") + name + " to: " + typeid(ResultType*).name();
Result = Def::Default;
return false;
}
Result = *res2;
return true;
}
std::string Error() const
{
return error;
}
private:
ResultType* Result;
std::string error;
};
#define DEF_DEFAULT(_libname, _name) \
static std::string Libname() { return _libname; } \
static std::string Name() { return _name; } \
static void Error(const std::string& msg) { \
std::cerr << "Error: " << msg << std::endl; \
}
#include "dynamic.h"
#include <iostream>
struct DefTest {
static std::string Default() { return "default"; }
static std::string Libname() { return "./dynamic_lib.so"; }
static std::string Name() { return "dynamic_lib_test"; }
static void Error(const std::string& msg) {
std::cerr << "Error: " << msg << std::endl;
}
};
struct DefTest2 {
static std::string Default() { return "default"; }
DEF_DEFAULT("./dynamic_lib.so", "dynamic_lib_test2")
};
struct DefTest3 {
static int Default() { return 42; }
DEF_DEFAULT("./dynamic_lib.so", "dynamic_lib_test")
};
int main()
{
std::string error;
std::cout << "Func1: " << Dynamic<DefTest>::Get()() << std::endl;
std::cout << "Func2: " << Dynamic<DefTest2>::Get()() << std::endl;
std::cout << "Func3: " << Dynamic<DefTest3>::Get()() << std::endl;
}
#include <boost/any.hpp>
#include <string>
std::string test()
{
return "hello";
}
extern "C" {
boost::any dynamic_lib_test = &test;
}
all: dynamic_lib.so dynamic
dynamic_lib.so: dynamic_lib.cc dynamic.h
g++ -g -Wall -Werror -std=c++11 -shared -o dynamic_lib.so dynamic_lib.cc
dynamic: dynamic_client.cc dynamic.h
g++ -g -Wall -Werror -std=c++11 -o dynamic dynamic_client.cc -ldl
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment