简体   繁体   English

Linux 共享库 init 和 deinit 也使用 c++ 静态初始化程序

[英]Linux shared library init & deinit when also using c++ static initializer

I want to have automated calls to initialize and deinitialize my shared library.我想要自动调用来初始化和取消初始化我的共享库。

In my shared library, I need some static initialization of C++ objects, among others because of use of third party code (eg UnitTest++).在我的共享库中,由于使用了第三方代码(例如 UnitTest++),我需要对 C++ 对象进行一些静态初始化。 When my init function is executed, I need to be guaranted, that all static initialization of C++ objects (of all linked translation units) is done (and vice versa for deinit);当我的 init 函数被执行时,我需要保证,C++ 对象(所有链接的翻译单元)的所有静态初始化都已完成(反之亦然); so just the same conditions as the execution of main() can expect in a C++ program.所以在 C++ 程序中可以期望与执行 main() 相同的条件。

I've seen much informations about linux shared library init/deinit eg like:我已经看到很多关于 linux 共享库 init/deinit 的信息,例如:

But the provided solutions won't fit my needs. 但是提供的解决方案不符合我的需求。 In both approaches ( __attribute__((constructor)) and even -Wl,-init,<function name> ) the init function seems to be called before static initialization of C++ objects is completely done. 在这两种方法( __attribute__((constructor))甚至-Wl,-init,<function name> )中,init 函数似乎在 C++ 对象的静态初始化完成之前被调用。

I also played around with __attribute__ ((init_priority(…))) like:我也玩过__attribute__ ((init_priority(…)))像:

 class InitAndDeinit { public: InitAndDeinit() { // Do some initialization } ~InitAndDeinit() { // Do some cleanup } } initAndDeinit __attribute__((init_priority(65535)));

But that also won't place the calls to the desired point;但这也不会将呼叫置于所需的位置; even with __attribute__((constructor(65535))) .即使使用__attribute__((constructor(65535)))

I'd tested with gcc 4.6.4, 4.7.3 and 4.8.1 (4.6.4 shows a slightly different behaviour regarding the sorting of __attribute__((constructor)) ).我已经用 gcc 4.6.4、4.7.3 和 4.8.1 进行了测试(4.6.4 显示了关于__attribute__((constructor))排序的稍微不同的行为)。

Any suggestions?有什么建议?

My current workaround is to provide exported functions (lib_init() and lib_deinit()) which have to called manually by the application.我当前的解决方法是提供必须由应用程序手动调用的导出函数(lib_init() 和 lib_deinit())。

Here's one possible solution.这是一种可能的解决方案。

Static objects in a TU are initialized in their order of definition. TU 中的静态对象按其定义顺序进行初始化。 Append a definition of a static object of a special type T to the end of each source file.将特殊类型T的静态对象的定义附加到每个源文件的末尾。 The constructor of T should increment a static zero-initialized member. T的构造函数应该增加一个静态零初始化成员。 As soon as the counter reaches the number of source files in the module (determined by a build script), call your lib_init() .一旦计数器达到模块中源文件的数量(由构建脚本确定),请调用您的lib_init()

lib_deinit() is called after the counter is decremented back to zero. lib_deinit()在计数器递减为零后被调用。

Each library should have its own T .每个库都应该有自己的T

You should be able to modify your makefile such that you don't have to physically alter source files.您应该能够修改您的 makefile,这样您就不必物理更改源文件。 For instance, instead of g++ -c foo.C use g++ -c myspecialstaticinitcode.C -o foo.C -include foo.C or something like that.例如,代替g++ -c foo.C使用g++ -c myspecialstaticinitcode.C -o foo.C -include foo.C或类似的东西。

@Joe static object initialization and the order of initialization is determined by loader or linker handling the .ctors and .dtors section or the .init_array and fini_array section. @Joe 静态对象初始化和初始化顺序由处理 .ctors 和 .dtors 部分或 .init_array 和 fini_array 部分的加载程序或链接器决定。 When the loader calls dlopen() before it returns, global constructors and static object initialization takes place.当加载器在返回之前调用 dlopen() 时,会发生全局构造函数和静态对象初始化。 It may already be happening unless the shared libraries you are using are compiled with `-nostartfiles'' or ``-nostdlib'' The Runtime ABI specification does not mention how it needs to be implemented, it's upto linker/loader.除非您使用的共享库是用“-nostartfiles”或“-nostdlib”编译的,否则它可能已经发生。运行时 ABI 规范没有提到它需要如何实现,它取决于链接器/加载器。 However the standard states that static data and global constructor initialization must take place before any function of the shared library can be called.然而,标准规定在调用共享库的任何函数之前必须进行静态数据和全局构造函数初始化。

please see below.请看下面。

5.2. 5.2. Library constructor and destructor functions Libraries should export initialization and cleanup routines using the gcc attribute ((constructor)) and attribute ((destructor)) function attributes.库构造函数和析构函数 库应该使用 gcc属性((constructor)) 和属性((destructor)) 函数属性导出初始化和清理例程。 See the gcc info pages for information on these.有关这些的信息,请参阅 gcc 信息页面。 Constructor routines are executed before dlopen returns (or before main() is started if the library is loaded at load time).构造器例程在 dlopen 返回之前执行(如果库在加载时加载,则在 main() 启动之前)。 Destructor routines are executed before dlclose returns (or after exit() or completion of main() if the library is loaded at load time).析构函数在 dlclose 返回之前执行(如果库在加载时加载,则在 exit() 或 main() 完成之后)执行。 The C prototypes for these functions are: void attribute ((constructor)) my_init(void);这些函数的 C 原型是: void属性((constructor)) my_init(void); void attribute ((destructor)) my_fini(void); void属性((析构函数)) my_fini(void);

Shared libraries must not be compiled with the gcc arguments -nostartfiles'' or -nostdlib''.不得使用 gcc 参数-nostartfiles'' or -nostdlib'' 编译共享库。 If those arguments are used, the constructor/destructor routines will not be executed (unless special measures are taken).如果使用这些参数,则不会执行构造函数/析构函数例程(除非采取特殊措施)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM