January 23, 2007
Todor Totev wrote:
>> Walter Bright wrote:
>>>   Try using enums instead of const variables, they don't take up any space in the object file.
>>
>> Thanks, but that makes only a dent in the overhead.
> 
> 
> Actually using enums instead of consts have a very nice side effect.
> Consider this declaration from win32:
> 
> HANDLE CreateFileW(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
> 
> Now, which invocation is correct?
> 
> CreateFile("a", OPEN_EXISTING, FILE_SHARE_READ, null, GENERIC_READ ...)
> or
> CreateFile("a", OPEN_EXISTING, GENERIC_READ, null, FILE_SHARE_READ ...)
> or even
> CreateFile("a", GENERIC_READ, OPEN_EXISTING, null, FILE_SHARE_READ ...)?
> 
> The compiler happily accepts all of them.
> 
> Using enums, we have:
> 
> enum FILE_SHARE {
>   READ  = 1,
>   WRITE = 2,
>   BOTH  = READ | WRITE
> }
> 
> enum DISPOSITION {
>   CREATE_ALWAYS = 1,
>   OPEN_EXISTING = 2
> }
> 
> void CreateFile(char[] fileName, DISPOSITION disposition, FILE_SHARE share) {}
> 
> int main() {
>   // compiler allows unknown flags
>   CreateFile("filename", cast(DISPOSITION)4, FILE_SHARE.READ);
> 
>   // when we swap the arguments by mistake
>   CreateFile("filename", FILE_SHARE.READ, DISPOSITION.CREATE_ALWAYS);
> 
>   return 0;
> }
> 
> This way if I make an error the compiler will very helpfully tell me
> what exactly is happening. Consider: CreateFont has 14 parameters,
> if the IDE does not help me i'd make an error when I use it, trust me
> 
> On the other hand, when a new version of Windows come with expanded options
> I can just use the new numbers without breaking anything while the d package is
> updated.
> 
> The dotnet framework uses enums and I really like the idea.

I agree that this is a great feature of D.  And if you're willing to adapt the Win32 headers to use this convention then I would gladly accept them :-)


Sean
January 23, 2007
> Certainly, and I think you'll find many who agree, along with some who can't bear to type a few extra characters :)
Yep

> But that's a different type of issue than the one we're facing. I wish you had a fix for that one :p
> No, nada, nein, не, όχι :-(
January 23, 2007
Sean Kelly wrote:
> As you can see, simply putting the Win32 object files into a library prior to linking reduced the application size by 51,100 bytes, but separate compilation had the same (bad) result as compiling all modules on one line.

I suggest linking with /MAP, which will generate a .map file listing all the modules linked in, and all the global symbols linked in. It's a lot easier to see what's happening with that than guessing based on the file size.
January 23, 2007
Walter Bright wrote:
> Sean Kelly wrote:
> 
>> As you can see, simply putting the Win32 object files into a library prior to linking reduced the application size by 51,100 bytes, but separate compilation had the same (bad) result as compiling all modules on one line.
> 
> 
> I suggest linking with /MAP, which will generate a .map file listing all the modules linked in, and all the global symbols linked in. It's a lot easier to see what's happening with that than guessing based on the file size.


Done that, Walter.

The difference is entirey Win32 struct inits, consts and so on. Remove the int consts, and you still have the struct inits ... almost enough to hand out at Christmas :)

What shall we do next?
January 24, 2007
Walter Bright wrote:
> Sean Kelly wrote:
>> As you can see, simply putting the Win32 object files into a library prior to linking reduced the application size by 51,100 bytes, but separate compilation had the same (bad) result as compiling all modules on one line.
> 
> I suggest linking with /MAP, which will generate a .map file listing all the modules linked in, and all the global symbols linked in. It's a lot easier to see what's happening with that than guessing based on the file size.

