Background:
I found myself with the unenviable task of porting a C ++ GNU / Linux application to Windows. One of the tasks of this application is to search for shared libraries by specific paths, and then dynamically load classes from them using the posix dlopen () and dlsym () calls. We have a very good reason for downloading this method, so that I do not become involved here.
Problem:
In order to dynamically detect characters generated by the C ++ compiler using dlsym () or GetProcAddress (), they must be decoupled using the extern "C" link block. For example:
#include <list> #include <string> using std::list; using std::string; extern "C" { list<string> get_list() { list<string> myList; myList.push_back("list object"); return myList; } }
This code is great for C ++ and compiles and runs on numerous compilers on both Linux and Windows. However, it does not compile with MSVC because "the return type is not valid C". The workaround we came up with is to change the function to return a pointer to a list instead of a list object:
#include <list> #include <string> using std::list; using std::string; extern "C" { list<string>* get_list() { list<string>* myList = new list<string>(); myList->push_back("ptr to list"); return myList; } }
I am trying to find the optimal solution for the GNU / Linux bootloader that will either work with new functions as well as with a prototype of an old obsolete function, or at least detect when an obsolete function is encountered and a warning is issued. It would be indecent for our users if the code simply broke off when they tried to use the old library. My initial idea was to set up a SIGSEGV signal handler while calling get_list (I know this is not good - I am open to better ideas). So just to confirm that loading the old library will be segfault, where I thought I started the library using the old function prototype (returning a list object) through the new loading code (which expects a pointer to the list) and to my surprise it just worked. The question is why?
The downloaded code below works with both of the function prototypes listed above. I have confirmed that it works on Fedora 12, RedHat 5.5 and RedHawk 5.1 using gcc versions 4.1.2 and 4.4.4. Compile the libraries using g ++ with -shared and -fPIC, and the executable must be linked to dl (-ldl).
#include <dlfcn.h> #include <stdio.h> #include <stdlib.h> #include <list> #include <string> using std::list; using std::string; int main(int argc, char **argv) { void *handle; list<string>* (*getList)(void); char *error; handle = dlopen("library path", RTLD_LAZY); if (!handle) { fprintf(stderr, "%s\n", dlerror()); exit(EXIT_FAILURE); } dlerror(); *(void **) (&getList) = dlsym(handle, "get_list"); if ((error = dlerror()) != NULL) { printf("%s\n", error); exit(EXIT_FAILURE); } list<string>* libList = (*getList)(); for(list<string>::iterator iter = libList->begin(); iter != libList->end(); iter++) { printf("\t%s\n", iter->c_str()); } dlclose(handle); exit(EXIT_SUCCESS); }
bckohan
source share