www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Default initializers (or: win32 bindings' struct sizes)

reply Lionello Lunesu <lio lunesu.remove.com> writes:
Hi,

Many structures in the win32 bindings project on dsource set their size 
using D's default initializer:

#struct STARTUPINFOA {





This does save some typing when in Win32 projects, but results in 
unexpected linker errors (dmd 1.0):

  Error 42: Symbol Undefined _D5win327winbase12STARTUPINFOA6__initZ

These errors can only be solved by
1) adding the appropriate .d files from the win32 folder on the command 
line, or
2) building a win32.lib (containing all initializers) and linking to it;
3) commenting out the "= ...sizeof;" part.

All of which seem inappropriate for a bindings project that merely 
contains translated headers.

One solution might be to add a version(..) around all default 
initializer, providing both an initialized and uninitialized version.

Another, far better, solution would be to change DMD: the compiler knows 
the initializer and can safely inline it. What's more, the there are no 
linker errors for the default built-in initializers:

struct S { int s; }    // no linker error
struct D { int d=0; }  // linker error!

The linking error occurs even with the -O -release -inline flags.

Why does DMD (I don't know about GDC) require that __init symbol for 
custom initializers and not for the default ones? Is there any chance 
that this requirement will be dropped?

L.
Jan 17 2007
parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Lionello Lunesu wrote:
 What's more, the there are no linker errors for the default built-in
initializers:
 
 struct S { int s; }    // no linker error
 struct D { int d=0; }  // linker error!
 
 The linking error occurs even with the -O -release -inline flags.
 
 Why does DMD (I don't know about GDC) require that __init symbol for 
 custom initializers and not for the default ones? Is there any chance 
 that this requirement will be dropped?
Actually, it's not (only) about custom initializers: ***** urxae urxae:~/tmp$ cat test.d import test2; import std.stdio; void main() { S s; writefln(cast(int)s.c); } urxae urxae:~/tmp$ cat test2.d struct S { char c; } urxae urxae:~/tmp$ dmd test.d gcc test.o -o test -m32 -lphobos -lpthread -lm -Xlinker -L/home/urxae/opt/dmd/lib test.o: In function `_Dmain': test.d:(.gnu.linkonce.t_Dmain+0x7): undefined reference to `_D5test21S6__initZ' collect2: ld returned 1 exit status --- errorlevel 1 ***** (Similarly fails for wchar, dchar, float, double and real) It looks to be about everything but *all-zero* default initializers. Those seem to be the only ones not to need explicit initializers to be generated if the type is used as a local variable. Their initialization is inlined. For some reason the inlining doesn't happen for explicitly zero-initialized variables, nor for non-zero or non-default initializers. This despite the fact that global/static variables seem to get the initializer "inlined" into the '.data' or (if all-zero) '.bss' section[1]. So it's not that the compiler doesn't know what the initializers should be, it's that the code generated to initialize local variables at run-time depends on the initializer data being generated by compilation of the imported module if it's either non-default or not all-zero. Preventing your link error would be a simple matter of treating initializer symbols similar to templates: put them in link-once sections in every object file where they're needed. Not that I'm saying this should necessarily be done; I'm just saying it should be relatively simple to implement. [1]: At least, those are the names on Linux (and anywhere else that uses ELF binaries, for that matter). Not sure what they are on Windows, but the principle should be similar.
Jan 17 2007