hello_small.map:

 Start         Length     Name                   Class
 0002:00000000 00011570H  _TEXT                  CODE 32-bit
 0002:00011570 00000198H  ICODE                  ICODE 32-bit
 0003:00000000 00000004H  .CRT$XIA               DATA 32-bit
 0003:00000010 00000004H  .CRT$XIZ               DATA 32-bit
 0003:00000020 00000004H  .CRT$XCA               DATA 32-bit
 0003:00000030 00000004H  .CRT$XCZ               DATA 32-bit
 0003:00000040 00000004H  .CRT$XPA               DATA 32-bit
 0003:00000050 00000004H  .CRT$XPZ               DATA 32-bit
 0003:00000060 00000004H  .CRT$XTA               DATA 32-bit
 0003:00000070 00000004H  .CRT$XTZ               DATA 32-bit
 0003:00000074 00000000H  IMP__DATA              IMP__DATA 32-bit
 0003:00000080 00005100H  _DATA                  DATA 32-bit
 0003:00005180 00000000H  FMB                    DATA 32-bit
 0003:00005180 00000024H  FM                     DATA 32-bit
 0003:000051A4 00000000H  FME                    DATA 32-bit
 0003:000051A4 00000000H  XIB                    DATA 32-bit
 0003:000051A4 0000001CH  XI                     DATA 32-bit
 0003:000051C0 00000000H  XIE                    DATA 32-bit
 0003:000051C0 00000000H  XCB                    DATA 32-bit
 0003:000051C0 00000014H  XC                     DATA 32-bit
 0003:000051D4 00000000H  XCE                    DATA 32-bit
 0003:000051D4 00000000H  XIFCB                  DATA 32-bit
 0003:000051D4 00000004H  XIFU                   DATA 32-bit
 0003:000051D8 00000000H  XIFL                   DATA 32-bit
 0003:000051D8 00000004H  XIFM                   DATA 32-bit
 0003:000051DC 00000000H  XIFCE                  DATA 32-bit
 0003:000051E0 00000000H  CONST                  CONST 32-bit
 0003:000051E0 00000000H  EEND                   ENDBSS 32-bit
 0003:000051E0 000016ECH  _BSS                   BSS 32-bit
 0003:000068CC 00000000H  XOB                    BSS 32-bit
 0003:000068CC 00000004H  XO                     BSS 32-bit
 0003:000068D0 00000000H  XOE                    BSS 32-bit
 0003:000068D0 00000000H  XOFB                   BSS 32-bit
 0003:000068D0 00000108H  XOF                    BSS 32-bit
 0003:000069D8 00000000H  XOFE                   BSS 32-bit
 0003:000069E0 00000419H  c_common               BSS 32-bit
 0003:00006E00 00000000H  STACK                  STACK 32-bit

Program entry point at 0000A2AC

--------------------------------------------------------------------------------

hello_large.map:

 Start         Length     Name                   Class
 0002:00000000 00011570H  _TEXT                  CODE 32-bit
 0002:00011570 00000198H  ICODE                  ICODE 32-bit
 0003:00000000 00000004H  .CRT$XIA               DATA 32-bit
 0003:00000010 00000004H  .CRT$XIZ               DATA 32-bit
 0003:00000020 00000004H  .CRT$XCA               DATA 32-bit
 0003:00000030 00000004H  .CRT$XCZ               DATA 32-bit
 0003:00000040 00000004H  .CRT$XPA               DATA 32-bit
 0003:00000050 00000004H  .CRT$XPZ               DATA 32-bit
 0003:00000060 00000004H  .CRT$XTA               DATA 32-bit
 0003:00000070 00000004H  .CRT$XTZ               DATA 32-bit
 0003:00000074 00000000H  IMP__DATA              IMP__DATA 32-bit
 0003:00000080 00011660H  _DATA                  DATA 32-bit
 0003:000116E0 00000000H  FMB                    DATA 32-bit
 0003:000116E0 00000024H  FM                     DATA 32-bit
 0003:00011704 00000000H  FME                    DATA 32-bit
 0003:00011704 00000000H  XIB                    DATA 32-bit
 0003:00011704 0000001CH  XI                     DATA 32-bit
 0003:00011720 00000000H  XIE                    DATA 32-bit
 0003:00011720 00000000H  XCB                    DATA 32-bit
 0003:00011720 00000014H  XC                     DATA 32-bit
 0003:00011734 00000000H  XCE                    DATA 32-bit
 0003:00011734 00000000H  XIFCB                  DATA 32-bit
 0003:00011734 00000004H  XIFU                   DATA 32-bit
 0003:00011738 00000000H  XIFL                   DATA 32-bit
 0003:00011738 00000004H  XIFM                   DATA 32-bit
 0003:0001173C 00000000H  XIFCE                  DATA 32-bit
 0003:00011740 00000000H  CONST                  CONST 32-bit
 0003:00011740 00000000H  EEND                   ENDBSS 32-bit
 0003:00011740 0000499CH  _BSS                   BSS 32-bit
 0003:000160DC 00000000H  XOB                    BSS 32-bit
 0003:000160DC 00000004H  XO                     BSS 32-bit
 0003:000160E0 00000000H  XOE                    BSS 32-bit
 0003:000160E0 00000000H  XOFB                   BSS 32-bit
 0003:000160E0 00000108H  XOF                    BSS 32-bit
 0003:000161E8 00000000H  XOFE                   BSS 32-bit
 0003:000161F0 00000419H  c_common               BSS 32-bit
 0003:00016610 00000000H  STACK                  STACK 32-bit

Program entry point at 0000A2AC
January 24, 2007
Sean Kelly wrote:
>> I suggest linking with /MAP, which will generate a .map file listing all the modules linked in, and all the global symbols linked in. It's a lot easier to see what's happening with that than guessing based on the file size.
> 
> hello_small.map:

