在Windows中加载共享库时, LoadLibrary() 调用会导致库中的 DllMain 为每个新进程和线程库附加执行,并为每个进程和线程库执行detaaches .
LoadLibrary()
DllMain
Mac OS X,Linux和其他POSIX兼容的操作系统是否有类似的机制?
您可以使用 .init 机制为linux库定义一个on-load函数 . 这与指定二进制文件的加载时间入口点相同(例如,使用除main之外的其他内容作为程序的入口点) .
.init
使用 ld 直接链接时,请使用:
ld
-init <function name>
或者,如果您使用cc / gcc进行链接,则使用:
-Wl,-init,<function name>
这是最简单的水平 .
Edit 对于析构函数/终结符,使用 .fini 机制 . 这与init选项的运行方式相同,您可以使用:
.fini
-fini <function name>
在调用 ld 时 . 可用性仅限于Mac OSX平台上的 -init 选项 .
-init
您还应该能够使用gcc的 __attribute__((constructor)) 语法:
__attribute__((constructor))
static void con() __attribute__((constructor)); void con() { printf("I'm a constructor\n"); }
这可能是一种更便携的方式,而不是使用链接器选项 . 应该在加载时调用所有构造函数,但不依赖于它们的初始化顺序,这会导致精神错乱和不可重现的错误,这些错误会花费时间和精力进行调试 .
Edit 2 使用 __attribute__((constructor))/__attribute__((destructor)) 语义是C / C编程语言最优选的机制 .
__attribute__((constructor))/__attribute__((destructor))
对于 D 编程语言,您应该使用静态模块构造函数/析构函数:
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"); } }
这在writing win32 DLLS和语言规范relating to static constructors/destructors中有强烈暗示 .
Edit 3 您需要链接 .o ,它导出构造函数/析构函数例程,这将允许使用静态初始值设定项 . 因为它应该做的就是调用Runtime.initialize(),这实际上调用了 D 代码中的所有静态构造函数/析构函数 .
.o
为初始化程序存档(在名为 myshared.d 的文件中):
myshared.d
import core.runtime; extern (C) { void attach(); void detach(); } export void attach() { Runtime.initialize(); } export void detach() { Runtime.terminate(); }
为此存根创建.o:
dmd -m32 -c myshared.d
检查附加/分离功能的名称:
nm myshared.o
显示(以及其他输出):
0000001c S _D8myshared6attachFZv 00000034 S _D8myshared6detachFZv
示例.c代码用于调用它(在本例中称为export.c),我们从 my shared.o 文件中引用导出例程的名称:
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 引用需要使用导出函数的错位名称 . 这些必须匹配或代码不会链接 .
extern void
使用以下代码编译C代码:
gcc -m32 -c export.c
使用以下命令将.c.o和.d.o文件链接在一起:
cc -o libmyshared.dylib -m32 -shared myshared.o export.o -lphobos2
假设phobos2库位于标准链接器搜索路径中 . 编译器和链接器的 -m32 选项的第一部分是因为我在本地构建的D编译器的版本仅支持32位 .
-m32
这会生成一个可以链接到的.dylib . 它似乎是基于我执行的有限测试工作 . 看起来对共享对象/动态库的支持非常有限,因此很有可能需要克服另一个障碍 .
要在加载或卸载共享库时执行函数,可以使用特定于GCC的属性语法标记构造函数和析构函数:
__attribute__((constructor)) void init(void) { ... } __attribute__((destructor)) void fini(void) { ... }
因为C环境的各个部分依赖于GCC在幕后添加的标准 .init 代码中初始化的内容,所以直接使用 -Wl,-init,<function name> 可能会导致程序崩溃 .
有关更多信息,请参阅Library constructor and destructor functions上的Libary HOWTO .
GCC和clang AFAIK支持GCC构造函数和析构函数属性 . 有关详细信息,请参阅How exactly does attribute((constructor)) work?
对于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;
InitLibrary InitLib;
4 回答
您可以使用
.init
机制为linux库定义一个on-load函数 . 这与指定二进制文件的加载时间入口点相同(例如,使用除main之外的其他内容作为程序的入口点) .使用
ld
直接链接时,请使用:或者,如果您使用cc / gcc进行链接,则使用:
这是最简单的水平 .
Edit 对于析构函数/终结符,使用
.fini
机制 . 这与init选项的运行方式相同,您可以使用:在调用
ld
时 . 可用性仅限于Mac OSX平台上的-init
选项 .您还应该能够使用gcc的
__attribute__((constructor))
语法:这可能是一种更便携的方式,而不是使用链接器选项 . 应该在加载时调用所有构造函数,但不依赖于它们的初始化顺序,这会导致精神错乱和不可重现的错误,这些错误会花费时间和精力进行调试 .
Edit 2 使用
__attribute__((constructor))/__attribute__((destructor))
语义是C / C编程语言最优选的机制 .对于
D
编程语言,您应该使用静态模块构造函数/析构函数:或者静态类构造函数:
这在writing win32 DLLS和语言规范relating to static constructors/destructors中有强烈暗示 .
Edit 3 您需要链接
.o
,它导出构造函数/析构函数例程,这将允许使用静态初始值设定项 . 因为它应该做的就是调用Runtime.initialize(),这实际上调用了D
代码中的所有静态构造函数/析构函数 .为初始化程序存档(在名为
myshared.d
的文件中):为此存根创建.o:
检查附加/分离功能的名称:
显示(以及其他输出):
示例.c代码用于调用它(在本例中称为export.c),我们从
my shared.o
文件中引用导出例程的名称:请注意,
extern void
引用需要使用导出函数的错位名称 . 这些必须匹配或代码不会链接 .使用以下代码编译C代码:
使用以下命令将.c.o和.d.o文件链接在一起:
假设phobos2库位于标准链接器搜索路径中 . 编译器和链接器的
-m32
选项的第一部分是因为我在本地构建的D编译器的版本仅支持32位 .这会生成一个可以链接到的.dylib . 它似乎是基于我执行的有限测试工作 . 看起来对共享对象/动态库的支持非常有限,因此很有可能需要克服另一个障碍 .
要在加载或卸载共享库时执行函数,可以使用特定于GCC的属性语法标记构造函数和析构函数:
因为C环境的各个部分依赖于GCC在幕后添加的标准
.init
代码中初始化的内容,所以直接使用-Wl,-init,<function name>
可能会导致程序崩溃 .有关更多信息,请参阅Library constructor and destructor functions上的Libary HOWTO .
GCC和clang AFAIK支持GCC构造函数和析构函数属性 . 有关详细信息,请参阅How exactly does attribute((constructor)) work?
对于C,您可以创建一个类并使用他的构造函数和析构函数来初始化库 .
之后,您只需要为此类定义一个变量 .
在库中初始化openssl的示例:
并且只在cpp文件中添加此行:
InitLibrary InitLib;