Search code examples
c++visual-c++linkerg++dead-code

selectively disable dead code elimination in a library


I have many cpp files, some of which have functions to self-subscribe to events. Unfortunately, most linkers will eliminate all symbols from compilation units if there is no apparent function call into them. Is there a way to force linking of these subscription functions? I do not want to disable dead code stripping entirely, because I might miss a lot of opportunities from the other translation units.

Subscriber.cpp:

Event &someEvent();

void doSomething()
{
  printf("doing something\n");
}

class Initializer
{
  public: Initializer()
  {
    // I need this function to be kept
    someEvent().subscribe(&doSomething);
  }
} initializer;

Main.cpp:

Event &someEvent();

int main()
{
  someEvent().dispatch();
}

Thanks

EDIT:

Here is a repro build: https://github.com/malytomas/deadCodeElimination (Thanks Ayjay for help, even if his/her example does not reproduce the problem.)

The problem happens only with libraries. (Thanks Employed Russian for bringing this up.)


Solution

  • Unfortunately, most linkers will eliminate all symbols from compilation units if there is no apparent function call into them.

    You are mistaken: a linker that would do that would be a broken linker. Linkers do not garbage-collect code that registers global constructors or destructors.

    What most likely happens is that your object files aren't even selected into the link (not pulled from archive libraries) in the first place. This post has a good explanation of the algorithm many linkers use to determine what is and isn't selected.

    Update:

    Now that we can see a repro, your actual question has nothing to do with dead code elimination. As I suspected, subscriber.o is simply not pulled in from libsubscriber.a, because the linker finds no reason to do so.

    Here is the actual link command:

    /usr/bin/c++ -rdynamic CMakeFiles/main.dir/main.cpp.o  -o main libsubscriber.a
    

    Here is the command you want to have:

    /usr/bin/c++ -rdynamic CMakeFiles/main.dir/main.cpp.o  -o main \
      -Wl,--whole-archive libsubscriber.a -Wl,--nowhole-archive
    

    I don't know how to achieve that with CMake, sorry.

    Alternatively, you could also achieve desired effect with:

    /usr/bin/c++ -rdynamic CMakeFiles/main.dir/main.cpp.o  -o main \
     -u _Z19forceLinkSubscriberv libsubscriber.a