如何在Linux上初始化共享库

11

我正在使用Linux下的C ++开发共享库,并希望此库使用log4cxx进行日志记录。但是,我不确定如何设置它。为了使log4cxx起作用,我需要创建一个logger对象。我该如何确保在加载我的库时创建此对象?

我怀疑最容易的方法是将logger对象创建为全局变量,然后从我的库的任何源文件中使用它,在头文件中声明它为extern。但是,当应用程序连接到库时,如何自动创建日志记录器?

我知道在Windows的DLL中,有一种名为REASON_FOR_CALL == PROCESS_ATTACH的东西;在Linux下是否有类似的东西?


正如在被接受的答案的评论中所指出的那样,这个问题在C中也会出现,解决方案是相同的,因此即使问题描述使用的是C++,我已经添加了C标签。(它为我解决了一个C问题) - dave
3个回答

20

在 Linux 下的 C++ 中,全局变量会在库被加载时自动构造。这可能是最简单的方法。

如果您需要在库加载时调用任意函数,请使用 GCC 的构造函数属性:

__attribute__((constructor)) void foo(void) {
    printf("library loaded!\n");
}

构造函数在库被加载时由动态链接器调用。这实际上是C++全局初始化的实现方式。


1
这对于C库也是有效的。还有__attribute__((destructor)),用于在卸载库时调用函数。 - Bernardo Ramos
这个属性与对象的构造没有任何关系吗? - einpoklum
@einpoklum,没错,这与对象构造大多无关。你可以在C中使用它,因为C没有对象。话虽如此,C++在内部使用它来调用全局对象的构造函数和析构函数。 - Jay Conrod

10
如果你想让你的代码具有可移植性,你应该尝试像这样做:
namespace {
  struct initializer {
    initializer() {
      std::cout << "Loading the library" << std::endl;
    }

    ~initializer() {
      std::cout << "Unloading the library" << std::endl;
    }
  };
  static initializer i;
}

1
你能解释一下为什么你的答案比只使用全局变量更好,而且不需要做任何特殊处理吗? - einpoklum
它为您提供了一个析构函数来进行清理。此外,即使是异常或正常计划的退出,析构函数也将始终在程序退出时被调用。 - Adnan Y

3

使用全局变量(或封装在函数中的本地静态变量)很好...但是这时你就进入了静态初始化失败的领域(实际销毁也不美观)。

我建议看看Loki的Singleton实现。

有各种生命周期策略,其中之一是Phoenix,可以帮助您避免这种失败。

顺便提一下,阅读《现代C++设计》会深入解释Singleton遇到的问题以及各种策略的用途。


1
如果使用“大失败”来形容其他人可能称之为“地狱”,则加1分 :) - unwind
2
Fiasco是由那个糟糕的网站C++ FAQ提出的一个愚蠢的概念。这不是一场灾难,而且在这个范围内,评论甚至与全局变量之间似乎没有任何耦合。 - Martin York
2
请允许我不同意马丁的观点,记录全局变量的构造或销毁是很有诱惑力的。 - Matthieu M.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接