#c #shared-libraries #solaris #sunstudio #dlsym
#c #общие библиотеки #solaris #sunstudio #dlsym
Вопрос:
Я создаю небольшую разделяемую библиотеку-оболочку C вокруг библиотеки Fortran 95. Поскольку символы Fortran содержатся .
в имени символа, я должен использовать dlsym
для загрузки функции Fortran в указатель функции C .
В настоящее время у меня есть куча глобальных указателей на функции в заголовочных файлах:
// test.h
extern void (*f)(int* arg);
и я заполняю их в соответствующем файле C :
// test.cc
void (*f))(int* = reinterpret_cast<void(*)(int*>(dlsym(RTLD_DEFAULT, "real_f.symbol_name_");
Вопросы:
- Если я сделаю это таким образом, когда эти указатели будут заполнены?
- Могу ли я предположить, что они будут загружены в мой исполняемый файл, который загружает эту библиотеку?
- В частности, могу ли я использовать эти функции в статически созданных объектах в моем исполняемом файле или других библиотеках? Или это страдает от фиаско статического порядка инициализации?
- Если приведенный выше способ неверен, каков наиболее элегантный способ заполнения этих указателей, чтобы их можно было использовать в статических объектах в исполняемых файлах и других библиотеках?
Я использую компилятор Sun Studio на Solaris, если это имеет значение, но меня также заинтересовало бы решение для GCC в Linux.
Ответ №1:
Где строка
f = reinterpret_cast<void(*)(int*)>(dlsym(RTLD_DEFAULT, "real_f.symbol_name_"));
происходит в test.cc
? Указатель будет инициализирован при выполнении строки
(что, конечно, зависит от того, когда вызывается функция, которая его содержит
). Или вы хотели написать
void (*f)(int* ) = reinterpret_cast<void(*)(int*>(dlsym(RTLD_DEFAULT, "real_f.symbol_name_");
? В этом случае указатель будет инициализирован во время статической
инициализации. Это означает, что у вас все еще возникают
проблемы с порядком инициализации, если вы пытаетесь использовать указатели в конструкторе статического
объекта.
Классическим решением для этого было бы использовать какой-то синглтон:
struct LibraryPointers
{
void (*f)(int* );
// ...
static LibraryPointers constamp; instance()
private:
LibraryPointers();
};
LibraryPointers constamp;
LibraryPointers::instance()
{
static LibraryPointers theOneAndOnly;
return theOneAndOnly;
}
LibraryPointers::LibraryPointers()
: f( reinterpret_cast<void(*)(int*)>(dlsym(RTLD_DEFAULT, "real_f.symbol_name_")) )
, // initialization of other pointers...
{
}
Затем оберните библиотеку в класс C , который использует эту структуру для получения
адресов указателей.
И последнее замечание: reinterpret_cast
то, что вы пытаетесь сделать, не является законным, по крайней мере, формально. (Я думаю, что и Sun CC, и g примут это, однако.) Согласно Posix, правильный способ получить указатель на функцию из dlsym
будет:
void (*f)(int* );
*reinterpret_cast<void**>(amp;f) = dlsym(...);
Однако это не поддается инициализации.
Комментарии:
1. Да, спасибо, я действительно хотел написать это так, как вы сказали. Я исправлю вопрос. Я знаю, что у меня будут проблемы с другими статическими объектами в той же библиотеке, но верно ли это и в других библиотеках, которые используют эту библиотеку?
2. Мне бы очень хотелось избежать одноэлементного решения, я тоже думал об этом..
3. @lytenyn У других библиотек не должно возникнуть проблем, если они загружаются после загрузки вашей библиотеки. (И, конечно, если они были загружены раньше, глобальный символ с указателем на функцию недоступен.)