Автоматически выполняемые функции при загрузке общих библиотек
при загрузке общих библиотек в Windows,LoadLibrary()
называть причины DllMain
в библиотеке, чтобы выполнить для каждого нового процесса и потока библиотека придает, и для каждого процесса и потока библиотека из deattaches.
существует ли аналогичный механизм для Mac OS X, Linux и, возможно, других POSIX-совместимых ОС?
4 ответов
вы можете определить функцию on-load для библиотеки linux с помощью .init
механизм. Это то же самое, что указать точку входа во время загрузки для двоичного файла (например, используя что-то другое, чем main в качестве точки входа для программы).
при связывании с помощью ld
можно использовать в:
-init <function name>
или если вы используете cc/gcc для связи, вы используете:
-Wl,-init,<function name>
это на самом простом уровне.
редактировать
Для деструкторы/финализаторы, вы используете .fini
механизм. Это работает так же, как опция init, и вы используете:
-fini <function name>
при вызове ld
. Доступность ограничена -init
опция на платформе Mac OSX.
вы также должны иметь возможность использовать __attribute__((constructor))
синтаксис для gcc:
static void con() __attribute__((constructor));
void con() {
printf("I'm a constructor\n");
}
что, вероятно, является более портативным способом, а не завинчиванием параметров компоновщика. Все конструкторы должны вызываться во время загрузки, но не зависит от порядка их инициализации, что приводит к безумию и невоспроизводимых ошибок, которые стоили времени и усилий для отладки.
Изменить 2 использование __attribute__((constructor))/__attribute__((destructor))
semantic является наиболее предпочтительным механизмом для языка программирования C / C++.
на D
язык программирования вы действительно должны использовать конструктор/деструктор статического модуля:
static this() {
printf("static this for mymodule\n");
}
static ~this() {
printf("static ~this for mymodule\n");
}
или статический класс конструктор:
class Foo {
static this() {
printf("static this for Foo\n");
}
}
на это сильно намекают в написание Win32 DLL и в спецификации языка относящиеся к статическим конструкторам / деструкторам.
редактировать 3 вам нужно будет связать в .o
что экспортирует процедуры конструктора/деструктора, что позволит использовать статические инициализаторы. Как и все, что он должен сделать, это вызвать Runtime.initialize (), это фактически вызывает все статические конструкторы/деструкторы в D
код.
заглушка D код для инициализатора (в файле с именем myshared.d
):
import core.runtime;
extern (C) {
void attach();
void detach();
}
export void attach() {
Runtime.initialize();
}
export void detach() {
Runtime.terminate();
}
создать .О, этот огрызок:
dmd -m32 -c myshared.d
Проверьте имена функций присоединения / отсоединения:
nm myshared.o
показывает (среди других выходных данных):
0000001c S _D8myshared6attachFZv
00000034 S _D8myshared6detachFZv
образец .C код для вызова этого (называется export.c в этом случае), мы ссылаемся на имена экспортированных подпрограмм из my shared.o
файл:
extern void D8myshared6attachFZv(void);
extern void D8myshared6detachFZv(void);
void __attach(void) __attribute__((constructor));
void __detach(void) __attribute__((destructor));
void __attach(void)
{
D8myshared6attachFZv();
}
void __detach(void)
{
D8myshared6detachFZv();
}
отметим, что extern void
ссылки должны использовать искаженное имя экспортируемой функции. Они должны совпадать или код не будет связываться.
скомпилируйте код C, используя:
gcc -m32 -c export.c
ссылка .С. О, а также .д.o файлы вместе с помощью:
cc -o libmyshared.dylib -m32 -shared myshared.o export.o -lphobos2
предполагая, что библиотека phobos2 находится в вашем стандартном пути поиска компоновщика. Обрывки -m32
параметры для компилятора и компоновщика заключаются в том, что версия D компилятор, который я построил локально, поддерживал только 32bit.
это производит .dylib, с которым можно связать. Кажется, он работает на основе ограниченного тестирования, которое я выполнил. Похоже, поддержка общих объектов / динамических библиотек очень ограничена, поэтому есть хороший шанс, что будет еще одно препятствие для преодоления.
чтобы функция выполнялась при загрузке или выгрузке общей библиотеки, вы можете пометить конструктор и функцию деструктора, используя синтаксис атрибута GCC:
__attribute__((constructor)) void init(void) { ... }
__attribute__((destructor)) void fini(void) { ... }
потому что различные части среды C зависят от того, что инициализируется в стандарте .init
код добавлен GCC за кулисами, напрямую используя -Wl,-init,<function name>
может привести к сбою вашей программы.
для получения дополнительной информации см. Libary HOWTO on библиотека конструктора и функции деструктора.
GCC, а также clang AFAIK, поддерживают конструктор GCC и атрибуты деструктора. Дополнительные сведения см. В разделе как именно работает _ _ attribute__((конструктор))?
для C++ можно создать класс и использовать его конструктор и деструктор для инициализации библиотеки.
после этого вам нужно только определить переменную для этого класса.
пример инициализации openssl в библиотеке:
class InitLibrary {
public:
InitLibrary() {
CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use
SSL_library_init(); // Initialize OpenSSL's SSL libraries
SSL_load_error_strings(); // Load SSL error strings
ERR_load_BIO_strings(); // Load BIO error strings
OpenSSL_add_all_algorithms(); // Load all available encryption algorithms
}
~InitLibrary() {
ERR_remove_state(0);
CRYPTO_cleanup_all_ex_data();
ENGINE_cleanup();
}
};
и только добавьте эту строку в cpp-файл:
InitLibrary InitLib;