Справочная информация:
Я столкнулся с незавидной задачей переноса приложения C ++ GNU / Linux на Windows. Это приложение выполняет поиск общих библиотек по определенным путям, а затем динамически загружает из них классы с помощью вызовов posix dlopen () и dlsym (). У нас есть очень веская причина для такой загрузки, поэтому я не буду вдаваться в подробности.
Проблема:
Для динамического обнаружения символов, сгенерированных компилятором C ++ с помощью dlsym () или GetProcAddress (), они должны быть обработаны с помощью внешнего блока связей «C». Например:
#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;
}
}
Этот код отлично подходит для C ++, компилируется и работает на многочисленных компиляторах как в Linux, так и в Windows. Однако он не компилируется с MSVC, потому что «тип возвращаемого значения не является допустимым C». Обходной путь, который мы нашли, состоит в том, чтобы изменить функцию так, чтобы она возвращала указатель на список вместо объекта списка:
#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;
}
}
Я пытался найти оптимальное решение для загрузчика GNU / Linux, которое будет либо работать как с новыми функциями, так и со старым прототипом унаследованной функции, либо, по крайней мере, обнаруживать устаревшую функцию и выдавать предупреждение. Для наших пользователей было бы неприлично, если бы в коде произошел сбой при попытке использовать старую библиотеку. Моя первоначальная идея состояла в том, чтобы установить обработчик сигнала SIGSEGV во время вызова get_list (я знаю, что это странно - я открыт для лучших идей). Так что просто для того, чтобы подтвердить, что загрузка старой библиотеки приведет к сбою, где я думал, что я запустил библиотеку, используя старый прототип функции (возвращая объект списка), через новый код загрузки (который ожидает указатель на список), и, к моему удивлению, это просто работал. У меня вопрос почему ?
Код загрузки ниже работает с обоими прототипами функций, перечисленными выше. Я подтвердил, что он работает на Fedora 12, RedHat 5.5 и RedHawk 5.1 с использованием версий gcc 4.1.2 и 4.4.4. Скомпилируйте библиотеки, используя g ++ с -shared и -fPIC, и исполняемый файл должен быть связан с 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);
}