3

I have a static library which is generated from many cpp files on linux using g++. one header file contains a class which implements factory pattern

pseudo code in the header file as below

class Factory
{
public:
    static Factory& instance();
    Base * create(const std::string& name);
    template<class T>
      void register_class(const std::string& name);
}

template <class T>
class FactoryRegister
{
public:
    FactoryRegister(const std::string& name)
    {
       Factory::instance().register_class<T>(name);
    }
}

cpp file for Factory has the implementations. in another cpp file Derive.cpp, there is a class that I want to register into Factory. and I defined a global variable to do this. code as below

FactoryRegister<Derive> g_register_derive("derive");

all these files are compiled into one static library and is linked to one executable.

my understanding is that as the g_register_derive is not referenced by any code, it shouldn't be linked into the executable unless whole-archive option is provided.

the strange part is that if I put g_register_derive in Derive.cpp, it's true that this symbol is not linked into the executable. but if I put g_register_derive in Factory.cpp, it got linked into executable.

I used nm to verify the result, and there is also a line of code calls Factory::instance().create("Derive") which can also be used to check if g_register_derive is linked or not.

and of course if I provided whole-archive option, g_register_derive will always be linked into the executable.

jww
  • 97,681
  • 90
  • 411
  • 885
Lei Yu
  • 199
  • 9

1 Answers1

2

See the Stackoverflow tag wiki about static-libraries to understand linkage with static libraries, especially the fact that by default, an object file libx.a(p.o) in a static library is extracted and linked into a program only if the linker needs it.

If the linker needs to link an archive member libx.a(p.o) in order to resolve some prior reference to a symbol foo that is defined in that object file, then the definition of any other symbol bar that is also defined in libx.a(p.o) is also linked into the program - because it is part of that object file - whether bar is referenced by the program or not.

So, if you define g_register_derive in source file p.cpp which is compiled to p.o and archived as libx.a(p.o), and your application needs to link libx.a(p.o) for any reason, then by default1 g_register_derive becomes defined in your program.

If you move the definition of g_register_derive to q.cpp, which is compiled and archived as libx.a(q.o), and your application does not need to link libx.a(q.o) for any reason, then g_register_derive is not defined in your program.


[1] With non-default compilation and linkage options, you can remove definitions of unused symbols from your program. See How to remove unused C/C++ symbols with GCC and ld? and the accepted answer.

Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182