Please be sure you are linking with the /MAP switch, as it will give all the symbols, not just the segments.
January 24, 2007
Walter Bright wrote:
> Sean Kelly wrote:
>>> I suggest linking with /MAP, which will generate a .map file listing all the modules linked in, and all the global symbols linked in. It's a lot easier to see what's happening with that than guessing based on the file size.
>>
>> hello_small.map:
> 
> Please be sure you are linking with the /MAP switch, as it will give all the symbols, not just the segments.

Oops, I missed the leading slash.  The output is obviously quite large so I'm just going to note some of the larger blocks that are present in hello_large.map that are missing from hello_small.map:

0003:0001172C   _D5tango3sys5win325Types10ACE_HEADER6__initZ 0042372C
...
0003:00002C08   _D5tango3sys5win325Types9cSTARTDOCi 00414C08


0003:00001074   _D5tango3sys5win325Types10RASCS_DONEi 00413074
...
0003:00014604   _D5tango3sys5win325Types10WINDOWINFO6__initZ 00426604

The first block goes from line 410 to line 6719 in the map file, and the second block goes from line 8047 to line 14559 in the map file.  All told, that's 12821 separate constants or initializers in the manually linked version that seem absent from the library-based version.
January 24, 2007
Sean Kelly wrote:
> The first block goes from line 410 to line 6719 in the map file, and the second block goes from line 8047 to line 14559 in the map file.  All told, that's 12821 separate constants or initializers in the manually linked version that seem absent from the library-based version.

That means that, in the library based version, nothing in the explicitly linked .obj files referenced them.

If you want to find out what reference is pulling in a particular library module, use lib to remove that library module, relink, and note the undefined reference.
January 24, 2007
Walter Bright wrote:
> Sean Kelly wrote:
>> The first block goes from line 410 to line 6719 in the map file, and the second block goes from line 8047 to line 14559 in the map file.  All told, that's 12821 separate constants or initializers in the manually linked version that seem absent from the library-based version.
> 
> That means that, in the library based version, nothing in the explicitly linked .obj files referenced them.

If that's true then nothing in either version referenced them.  The application is identical in both cases but for some of the objects living in a library in the small case.

> If you want to find out what reference is pulling in a particular library module, use lib to remove that library module, relink, and note the undefined reference.

See above.


Sean
January 24, 2007
Sean Kelly wrote:
> Todor Totev wrote:
>>> Walter Bright wrote:
>>>>   Try using enums instead of const variables, they don't take up any space in the object file.
>>>
>>> Thanks, but that makes only a dent in the overhead.
>>
>>
>> Actually using enums instead of consts have a very nice side effect.
>> Consider this declaration from win32:
>>
>> HANDLE CreateFileW(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
>>
>> Now, which invocation is correct?
>>
>> CreateFile("a", OPEN_EXISTING, FILE_SHARE_READ, null, GENERIC_READ ...)
>> or
>> CreateFile("a", OPEN_EXISTING, GENERIC_READ, null, FILE_SHARE_READ ...)
>> or even
>> CreateFile("a", GENERIC_READ, OPEN_EXISTING, null, FILE_SHARE_READ ...)?
>>
>> The compiler happily accepts all of them.
>>
>> Using enums, we have:
>>
>> enum FILE_SHARE {
>>   READ  = 1,
>>   WRITE = 2,
>>   BOTH  = READ | WRITE
>> }
>>
>> enum DISPOSITION {
>>   CREATE_ALWAYS = 1,
>>   OPEN_EXISTING = 2
>> }
>>
>> void CreateFile(char[] fileName, DISPOSITION disposition, FILE_SHARE share) {}
>>
>> int main() {
>>   // compiler allows unknown flags
>>   CreateFile("filename", cast(DISPOSITION)4, FILE_SHARE.READ);
>>
>>   // when we swap the arguments by mistake
>>   CreateFile("filename", FILE_SHARE.READ, DISPOSITION.CREATE_ALWAYS);
>>
>>   return 0;
>> }
>>
>> This way if I make an error the compiler will very helpfully tell me
>> what exactly is happening. Consider: CreateFont has 14 parameters,
>> if the IDE does not help me i'd make an error when I use it, trust me
>>
>> On the other hand, when a new version of Windows come with expanded options
>> I can just use the new numbers without breaking anything while the d package is
>> updated.
>>
>> The dotnet framework uses enums and I really like the idea.
> 
> I agree that this is a great feature of D.  And if you're willing to adapt the Win32 headers to use this convention then I would gladly accept them :-)
> 
> 
> Sean

As far as possible, we did that, for the ones that actually are enums. The problem is, most of those things aren't actually enums! They are complicated bitfields that get ORed together.