11

I am developing a shared library using C++ under Linux, and I would like this library to use log4cxx for logging purposes. However, I'm not sure how to set this up. For log4cxx to work, I need to create a logger object. How can I make sure this object is created when my library is loaded?

I suspect that it will be easiest to create the logger object as a global variable and then use it from any of the source files of my library, declaring it as extern in the headers. But how can I have the logger created automatically once an application connects to the library?

I know that in DLLs for Windows, there's a thing as REASON_FOR_CALL == PROCESS_ATTACH; is there a similar thing under Linux?

dave
  • 4,812
  • 4
  • 25
  • 38
andreas-h
  • 10,679
  • 18
  • 60
  • 78
  • As noted in the comments on the accepted answer, this is a problem comes up in C as well and the solution is the same, so I've added the C tag even though the problem description is using C++. (it solved a C problem for me) – dave Aug 02 '19 at 07:36

3 Answers3

20

In C++ under Linux, global variables will get constructed automatically as soon as the library is loaded. So that's probably the easiest way to go.

If you need an arbitrary function to be called when the library is loaded, use the constructor attribute for GCC:

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

Constructor functions get called by the dynamic linker when a library is loaded. This is actually how C++ global initialization is implemented.

Jay Conrod
  • 28,943
  • 19
  • 98
  • 110
  • 1
    This is valid for C libraries too. There is also the `__attribute__((destructor))` for a function to be called when the library is unloaded – Bernardo Ramos Jun 17 '15 at 01:41
  • ... and this attribute has nothing to do with object construction? – einpoklum Jan 22 '16 at 16:38
  • @einpoklum, right, this is mostly unrelated to object construction. You can use it in C, which doesn't have objects. That said, C++ uses this internally to call constructors and destructors of global objects. – Jay Conrod Jan 22 '16 at 22:46
10

If you want your code to be portable you should probably try something like this:

namespace {
  struct initializer {
    initializer() {
      std::cout << "Loading the library" << std::endl;
    }

    ~initializer() {
      std::cout << "Unloading the library" << std::endl;
    }
  };
  static initializer i;
}
  • 1
    Can you explain why your answer is better to just using globals and not doing anything special about it? – einpoklum Jan 22 '16 at 16:39
  • It gives you a destructor to cleanup. Additionally the destructor will always be called on program exits even when it's an exception or a normal planned exit. – Adnan Y Mar 03 '17 at 22:07
3

Using a global (or a local-static wrapped up in a function) is nice... but then you enter the land of static initialization fiasco (and the actual destruction is not pretty either).

I would recommend to have a look at the Singleton implementation of Loki.

There are various lifetime policies, one of which is Phoenix and will help you avoid this fiasco.

When you are at it, read Modern C++ Design which explains the problems encountered by the Singleton in depth as well as the uses for the various policies.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • 1
    +1 for using the word "fiasco" to describe what others might call "hell". :) – unwind Nov 05 '09 at 16:22
  • 2
    Fiasco is a stupid concept brought up by that terrible website C++ FAQ. Its not a fiasco and the comment is not even relevant in this scope as there does not seem like there would be any coupling between global variables. – Martin York Nov 05 '09 at 17:23
  • 2
    Allow me to disagree Martin, but the temptation to log construction or destruction of globals is real. – Matthieu M. Nov 06 '09 at 07:11