0

I'm working on a project where we have several executables that share several object files. We want to add logging to all of the executables, and have a library for doing so.

However, it seems clumsy to go to the main() function of every executable file and add in the same boiler-plate function call to start the logging. It means we write the same thing over again, and loose out on maintainability and DRY ("don't repeat yourself"). It would be nice if we could systematically ensure that logging started before the main function gets called.

It occurred to me there are functions in libc++ that make the call to main, and it may be possible to override them. However, I don't know what they are and imagine this could break things if we're not careful. Does anyone know how this would be done? Or, if that's too over-the-top, any other suggestions on how to proceed?

We're using C++11 with g++ 4.8 if it makes any difference.

bchurchill
  • 1,410
  • 8
  • 23
  • Why don't you "inject" your startup and shutdown code in the constructor / destructor of a global variable? The only problem you're left with is when you do this multiple times; the order in which they are initialized is then not specified, so you should not depend on any. – leemes Sep 29 '14 at 08:45
  • How would overriding the main function in every executable be more maintainable than adding one function call to main in every executable? – eerorika Sep 29 '14 at 08:47
  • This is not a duplicate. He has not asked "how do I get code to run before main"? He has asked how to solve a problem, where that might be part of the solution. – CashCow Sep 29 '14 at 08:56

1 Answers1

5

You do not need to do this by modifying main().

You should instead create a class at global scope in a shared object library. The constructor of this class will perform the "initialisation" you want to do, before main() runs, and its destructor will run after main().

The issue you need to deal with is that the order of this initialisation and destruction is not guaranteed to be deterministic with regards to any other global-scope objects. All of this could go in one .cpp compilation unit.

class LoggingManager // you can make this a singleton but not necessary
{
   public:
      LoggingManager(); 

      ~LoggingManager();
};

LoggingManager::LoggingManager()
{
     // your initialisation code goes here
}

LoggingManager::~LoggingManager()
{
     // your clean-up code goes here. It should not throw
}

LoggingManager loggingManagerStaticInstance; 

Note that there is a small danger of the "static initialization" issue which means in reality your loggingManagerStaticInstance might not be loaded until your compilation unit is first accessed.

In reality it doesn't matter if this is after main() as long as the initialisation happens before it is first needed (a bit like a singleton) but it means your compilation unit might need to contain something that is guaranteed to get pulled in.

If you want to "stick" to gnu or similar they provide __attribute__(constructor) which might resolve it although there is an easier way of having some dummy extern int implemented or dummy function that returns an int that gets called from within whatever header you do actually use to implement logging.

CashCow
  • 30,981
  • 5
  • 61
  • 92
  • I'm holding my downvote for now, but I believe this is incorrect. Global objects are created some time before the first function from its translation unit is called. That may well be _after_ `main` is called. – MSalters Sep 29 '14 at 11:53
  • I like it! @MSalters that's good to know. I don't necessarily need to start logging _before_ main is called; as long as I keep track of what compilation unit I put the global object in and make sure that we call something in that toward the beginning, we should be good, right? – bchurchill Sep 30 '14 at 07:47
  • @bchurchill: Yes, but there's often a better (less fragile) way: make the logger a `static` variable inside a `getLogger()` method which returns a reference to it. That constructs the logger when it's first needed. – MSalters Sep 30 '14 at 07:55
  • Awesome. Much better. – bchurchill Sep 30 '14 at 07:56