Troubles with compiling, static initialization and static libraries

92 views Asked by At

I have recently encountered a behavior in C++ program that I cannot entirely understand. Let me explain the behavior via simple example.

1. First static library

At the very bottom of hierarchy, I have a static library - lets name it FirstLIB. This library includes two pairs of header/source files. The sample.h header file contains MyClass class definition. Corresponding sample.cpp file contains implementation of this class (its methods). The code is presented below:

sample.h

#ifndef __sample_h
#define  __sample_h

namespace SampleNamespace
{
    class MyClass
    {
        int counter;

    public:
        MyClass();
        int GetCounter();
        void SetCounter(int value);
    };
}

#endif

and sample.cpp

#include <iostream>
#include "sample.h"

namespace SampleNamespace
{
    MyClass::MyClass(): counter(0)
    {
        std::cout << "Inside of MyClass constructor!" << std::endl;
    }

    int MyClass::GetCounter() { return counter; }
    void MyClass::SetCounter(int value) { counter = value; }
}

Onwards, the dvcl.h file declares simple API used to manipulate MyClass object and dvcl.cpp implements this API. It's important to notice that dvcl.cpp file contains definition of MyClass object that is used by the methods of this API. The variable is defines as static so it will be visible only inside of this source file.

dvcl.h

#ifndef _dvcl_h
#define _dvcl_h

void DVCL_Initialize(int counter);
int DVCL_GetCounter();
void DVCL_SetCounter(int value);

#endif

dvcl.cpp

#include "dvcl.h"
#include "sample.h"

static SampleNamespace::MyClass myClass;

void DVCL_Initialize(int counter)
{
    myClass.SetCounter(counter);
}
int DVCL_GetCounter()
{
    return myClass.GetCounter();
}
void DVCL_SetCounter(int value)
{
    myClass.SetCounter(value);
}

2. Second static library

Second static library - lets name it SecondLIB - is even simpler than the first one. It only contains one header/source pair. The dvconference_client.h header declares one function, while dvconference_client.cpp implements this function. dvconference_client.cpp also includes dvcl.h header file (which will trigger compilation of dvcl.cpp source). The code can be found below:

dvconference_client.h

#ifndef __external_file
#define __external_file

int DoSomething();

#endif

dvconference.cpp

#include "dvconference_client.h"
#include "dvcl.h"

int DoSomething()
{
    return DVCL_GetCounter();
}

3. Main executable

And finally, the main executable MainEXE includes only one main.cpp file. This source includes dvconference_client.h and dvcl.h headers. The code is presented below:

#include <iostream>
#include "dvconference_client.h"
#include "dvcl.h"

int main()
{
    std::cout << DoSomething() << std::endl;
    std::cout << DVCL_GetCounter() << std::endl;
    return 0;
}

4. My doubts and questions:

  • If I don't call a function that references myClass object (so DoSomething() or one of DVCL_ functions), the MyClass constructor is not invoked. I expected that myClass object will be instantiated by default as dvcl.cpp is compiled. However, it appears that compiler generates needed statements only if it understand that object is actually used in runtime. Is this really true?
  • If particular header file (in this case dvcl.h) is included in different sources, the corresponding dvcl.cpp is compiled only once. I remember reading something about this, however I'm not sure that this is really true. Is it actually correct that C++ compiler will compile every source file only once, regardless of how many the corresponding header file is included.
  • myClass object defined in dvcl.cpp is instantiated only once. If I correctly understand the 2nd point and if dvcl.cpp is compiled only once, then there is nothing to question here.

I hope more experienced colleagues can clear my doubts (and I apologize for very long post).

2

There are 2 answers

0
Manish Goel On BEST ANSWER
  1. "static SampleNamespace::MyClass myClass; " is both a declaration and definition. So your constructor is invoked and created. Asm-code to instantiate this is generated at compile-time but this is executed at executable-load-time.

For referenec, stages of compilation source-code --> pre-processing --> compilation --> linking --> loading --> execution

  1. Yes, ".c/.cpp" file are compiled only once. But header are parsed per inclusion.

  2. Yes object is executed only once because corresponding object-file is linked and loaded only once.

0
Serge Ballesta On

First point :

dvcl compilation unit is in a static library. If the code is not used, the compiled object (.o) is not included in resulting executable. As such, static SampleNamespace::MyClass myClass; is never executed. It won't be the same if you were using a dynamic library or explicitely linking the .o file at link time.

Second point :

Use you or not libraries, a source file (.c) or (.cpp) is only compiled (and linked into the executable) once. That's the reason for having .h files that are included in other files and as such processed one time per including file

Third point :

The object is effectively instantiated once, since the .o file is linked only once