Carl Daniel [VC++ MVP] wrote:
Jesper Schmidt wrote:
On Oct 21, 2:29 am, "Jesper Schmidt" <schmi...@gmail.comwrote:
When does CLR performs initialization of static variables in a class
library?
(1) when the class library is loaded
(2) when a static variable is first referenced
(3) when...
It seems that (1) holds for unmanaged C++ code, but not for managed
code. I have class library with both managed and unmanaged static
variables that are not referenced by any part of the program. All the
unmanaged variables are initialized when the library is loaded, but
the constructors for the managed variables are never called. This is
problem because these constructors must be called in order to
initialize the application properly. Is there a way to trigger the
initialization of static variables in a class library?
I have done some further investigation into my problem with the
missing initialization of unreferenced static variables in a class
library. Out of desperation, I tried to add the source code directly
to the project, which generates the final executable, and then
suddenly everything worked including the new .NET functionality I
have added. Thank you, Microsoft, for making the excellent .NET
framework available to us C++ programmers. C++/CLI is great! Below is
the stack trace that initiated the initialization of the managed
static variables.
_initterm_m(void*** pfbegin = 0x004051A4, pfend = error: cannot
obtain value)
<CrtImplementationDetails>::LanguageSupport::Initi alizePerProcess()
<CrtImplementationDetails>::LanguageSupport::_Init ialize()
<CrtImplementationDetails>::LanguageSupport::Initi alize()
.cctor@@$$FYMXXZ()
Can anybody tell me why the code should work any differently when it
is loaded as a class library or even better does anybody know how I
move the code back into the class library again without loosing the
initialization of the static variables?
First thing I'd check - was the definition of the static variables and the
code that initializes them even included in the DLL? More than likely, the
linker simply left it out, since it's not referenced. In general, you have
to force a reference to something to be guaranteed that it's included in the
linked image.
I have thought of this, but I do not think that this is the problem.
First, I have tried to switch on the "Keep Unreferenced Data
(/OPT:NOREF)" option to the linker and it made no difference. Secondly,
I can see the unreferenced symbol '*halo_unit_test_28' in the IL
disassembly (see below).
***************************************
..field static assembly method void *()
'?A0xfabd948e.halo_unit_test_28$initializer$' at D_00024424
..field static assembly valuetype
halo.unit_test.'test_case<halo::serialization::dot net::stream_obuffer_test>'
'?A0xfabd948e.halo_unit_test_28' at D_000369BC
..method assembly static void
'?A0xfabd948e.??__E?A0xfabd948e@halo_unit_test_28@ @YMXXZ'() cil managed
{
.vtentry 30 : 1
// Code size 36 (0x24)
.maxstack 4
IL_0000: ldsflda valuetype
halo.unit_test.'test_case<halo::serialization::dot net::stream_obuffer_test>'
'?A0xfabd948e.halo_unit_test_28'
IL_0005: ldsflda valuetype
'<CppImplementationDetails>'.$ArrayType$$$BY0DB@$$ CBD
modopt([mscorlib]System.Runtime.CompilerServices.IsConst)
'?A0xfabd948e.unnamed-global-2'
IL_000a: ldsflda valuetype
'<CppImplementationDetails>'.$ArrayType$$$BY0DN@$$ CBD
modopt([mscorlib]System.Runtime.CompilerServices.IsConst)
'?A0xfabd948e.unnamed-global-1'
IL_000f: ldc.i4.s 28
IL_0011: call valuetype
halo.unit_test.'test_case<halo::serialization::dot net::stream_obuffer_test>'*
modopt([mscorlib]System.Runtime.CompilerServices.CallConvThiscall)
'halo.unit_test.test_case<halo::serialization::dot net::stream_obuffer_test>.{ctor}'(valuetype
halo.unit_test.'test_case<halo::serialization::dot net::stream_obuffer_test>'*
modopt([mscorlib]System.Runtime.CompilerServices.IsConst)
modopt([mscorlib]System.Runtime.CompilerServices.IsConst),
int8
modopt([mscorlib]System.Runtime.CompilerServices.IsSignUnspecifiedB yte)
modopt([mscorlib]System.Runtime.CompilerServices.IsConst)*,
int8
modopt([mscorlib]System.Runtime.CompilerServices.IsSignUnspecifiedB yte)
modopt([mscorlib]System.Runtime.CompilerServices.IsConst)*,
int32)
IL_0016: pop
IL_0017: ldftn void
'?A0xfabd948e.??__F?A0xfabd948e@halo_unit_test_28@ @YMXXZ'()
IL_001d: call int32 _atexit_m(method void *())
IL_0022: pop
IL_0023: ret
} // end of global method
'?A0xfabd948e.??__E?A0xfabd948e@halo_unit_test_28@ @YMXXZ'
..method assembly static void
'?A0xfabd948e.??__F?A0xfabd948e@halo_unit_test_28@ @YMXXZ'() cil managed
{
.vtentry 29 : 1
// Code size 11 (0xb)
.maxstack 1
IL_0000: ldsflda valuetype
halo.unit_test.'test_case<halo::serialization::dot net::stream_obuffer_test>'
'?A0xfabd948e.halo_unit_test_28'
IL_0005: call void
modopt([mscorlib]System.Runtime.CompilerServices.CallConvThiscall)
'halo.unit_test.test_case<halo::serialization::dot net::stream_obuffer_test>.{dtor}'(valuetype
halo.unit_test.'test_case<halo::serialization::dot net::stream_obuffer_test>'*
modopt([mscorlib]System.Runtime.CompilerServices.IsConst)
modopt([mscorlib]System.Runtime.CompilerServices.IsConst))
IL_000a: ret
} // end of global method
'?A0xfabd948e.??__F?A0xfabd948e@halo_unit_test_28@ @YMXXZ'
***************************************
To me it looks as if the compiler has emitted the code that does the
initialization, but for some reason this code is not called when the
class library is loaded. Do CLR defer the initialization until the
symbol is referenced? If so, how do I explicitly trigger this
initialization without referring to the symbol itself?
--
Jesper