It's easy to load functions from dynamic libraries when you know this function in design time. just do something like this:
int (*fn)(int);
l0 = dlopen("./libfoo.so", RTLD_LAZY);
if (!l0)
{
fprintf(stderr, "l0 %s\n", dlerror());
return 1;
}
fn = (int (*)(int))dlsym(l0, "foo");
if ((error = dlerror()) != NULL)
{
fprintf(stderr, "fn:%s\n", error);
return 1;
}
x=(*fn)(y);
...
How to execute library function when it's unknown in design time? In runtime you have a function name and array of arguments pointers and array of arguments sizes:
char* fn_name="foo"; int foo_argc; void* foo_argv[]; int foo_argv_size[];
In scripting language it's a piece a cake task, but how to implement this nicely in c++?
As the problem is stated, you can't do this in standard C++. There is no way to validly call a function unless the compiler knows the callee's parameters at compilation time. Even in the case of a varargs function, the calling code must be compiled knowing what arguments are passed - there's no way to build a
va_list
.If you control the functions in the dll, then probably the best thing is to pass a collection of
boost::any
(if both will be compiled with the same compiler and libraries), orvoid*
(if you don't have that much compatibility), or some serialised form of the parameters (Google's protocol buffer, maybe).If the dll already exists and you can't change its interface, then you need either to play non-standard tricks with the stack to put the parameters in the right place according to your calling convention (which is what dynamic languages do when they have a C calling mechanism), or else you need a huge switch statement covering all the function signatures that it might be. Obviously the latter is only possible if you already have a good idea what dll(s) you're dealing with.
Also, in general you need more than a list of pointers to arguments and their sizes. The calling convention quite possibly depends on the types of the parameters, not just the sizes. For example, floating-point arguments could be passed in FPU registers instead of on the stack.
You also need to worry about the return type, and what the calling code is expecting to do with it.
There's actually a method to call a function at run-time if you know its calling convention and which parameters it receives. This however lies out of the standard C/C++ language scope.
For x86 assembler:
Assuming the following:
You may use then the following function:
You may need to adjust this function, depending on the calling convention used
You can't. There's no reflection in C++. You'll have to know the functions prototype in order to be able to call it. (Unless you implement your own reflection, anyway.)
Being a static language, C++ really depends on knowing the type/interface at compile time. I doubt there's a good low-level way to accomplish the task you're looking to solve but, as always, if you add another layer of abstraction you can probably accomplish the goal. Specifically in this case the approach I've used in the past when not knowing exactly what "arguments" need to be passed to a dynamically loaded plugin is to pass a single argument of
std::map< std::string, std::string > >
(i.e a key=value dictionary) Just pack it with whatever information needs to be passed in and let the plugin figure out what to do with it. It's somewhat inconvenient in that you must encode/decode most of your data but it can be used to gracefully handle most cases I've run in to at least.Of course, this assumes that you have the ability to control the API of the dynamically loaded DLL by standardizing the Plugin interface. If you can't do that... you're probably out of luck.