Reputation: 5701
I am working with a legacy C library that can be extended by writing user defined function(s) and then recompiling the source. I want to avoid the compilation requirement, and instead extend it ONCE with a function (see pseudocode below):
This function will be implemented like this:
VARIANT_TYPE CallSharedLibFunction(const char* library_name, const char* funcname, const char *params, const char* return_type){
// parse arguments and get data types and count
// initiate variable of data type indicated by return_type, to hold returned variable
/* this is the part I need help with */
// lptr = LoadSharedLibrary(library_name);
// funcptr = GetFunctionAddress(lptr, funcname);
// call function and pass it arguments
retvalue = funcptr(param1, param2, param3);
// wrap up returned value in the VARIANT_TYPE
VARIANT_TYPE ret;
setVariantValue(ret, retvalue, return_type);
return ret;
}
Note: despite the "Windows sounding" names (VARIANT_TYPE, LoadSharedLibrary and GetFunctionAddress), I am developing on Linux (Ubuntu 9.10). Ideally, I would like the library loading implementation to be cross platform (since I am using ANSI C code). But if I have to choose one platform, it will have to be the Linux platform.
I would be very grateful if anyone could shed some light on how I can invoke functions in arbitrary shared libraries (ideally, in a cross platform way - failing that, on Linux), so that I can implement the above function.
Upvotes: 2
Views: 1140
Reputation: 3190
You might want to have a look at the dlopen, dlsym and similar functions. These work on POSIX (linux, OSX, win32+cygwin etc...).
With dlopen(), you can open a shared library. Your LoadSharedLibrary can be a wrapper around dlopen(). You GetFuncPtr() function can be a wrapper around dlsym(). What you can do is write code around the dl*() functions to make it robust - like do some error checking. You also might want to define an interface in the shared library, i.e. a struct that 'exports' supported functions. This way you can get a list of methods without the need to resorting to reading elf files.
There is also a nice page about function pointers in C and C++.
Here's a quick example on the usage:
void* LoadSharedLibrary(const char* name)
{
return dlopen(name, RTLD_LOCAL | RTLD_LAZY);
}
void* GetFunctionAddress(void* h, const char* name)
{
return dlsym(h, name);
}
const char** GetFunctionList(void* h)
{
return (char**)dlsym(h, "ExportedFunctions");
}
// Declare a variable to hold the function pointer we are going to retrieve.
// This function returns nothing (first void) and takes no parameters (second void).
// The * means we want a pointer to a function.
void (*doStuff)(void);
// Here we retrieve the function pointer from the dl.
doStuff = GetFunctionAddress(h, "doStuff");
// And this how we call it. It is a convention to call function pointers like this.
// But you can read it as 'take contents of the doStuff var and call that function'.
(*doStuff)();
Upvotes: 5
Reputation: 399813
For Linux/POSIX, you use the dlopen()
family of functions to load shared libraries at runtime, look up symbol addresses, and so on.
If you want to add a library dependency to make working with loadable code a bit easier (and more portable), look into glib's module API.
Upvotes: 2