Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Global and file-static variables in static library

68 views
Skip to first unread message

David Wilkinson

unread,
Jul 13, 2007, 7:34:36 AM7/13/07
to
In some code I wrote for a client, I use the "self-registering plugin
pattern:

// D1.h

class D1: public Base
{
public:
D1();
// declare virtual overrides
};

//--------------------------------------------------

// D1.cpp

#include "D1.h"

namespace
{
Base* Create(){return new D1;}
bool auto_register = RegisterPlugin("D1", Create);
}

D1::D1(){}
// virtual function definitions for D1

//--------------------------------------------------

The function RegisterPlugin() creates an entry in a map of strings to
function pointers, which allows a factory function to create an instance
of the plugin D1 from its name "D1". The key feature of the pattern is
that the file D1.h is not #include'd anywhere except D1.cpp. It works
despite the fact that the code in D1.cpp is superficially not used by
the rest of the program. It works on VC7.1 and VC8 and various
unix/linux compilers.

Recently, however, using VC8, the client got it into his head to compile
my code into a static library (.lib) before linking it to his code. And
now the pattern does not work any more (the map is not populated).

Initially I thought this might be because I placed the code in an
anonymous namespace ("file-static"), but the same thing happens if I
make auto_register a global variable (using a different name for each
plugin).

It seems that when a .obj file is embedded in a static library, and then
linked with a client program such that the content of that .obj is
apparently unused, the content of that .obj file is not contained in the
image. This does not happen if the .obj files are linked individually.

Why does this happen? And what should I do about it? [I have found a
couple of workarounds, but they require explicit reference to something
in the plugin implementation, which rather spoils the beauty of the
pattern.]

--
David Wilkinson
Visual C++ MVP

Alex Blekhman

unread,
Jul 13, 2007, 9:06:19 AM7/13/07
to
"David Wilkinson" wrote:
> [...]

> Recently, however, using VC8, the client got it into his
> head to compile my code into a static library (.lib)
> before linking it to his code. And now the pattern does
> not work any more (the map is not populated).

It seems that there is no other way besides referencing `D1'
in some other translation unit. Here's description of the
problem:

"Constructors of global objects in static library are not
called"
http://groups.google.com/group/microsoft.public.vc.language/msg/e8e2eda4531eefa8

Alex

Giovanni Dicanio

unread,
Jul 13, 2007, 9:18:59 AM7/13/07
to

"David Wilkinson" <no-r...@effisols.com> ha scritto nel messaggio
news:e9A6EHUx...@TK2MSFTNGP04.phx.gbl...

> namespace
> {
> Base* Create(){return new D1;}
> bool auto_register = RegisterPlugin("D1", Create);
> }

> Initially I thought this might be because I placed the code in an

> anonymous namespace ("file-static"), but the same thing happens if I make
> auto_register a global variable (using a different name for each plugin).

David: just for test: could you try this:

static bool auto_register = RegisterPlugin....

using the 'static' keyword?

Giov


David Wilkinson

unread,
Jul 13, 2007, 9:55:19 AM7/13/07
to

Giov:

It does not seem to make any difference: anonymous namespace,
file-static or global, none of them get initialized when the file is an
a static library and nothing in the file is directly referenced.

It just seems that when .obj files are in a static library, the linker
eliminates stuff more aggressively than when they are stand-alone. This
is reasonable perhaps, because otherwise a static library might
contribute a lot of dead code. But it is a real PITA. What is needed,
perhaps, is some kind of FORCE keyword in the language that requires a
variable or class object to be initialized before main(), which seems to
be the default in all known compilers in the absence of static libraries
(though not, it seems, required by the standard).

Ben Voigt [C++ MVP]

unread,
Jul 13, 2007, 5:04:39 PM7/13/07
to

> It just seems that when .obj files are in a static library, the linker
> eliminates stuff more aggressively than when they are stand-alone. This
> is reasonable perhaps, because otherwise a static library might
> contribute a lot of dead code. But it is a real PITA. What is needed,
> perhaps, is some kind of FORCE keyword in the language that requires a
> variable or class object to be initialized before main(), which seems to
> be the default in all known compilers in the absence of static libraries
> (though not, it seems, required by the standard).

Have you tried:

#pragma comment(linker, "/include:__mySymbol")

as mentioned in http://msdn2.microsoft.com/en-us/library/ms879989.aspx

Carl Daniel [VC++ MVP]

unread,
Jul 13, 2007, 5:47:33 PM7/13/07
to
"Ben Voigt [C++ MVP]" <r...@nospam.nospam> wrote in message
news:247E1A1D-8059-479C...@microsoft.com...

... and not that to use this neat trick, you need to supply the mangled C++
name for the symbol. you can avoid that by including an extern "C" function
in the same module, and reference that function (with it's relatively
unmangled name) instead of your anonymous namespace scoped variable (which
will have a truly awful name).

Something like this:

// D1.h
#pragma comment(linker,"/include: _InitD")

class D1: public Base
{
public:
D1();
// declare virtual overrides
};

//--------------------------------------------------

// D1.cpp

#include "D1.h"

namespace


{
Base* Create(){return new D1;}
bool auto_register = RegisterPlugin("D1", Create);
}

D1::D1(){}


// virtual function definitions for D1

extern "C" __cdecl InitD()
{
}

-cd


David Wilkinson

unread,
Jul 13, 2007, 6:44:42 PM7/13/07
to
Carl Daniel [VC++ MVP] wrote:

> ... and not that to use this neat trick, you need to supply the mangled C++
> name for the symbol. you can avoid that by including an extern "C" function
> in the same module, and reference that function (with it's relatively
> unmangled name) instead of your anonymous namespace scoped variable (which
> will have a truly awful name).
>
> Something like this:
>
> // D1.h
> #pragma comment(linker,"/include: _InitD")
>
> class D1: public Base
> {
> public:
> D1();
> // declare virtual overrides
> };
>
> //--------------------------------------------------
>
> // D1.cpp
>
> #include "D1.h"
>
> namespace
> {
> Base* Create(){return new D1;}
> bool auto_register = RegisterPlugin("D1", Create);
> }
>
> D1::D1(){}
> // virtual function definitions for D1
>
> extern "C" __cdecl InitD()
> {
> }

Thanks Ben/Carl:

I would prefer a portable solution, because this is cross-platform code,
but the immediate problem is on VC, and this solves it there.

I had been working with ideas that involved calling a function that was
defined in D1.cpp, and had realized that this could be done without
including D1.h (by simply replicating the declaration). But of course
this call has to be placed in code that I know will be linked.

By contrast the #pragma trick can be used in D1.h (or D1.cpp) so the
plugin is truly self-registering again (thanks Carl for pointing this
out to me).

0 new messages