Forcing Construction of Global Objects in Static Libraries

Suppose you have a global object whose constructor does useful stuff – say, registration somewhere or initialization of global resources. Suppose further this object isn’t directly accessed anywhere – you just need the functionality in its ctor. All is fine, until we add the last assumption: suppose this object lies in a static library. This seems to be a long lasting pain, ultimately arising from the old (‘broken’? let’s just say ‘outdated’) C++ compiler-linker model. The way the linker works is by repeatedly searching for implementations of yet-unresolved referenced symbols, and including only the obj files with such implementations – thereby dropping entirely obj files with no external references, such as the one containing the global object whose ctor you need to run. To make things concrete, take the following toy example:

#include <tchar.h>

int _tmain(int argc, _TCHAR* argv[])
	return 0;

//GlobalInLib.cpp – compile as static lib
#include <stdio.h>
#include <tchar.h>

struct UsefulCtor
	UsefulCtor()  { _tprintf(_T("ThereIsNoSpoon")); }

UsefulCtor MyGlobalObj;

Under normal linkage, MyGlobalObj would be ignored. You can verify this either by putting a breakpoint in its constructor and see that it is never hit, or inspecting the output console window and see that it is empty. <Aside> An interesting discussion arose a while ago in MS forums on whether this behavior violates the standard. Here, einros writes:

The C++ standard, section 3.7.1, specifies: “If an object of static storage duration has initialization or a destructor with side effects, it shall not be eliminated even if it appears to be unused, […]”

But MS’ Holder Grund clarifies –

[Your quote of the standard] only holds if the corresponding translation unit is part of the program. In my definition and the one of at least four major toolchain implementators, it is not.

</Aside> Enter ‘Use Library Dependency Inputs’.

This arcane combo box in the project references dialog has the sole documented effect of enabling incremental linking for static libs, but the interesting part is how it does it:

When this property is set to Yes, the project system links in the .obj files for .libs produced by dependent projects, thus enabling incremental linking.

And indeed, setting this option to True causes construction of MyGlobalObj in the example above. Turns out you can force construction of globals in static libs after all.

Addendum: Only after writing this post did I come across this excellent 2005->2012 thread, which mentions this setting as a solution. Still, this effect of the linker is all but undocumented, and qualifies as deserving-more-web-presence.

This entry was posted in VC++. Bookmark the permalink.

5 Responses to Forcing Construction of Global Objects in Static Libraries

  1. Kevin Smyth says:

    There’s also /include which you can include as a pragma:

    __pragma(comment(linker, “/include:DecoratedName”))

    • Ofek Shilon says:

      The problem is, the #pragma must be coded at the *referencing* project: if it is coded in the referenced lib it will be ignored just like the rest of the object. This beats the whole ‘plug-and-play’ idea of a consumer exe who is unaware of the objects in the libs surrounding it.
      [Just to clarify – that is indeed the by-the-book approach, and the whole point of the use-lib-inputs hack is to fix its shortcomings. I should have mentioned it explicitly at the post.]

      • ttimot says:

        While I can confirm the “Use Library Dependency Inputs” solution works just fine, it seems __pragma *in the library* works too, at least in VC14.

        Interestingly, it didn’t work when placed in the same translation unit as the symbol I want to include, but it worked when placed in another .cpp file of that same static library. I’m not sure how much to trust this :)

  2. Anonymous says:

    This solution does not work with later versions of visual studio. At least not in 2017.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s