Я создаю простую структуру плагинов, в которой я хотел бы иметь возможность использовать dlopen() совместно используемую библиотеку (например, плагин), проверять и использовать любые заводские функции и в конечном итоге dlclose(), оставляя след.dlclose() не работает с заводской функцией и сложной статической функцией?
Моя фабричная система тривиальна, с одной экспортированной функцией, которая возвращает указатель на общий базовый класс. Чтобы проверить, правильно ли выгружен плагин, у меня есть статический объект, деструктор которого устанавливает bool из основной программы.
Вот основная программа:
// dltest.cpp follows. Compile with g++ -std=c++0x dltest.cpp -o dltest -ldl
#include <dlfcn.h>
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
if (argc > 1)
{
void* h = dlopen(argv[1], RTLD_NOW|RTLD_LOCAL);
if (!h)
{
cerr << "ERROR: " << dlerror() << endl;
return 1;
}
bool isFinilized = false;
*(bool**)dlsym(h, "g_finilized") = &isFinilized;
cout << boolalpha << isFinilized << endl;
if (dlclose(h))
{
cerr << "ERROR: " << dlerror() << endl;
return 2;
}
cout << boolalpha << isFinilized << endl;
}
return 0;
}
И код плагина заключается в следующем:
// libempty.cpp follows. Compile with g++ -std=c++0x libempty.cpp -o libempty.so -fPIC -shared
#include <iostream>
#include <vector>
using namespace std;
bool* g_finilized = nullptr;
struct Finilizer
{
~Finilizer()
{
cout << "~Finilizer()" << endl;
if (g_finilized) *g_finilized = true;
}
} g_finilizer;
class Base
{
public:
virtual void init() = 0;
};
class Foo: public Base
{
virtual void init()
{
static const vector<float> ns = { 0.f, 0.75f, 0.67f, 0.87f };
}
};
extern "C" __attribute__ ((visibility ("default"))) Base* newBase() { return new Foo; }
Если выполняется, выход:
false
false
~Finilizer()
Это показывает вызов dlclose () не работает должным образом, и библиотека не выгружается до выхода программы.
Однако, если мы перемещаем вектора вне функции, так что последние 8 строк читаем:
class Foo: public Base
{
virtual void init()
{
}
};
static const vector<float> ns = { 0.f, 0.75f, 0.67f, 0.87f };
extern "C" __attribute__ ((visibility ("default"))) Base* newBase() { return new Foo; }
Тогда dlclose() работает правильно и выход:
false
~Finilizer()
true
То же результаты генерируются, если вектор оставлен в функции, но экспорт не экспортируется:
class Foo: public Base
{
virtual void init()
{
static const vector<float> ns = { 0.f, 0.75f, 0.67f, 0.87f };
}
};
//extern "C" __attribute__ ((visibility ("default"))) Base* newBase() { return new Foo; }
Pos Результаты, полученные в результате, можно найти, если вектор заменен на массив C:
class Foo: public Base
{
virtual void init()
{
static const float ns[] = { 0.f, 0.75f, 0.67f, 0.87f };
}
};
extern "C" __attribute__ ((visibility ("default"))) Base* newBase() { return new Foo; }
Это ошибка в GCC/Linux? Существует ли какое-либо обходное решение, чтобы сложные объекты могли статически объявляться в членной функции факторизованного класса?
Откуда у вас возникла мысль, что одно поведение «правильно», а другое - нет? Я не думаю, что POSIX.1-2001 делает какие-либо гарантии так или иначе. –
Код ассемблера, сгенерированный в обоих случаях, значительно отличается. Когда 'ns' определяется как статическая локальная переменная, многие дополнительные обработчики регистрируются с помощью' __cxa_atexit() ', а поведение trader' ld-linux.so' показывает, что дополнительные символы разрешаются. К сожалению, Intel C++ не поддерживает списки инициализаторов, и трудно проверить, относится ли это поведение только к GCC. –
@NikolaiNFetissov: Согласно странице man: «Функция dlclose() уменьшает счетчик ссылок на дескриптор дескриптора динамической библиотеки. Если счетчик ссылок падает до нуля, а другие загруженные библиотеки не используют в нем символы, тогда динамическая библиотека выгружается «. Я не вижу явной причины, почему его следует выгружать в некоторых тестовых случаях, а не в других. – gavwould