15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


How to Slim MFC applications ?

Raja Segar -- rsz@pc.jaring.my
Thursday, November 28, 1996

Environment : VC++ 4.2b Patched, Win95, NT 4.0

What is the resolution power of the Visual C++ compiler ?
Is is resolved to the function level or class level?
Example :
  Let's say i included CString in my project and
  used only the + overloaded operator and the dynamic
  capabilities of the class, will all the other function
  in the class such as GetLength,  SetAt, MakeLower etc.etc
  be included in the final exe or just the ones referenced
  in the program.

If for example all the function in a class are included in
the EXE , is it advisable to overide the unused function to
a blank function. 

Example:
      Let's say i have class CMyClass and i did not utilise
a very big function in that class called BigFunc() can we
save space on the final EXE by overiding it as follow :-
 
  class DerivedClass: public CMyClass    
   ... 
   ...

  DerivedClass::BigFunc()
  {
    return;  
  }         
     
   
Any other tips on minimizing the size of a MFC application ? 
Thanks in advance for any reponds to this question.
Bye.
           
 (  _ \/ __)(_   )
  )   /\__ \ / /_ 
 (_)\_)(___/(____)@pc.jaring.my




Ken Nicolson -- kenn@owl.co.uk
Monday, December 02, 1996

On Thu, 28 Nov 1996 20:10:00 +0800, you wrote:

>Environment : VC++ 4.2b Patched, Win95, NT 4.0
>
>What is the resolution power of the Visual C++ compiler ?
>Is is resolved to the function level or class level?

I'm not 100% sure what you mean, but if you are referring to the compiler
option "Enable function level linking", it says something to the effect
that all C++ member functions are "automatically packaged", therefore
linking with /OPT:REF will exclude these unused packaged functions.

Similarly the linker will (at least I certainly hope it does!) only =
include
*referenced* functions and classes from libraries.

>Example :
>  Let's say i included CString in my project and
>  used only the + overloaded operator and the dynamic
>  capabilities of the class, will all the other function
>  in the class such as GetLength,  SetAt, MakeLower etc.etc
>  be included in the final exe or just the ones referenced
>  in the program.

These functions you mention may very well be used from elsewhere within =
the
MFC libraries, so even though you don't directly use them, they may still
be needed.

>If for example all the function in a class are included in
>the EXE , is it advisable to overide the unused function to
>a blank function.=20
>
>Example:
>      Let's say i have class CMyClass and i did not utilise
>a very big function in that class called BigFunc() can we
>save space on the final EXE by overiding it as follow :-
>=20
>  class DerivedClass: public CMyClass   =20
>   ...=20
>   ...
>
>  DerivedClass::BigFunc()
>  {
>    return; =20
>  }        =20

I'm not sure where you get the idea that this may help! If your code =
calls
CMyClass::BigFunc() it will be linked in, if it doesn't, it won't. Doing
the above can only *increase* code size!

>Any other tips on minimizing the size of a MFC application ?=20

The most obvious one is to dynamically link with the MFC DLLs, especially
if you have a suite of apps, so you only need to ship the DLLs once.

Most of the code bloat can be reduced by rewriting or redesigning the app
with more reusable routines, or redesign the class hierarchy to move more
functionality into base classes.

The current app I am working on is pretty fat, but it's not the MFC's
fault, as it always seems easier at the time to cut-and-paste a similar
routine than to spend the few extra minutes (or hours) to produce one
common routine.

>Thanks in advance for any reponds to this question.
>Bye.
>          =20
> (  _ \/ __)(_   )
>  )   /\__ \ / /_=20
> (_)\_)(___/(____)@pc.jaring.my

Ken



Dave_Rabbers@Quinton-Eng.CCMAIL.CompuServe.COM
Monday, December 02, 1996

If you want to make your exe or dll slim, why not use the DLL versions 
of MFC.  Dynamically link to MFC rather than statically linking.  Then 
you will not be including much MFC code in your exe or dll.

To answer your question, the linker appears to me to resolve to the 
object module level (.obj file).  This corresponds to the source file 
level when comparing against the MFC source.  Notice I said "appears 
to me" because I lack first hand knowledge.  If you want to see 
exactly what has been included, generate a .map file from the linker.

Most C++ source code I've seen, and all the MFC source code, 
implements a C++ class completely within a single .h and .cpp file, 
and may implement multiple classes within any one .cpp file.  Thus, 
any use of a class automatically appears to include all methods of 
that class within the link.  Again, look at the .map file.


______________________________ Reply Separator _________________________________
Subject: How to Slim MFC applications ?
Author:  INTERNET:rsz@pc.jaring.my at CSERVE
Date:    11/30/96 3:53 PM


Sender: owner-mfc-l@majordomo.netcom.com
Received: from majordomo.netcom.com (listless.netcom.com [206.217.29.105]) by 
dub-img-3.compuserve.com (8.6.10/5.950515)
     id OAA11170; Sat, 30 Nov 1996 14:50:24 -0500
Received: by majordomo.netcom.com (8.7.5/8.7.3/(NETCOM MLS v1.01)) id 
JAA09450; Sat, 30 Nov 1996 09:56:31 -0800 (PST)
Date: Thu, 28 Nov 1996 20:10:00 +0800
Message-Id: <199611281210.UAA23382@relay5.jaring.my> 
X-Sender: rsz@pop5.jaring.my
X-Mailer: Windows Eudora Pro Version 2.1.2 
Mime-Version: 1.0
Content-Type: text/plain; charset="us-ascii" 
To: mfc-l@netcom.com
From: Raja Segar 
Subject: How to Slim MFC applications ? 
Sender: owner-mfc-l@majordomo.netcom.com 
Errors-To: owner-mfc-l@majordomo.netcom.com 
Precedence: bulk
Reply-To: mfc-l@netcom.com

Environment : VC++ 4.2b Patched, Win95, NT 4.0

What is the resolution power of the Visual C++ compiler ? 
Is is resolved to the function level or class level? 
Example :
  Let's say i included CString in my project and
  used only the + overloaded operator and the dynamic 
  capabilities of the class, will all the other function
  in the class such as GetLength,  SetAt, MakeLower etc.etc 
  be included in the final exe or just the ones referenced 
  in the program.

If for example all the function in a class are included in 
the EXE , is it advisable to overide the unused function to 
a blank function.

Example:
      Let's say i have class CMyClass and i did not utilise
a very big function in that class called BigFunc() can we 
save space on the final EXE by overiding it as follow :-

  class DerivedClass: public CMyClass
   ...
   ...

  DerivedClass::BigFunc()
  {
    return;
  }


Any other tips on minimizing the size of a MFC application ? 
Thanks in advance for any reponds to this question.
Bye.

 (  _ \/ __)(_   )
  )   /\__ \ / /_
 (_)\_)(___/(____)@pc.jaring.my




P. Senthil -- senthilp@geocities.com
Tuesday, December 03, 1996

I guess one of the trade-offs in Object oriented programming is size
versus maintenance of code (and all other advantages of OOPS). Using
inheritance, the base classes code remains whether we use it or not.
Unless maybe if it was pure virtual. In using Application frameworks,
the size of the final executable is huge that is if you statically link
the MFC classes. So the only way to reduce size is to use MFC as a
shared library.

Another tip is to avoid having a class like CMyDialog which are derived
from MFC's CDialog to serve as a base class for other Dialog classes.
But this obviously rules against productivity which can be achieved by
having commonalities put in a base class. I think you should have got
the point by now.

Raja Segar wrote:
> 
>                            Postage paid by:
>                                [Image]
>                          Your Home on the Web!
> 
>     ---------------------------------------------------------------
> 
> Environment : VC++ 4.2b Patched, Win95, NT 4.0
> 
> What is the resolution power of the Visual C++ compiler ?
> Is is resolved to the function level or class level?
> Example :
>   Let's say i included CString in my project and
>   used only the + overloaded operator and the dynamic
>   capabilities of the class, will all the other function
>   in the class such as GetLength,  SetAt, MakeLower etc.etc
>   be included in the final exe or just the ones referenced
>   in the program.
> 
> If for example all the function in a class are included in
> the EXE , is it advisable to overide the unused function to
> a blank function.
> 
> Example:
>       Let's say i have class CMyClass and i did not utilise
> a very big function in that class called BigFunc() can we
> save space on the final EXE by overiding it as follow :-
> 
>   class DerivedClass: public CMyClass
>    ...
>    ...
> 
>   DerivedClass::BigFunc()
>   {
>     return;
>   }
> 
> 
> Any other tips on minimizing the size of a MFC application ?
> Thanks in advance for any reponds to this question.
> Bye.
> 
>  (  _ \/ __)(_   )
>   )   /\__ \ / /_
>  (_)\_)(___/(____)@pc.jaring.my
-- 
P. Senthil
-----------------------------------------------------------------------
1, 7th Avenue (West),
7th Main Road,
Dhandeeswaram Nagar,
Velachery,
MADRAS - 600 042.

Mail:  senthilp@geocities.com

Homepage: www.geocities.com/SiliconValley/Heights/6504



Arthur H. Warren -- awarren@jws.com
Wednesday, December 04, 1996

[Mini-digest: 4 responses]

>Dave_Rabbers@Quinton-Eng.CCMAIL.CompuServe.COM:
>To answer your question, the linker appears to me to resolve to the 
>object module level (.obj file).  This corresponds to the source file 
>level when comparing against the MFC source.

You can use compiler option /Gy and linker option /OPT:REF to enable
function-level linking. This should allow the linker to discard unused
functions from the executable & reduce its size. 

MAP files generated by previous versions of the linker used to indicated
which functions were unused so that you could remove them from the final
release build if you really wanted/needed to do so. 
 ________________________________________________________________________
 Herb Warren - Junior G-Man, Rocket Scientist.  AM/FM/GIS Services
 James W Sewall Company                         Voice:  207-827-4456
 147 Center Street                              Fax:    207-827-3641
 Old Town, Maine 04468                          Email:  awarren@jws.com
_________________________________________________________________________
-----From: Mike Blaszczak 

At 14:13 12/2/96 EST, Dave_Rabbers@Quinton-Eng.CCMAIL.CompuServe.COM wrote:

>To answer your question, the linker appears to me to resolve to the 
>object module level (.obj file).  This corresponds to the source file 
>level when comparing against the MFC source.  Notice I said "appears 
>to me" because I lack first hand knowledge.  If you want to see 
>exactly what has been included, generate a .map file from the linker.

The linker can resolve to the function- or datum-reference level.
See the online documentation for the /Gy compiler option, and the
linker's /OPT:REF option.

>Most C++ source code I've seen, and all the MFC source code, 
>implements a C++ class completely within a single .h and .cpp file, 

This is wrong: I can't think of any non-implementation MFC-provided
that _is_ implemented within a single CPP file.  Even CString is split
over two files!

.B ekiM
http://www.nwlink.com/~mikeblas/
I'm afraid I've become some sort of speed freak.
These words are my own. I do not speak on behalf of Microsoft.

-----From: Mike Blaszczak 

At 17:18 12/3/96 +0530, P. Senthil wrote:
>I guess one of the trade-offs in Object oriented programming is size
>versus maintenance of code (and all other advantages of OOPS). Using
>inheritance, the base classes code remains whether we use it or not.

That isn't true.  It's very simple to cook up an example that shows
it isn't true.  If you've got Visual C++ 4.2, try using 

  cl /Gy thisfile.cpp /link /OPT:REF /map

at the command line to compile this program:

-- CLIP AND SAVE -- CLIP AND SAVE -- CLIP AND SAVE --

volatile int x = 0;

////////////////////////////////////////////////////////////////////////
// class CFoo implementation

class CFoo
{
public:
   CFoo();
   ~CFoo();

   void DoSomething();
   void NeverUsed();
};

CFoo::CFoo()
{
   x = 1;
}

CFoo::~CFoo()
{
   x = 2;
}

void CFoo::NeverUsed()
{
   x = -1;
}

void CFoo::DoSomething()
{
   x = 3;   
}

////////////////////////////////////////////////////////////////////////
// class CBar implementation

class CBar : public CFoo
{
public:
   CBar();
   ~CBar();

   void DoSomething();
};

CBar::CBar()
{
   x = 4;
}

CBar::~CBar()
{
   x = 5;
}

void CBar::DoSomething()
{
   x = 6;   
}

////////////////////////////////////////////////////////////////////////
// here it is

void main()
{
   CBar theBar;
   theBar.DoSomething();
}

-- CLIP AND SAVE -- CLIP AND SAVE -- CLIP AND SAVE --

If you examine the map (that is, THISFILE.MAP) you'll find that the
the code for CFoo::NeverUsed() didn't show up in the executable image.

.B ekiM
http://www.nwlink.com/~mikeblas/
I'm afraid I've become some sort of speed freak.
These words are my own. I do not speak on behalf of Microsoft.

-----From: "P.J.  Tezza" 

Environment: VC++ 4.0, 4.1, 4.2-flat, 4.2b, Win 3.1, Win 95, NT 3.51, NT =
4.0

To make a broad generalization, at 100K+ of overhead for a statically =
linked MFC application and 900K+ of overhead for a dynamically linked =
MFC application, you are probably not going to see much savings by =
tuning your own code for size.

Let's say for the sake of discussion that you have 100K worth of your =
own object code (a medium sized application). Now let's say that you =
manage to shave off 20K (a pretty optimistic assumption) using tricks =
like using common functions and base classes just for size savings (a =
dubious trade off). Now you link with the MFC libraries statically (to =
see the best possible benefits), thus pulling in about 150K worth of =
MFC. Using very optimistic calculations, you have gained only an 8% =
savings - about a quarter of a second (with compression) worth of modem =
download time.

You can make a visible difference in your application's size if you are =
willing to avoid certain MFC features: view/document architecture, print =
preview support, OLE, ODBC, DAO, etc.. The MFC module architecture looks =
like it was designed to ensure that these major components do not get =
linked into your application if they are not used, thus reducing the =
size of the linked in MFC code. Because I really want to make my =
applications small (I build setup applications), I am considering =
playing around with custom, static library builds of MFC to actually =
avoid any code related to OLE, ODBC, etc.. There are some constants it =
looks like you can define (_AFX_NO_OCC_SUPPORT, _AFX_NO_OLE_SUPPORT, =
_AFX_NO_DOCOBJECT_SUPPORT, _AFX_NO_DB_SUPPORT and _AFX_NO_DAO_SUPPORT, =
in particular) to avoid code that simple MFC applications will not need. =
I am planning to experiment with this in the near future if anyone has =
any prior experience or is interested.

PJ
pj@exemplarsoftware.com




Mike Blaszczak -- mikeblas@nwlink.com
Saturday, December 07, 1996

[Mini-digest: 4 responses]

>-----From: "P.J.  Tezza" 

>I am considering
>playing around with custom, static library builds of MFC to actually 
>avoid any code related to OLE, ODBC, etc.. There are some constants it
>looks like you can define (_AFX_NO_OCC_SUPPORT, _AFX_NO_OLE_SUPPORT,
>_AFX_NO_DOCOBJECT_SUPPORT, _AFX_NO_DB_SUPPORT and _AFX_NO_DAO_SUPPORT,
>in particular) to avoid code that simple MFC applications will not need.
>I am planning to experiment with this in the near future if anyone has
>any prior experience or is interested.

These constants aren't really very reliable.  They're there largely to
help other vendors accept ports of MFC (and to help ourselves port MFC
to the Macintosh).  They're mostly obsolete and rarely tested, and they're
in jeopardy of being removed from MFC.

.B ekiM
http://www.nwlink.com/~mikeblas/
I'm afraid I've become some sort of speed freak.
These words are my own. I do not speak on behalf of Microsoft.

-----From: "P.J.  Tezza" 

Environment: VC++ 4.2-flat

After reading the responses to "How to Slim MFC applications?", you guys =
were so excited by the /Gy and /OPT:REF compiler and linker options, I =
started thinking that I had missed something. I researched these options =
when I created my setup toolkit, and I came to the conclusion that they =
were not even worth mentioning in my documentation as a way to decrease =
the size of setup applications. Just to be sure, I built various release =
versions of two fairly generic MFC applications using VC++ 4.2 flat and =
with MFC statically linked for the best savings effect. MULTIPAD.EXE is =
the MFC sample that you all know and love. _SETUP.EXE is a very full =
featured MFC based setup application, and SETUP.EXE is a single file =
.exe distribution image created by compressing a setup MULTIPAD.EXE, =
_SETUP.EXE, a bootstrap application (20392 bytes), a setup application =
help file (11844 bytes), 893 bytes worth of sample files and 58 bytes =
worth of tutorial files. (And you thought Multipad was fine without =
samples and a tutorial, didn't you?).

The following table presents the results of the relevant compiler and =
linker options in bytes and looks best when using a monospaced font:
                      =20
             /O2 (SPEED) /O1 (SIZE) /O2 /Gy /OPT:REF					=20
MULTIPAD.EXE 291840      291840     291840
_SETUP.EXE   691200      684544     484544
SETUP.EXE    501250      500970     500970

As you might guess from the _SETUP.EXE results, the documentation states =
that turning on "Optimize for Size" automatically enables /Gy which =
automatically enables /OPT:REF. Not that I am all that impressed by the =
final 280 byte savings achieved. On a whim, I grunged around in the MFC =
make files a bit and found /O1 several times, but never found /O2. =
Basically, all MFC release builds automatically enable /Gy and /OPT:REF, =
and there is no point in worrying about them in MFC applications.

Sorry for the bad news, and I still plan to play around with this topic =
some more.

PJ
pj@exemplarsoftware.com
-----From: Strhan Mojmir 

P.J. Tezza wrote:
>
>>You can make a visible difference in your application's size if you are =
>>willing to avoid certain MFC features: view/document architecture, print =
>>preview support, OLE, ODBC, DAO, etc.. The MFC module architecture looks =
>>like it was designed to ensure that these major components do not get =
>>linked into your application if they are not used, thus reducing the =
>>size of the linked in MFC code. Because I really want to make my =
>>applications small (I build setup applications), I am considering =
>>playing around with custom, static library builds of MFC to actually =
>>avoid any code related to OLE, ODBC, etc.. There are some constants it =
>>looks like you can define (_AFX_NO_OCC_SUPPORT, _AFX_NO_OLE_SUPPORT, =
>>_AFX_NO_DOCOBJECT_SUPPORT, _AFX_NO_DB_SUPPORT and _AFX_NO_DAO_SUPPORT, =
>>in particular) to avoid code that simple MFC applications will not need. =
>>I am planning to experiment with this in the near future if anyone has =
>>any prior experience or is interested.

I have defined these constants in my STDAFX.H headers and recompiled
whole projects.
There were no warning or errors on /W4 level. Result was that new EXEs
were about 1-5kB 
smaller than old ones. But all EXEs crashed during startup under
Windows95.
Later I have removed _AFX_NO_OCC_SUPPORT and _AFX_NO_OLE_SUPPORT
and recompiled again. Produced EXEs worked correctly, but no space
savings occured.

So I think that usage of these constants is dangerous and should be
avoided.
Same applies to section merging using /MERGE linker option. 

I have also tested /Gy /OPT:REF switches. 1-3kB savings occured and
produced images
were allways runnable. This means that it is safe to use these switches.

Mojmir Strhan



-----From: "P.J.  Tezza" 

----------
From: 	Strhan Mojmir

>I have defined these constants in my STDAFX.H headers and recompiled =
whole projects.
>... EXEs crashed during startup under Windows95.

Crashing makes sense - when you define the constants in your header =
files your application's object files assume that the MFC objects have a =
smaller memory layout. The object code in the MFC libraries was compiled =
without the constants and expects a different, larger memory layout for =
many MFC objects.=20

I believe that the intention of these constants is/was to create custom =
builds of the MFC libraries. If you use them to create custom MFC =
library builds and use them in your headers, the MFC object layouts will =
match. To this end, I rebuilt the MFC libraries with the following =
command line:

NMAKE DLL=3D0 DEBUG=3D0 CODEVIEW=3D0 MBCS=3D0 MT=3D0 =
"OPT=3D/D_AFX_NO_OCC_SUPPORT /D_AFX_NO_OLE_SUPPORT =
/D_AFX_NO_DOCOBJECT_SUPPORT /D_AFX_NO_DB_SUPPORT /D_AFX_NO_DAO_SUPPORT =
/D_AFX_NO_SOCKET_SUPPORT /D_AFX_NO_SYNC_SUPPORT /D_AFX_NO_OCX_SUPPORT =
/D_AFX_NO_INET_SUPPORT"

For more information about these options see \MSDEV\MFC\SRC\MAKEFILE. =
This did not even come close to working - I had to modify about 50 % of =
the MFC source code files to make things work with these constants =
defined. I then placed the following lines in Multipad's stdafx.h:

#define VC_EXTRALEAN
#define _AFX_NO_OCC_SUPPORT=20
#define _AFX_NO_OLE_SUPPORT=20
#define _AFX_NO_DOCOBJECT_SUPPORT=20
#define _AFX_NO_DB_SUPPORT=20
#define _AFX_NO_DAO_SUPPORT=20
#define _AFX_NO_SOCKET_SUPPORT
#define _AFX_NO_SYNC_SUPPORT
#define _AFX_NO_OCX_SUPPORT
#define _AFX_NO_INET_SUPPORT

Just for fun, I also placed the following lines in Multipad's resource.h =
to avoid standard MFC resources:

#define _AFX_NO_STOCKPPG_RESOURCES
#define _AFX_NO_CTLERROR_RESOURCES
#define _AFX_NO_APPMENU_RESOURCES
#define _AFX_NO_APPMENUSTRING_RESOURCES
#define _AFX_NO_FILECMD_RESOURCES
#define _AFX_NO_CFILE_RESOURCES
#define _AFX_NO_OLE_RESOURCES
#define _AFX_NO_MAPI_RESOURCES
#define _AFX_NO_SPLITTER_RESOURCES
#define _AFX_NO_TRACKER_RESOURCES
#define _AFX_NO_NEWTYPEDLG_RESOURCES

I changed Multipad's code generation/runtime library option from =
Multithreaded to Single-Threaded. This was with the idea that the =
single-threaded libraries would be smaller. I also rebuilt MFC without =
multithread support for the same reason. Finally, I rebuilt Multipad. =
Before doing all of this MULTIPAD.EXE was 291840 bytes. With the new MFC =
libraries, MFC was 267776 bytes for a total savings of 24064 bytes. =
Because there was so little savings, I did not bother to test out any =
other applications. I will hang onto the custom MFC library for a couple =
of days in case someone else wants to try.

My conclusions:

- The MFC developers put the _AFX_NO* constants into the library, but =
they never actually use them or test them out.
- The MFC 4 architecture combined with the VC++ linker is pretty good at =
removing unused MFC code without manual intervention.
- The only simple way to create 50K MFC applications is to use MFC 1 =
which came with MS C/C=3D=3D 7.0. Win32 developers may be better off =
trying to port MFC 1 to Win32 instead of trying to chop down MFC 4.

As you probably already know, small MFC applications can be created by =
linking to the MFC DLLs. Here are the main problems associated with =
this:

1) The various MFC DLL files must be gathered and installed correctly.
2) If anything happens to the MFC DLLs you have installed, for example =
some other application installs them incorrectly, your application will =
no longer work correctly.
3) The MFC DLLs are large and require several minutes to download.

For Visual C++ 4 MFC applications, I have solved the first two problems =
for anyone who cares to use Exemplar Setup Toolkit (see =
http://www.exemplarsoftware.com/setuptrialprogram.htm for more =
information).
The best that can be done to solve the third problem is to avoid =
downloading the MFC DLLs (or any other files, for that matter), if they =
are already installed on the end user's machine. I plan to add this =
capability to the next version of Exemplar Setup Toolkit.

PJ
pj@exemplarsoftware.com





Mike Blaszczak -- mikeblas@nwlink.com
Tuesday, December 10, 1996

>-----From: "P.J.  Tezza" 

>Environment: VC++ 4.2-flat

Please upgrade to 4.2B by installing the patch.  It fixes bugs that will 
cause you problems later.

>After reading the responses to "How to Slim MFC applications?", you guys
>were so excited by the /Gy and /OPT:REF compiler and linker options, I
>started thinking that I had missed something. I researched these options
>when I created my setup toolkit, and I came to the conclusion that they
>were not even worth mentioning in my documentation as a way to decrease
>the size of setup applications.

/Gy and /OPT:REF are very necessary, and certainly worth understanding
at a global level. If MFC wasn't built using them, any statically linked
MFC application would be very round and swollen.

Building your own application, wether it uses MFC or not, probably won't
change much with /Gy: in your application, you probably haven't sat down
and written code that you don't need, so eliminating code function-by-function
isn't going to result in a big win.

But your executable image size can change noticably with /OPT:REF; the
linker is the one responsible for doing dead-code removal.

All of the things I've said examine these options in the context of building
a statically linked MFC application. If you're building against your own
library, or a third-party library, or if you're just building an application
without MFC, there are different net effects.

>Just to be sure, I built various release
>versions of two fairly generic MFC applications using VC++ 4.2 flat

Please upgrade, particularly if you're redistributing what you're building.

>The following table presents the results of the relevant compiler and 
>linker options in bytes and looks best when using a monospaced font:

>             /O2 (SPEED) /O1 (SIZE) /O2 /Gy /OPT:REF
>MULTIPAD.EXE 291840      291840     291840
>_SETUP.EXE   691200      684544     484544
>SETUP.EXE    501250      500970     500970

It seems like you're comparing
        builds with /O2
        builds wiht /O1
        builds with /O2 /Gy /OPT:REF

which is very funny: /Gy is _included_ in /O1 and /O2 implicitly,
anyway.  The difference between your first column and your second column
is strictly because of the compiler deciding to generate different code.
I don't think you learn anything about /OPT:REF by comparing the second
column with the third.  Comparing the first column with the third, though,
shows you what benefit you get from /OPT:REF --because /Gy was already
switched on in column one.

>As you might guess from the _SETUP.EXE results, the documentation states
>that turning on "Optimize for Size" automatically enables /Gy which
>automatically enables /OPT:REF.

It does?  I don't think it does.  Where did you find that in the documentation?
I think the setting in the IDE's "Build Settings" window might switch the
linker option on automatically, but I don't think that /Gy for the
compiler changes the linker's /OPT: setting.

>Not that I am all that impressed by the
>final 280 byte savings achieved. On a whim, I grunged around in the MFC
>make files a bit and found /O1 several times, but never found /O2.

It looks like /OPT:REF actually saved you 206656 bytes in your _SETUP.EXE
program. I'm not sure I understand your conclusion. Maybe I'm misreading
your table. Maybe you're like other people on the list who stick to a
20 microsecond solution when a zero-microsecond solution is available;
maybe 200K doesn't matter to you.

>Basically, all MFC release builds automatically enable /Gy and /OPT:REF, =
>and there is no point in worrying about them in MFC applications.

That's how MFC is built, yes.  But how your own application is built
is up to you.

.B ekiM
http://www.nwlink.com/~mikeblas/
I'm afraid I've become some sort of speed freak.
These words are my own. I do not speak on behalf of Microsoft.




P.J. Tezza -- pj@exemplarsoftware.com
Monday, December 16, 1996

>>As you might guess from the _SETUP.EXE results, the documentation =
states
>>that turning on "Optimize for Size" automatically enables /Gy which
>>automatically enables /OPT:REF.

>It does?  I don't think it does.  Where did you find that in the =
documentation?
>I think the setting in the IDE's "Build Settings" window might switch =
the
>linker option on automatically, but I don't think that /Gy for the
>compiler changes the linker's /OPT: setting.

This quote is from the "LINK Command-Line Options". If I had not botched =
up my table with a typo, the build results would have supported my =
conclusions (see below). I am fairly sure that the author means that /Gy =
is necessary and sufficient to enable the linker's /OPT:REF =
optimizations.

"Syntax
/OPT:{REF|NOREF}
 =20
This option controls the optimizations that LINK performs during a =
build. Optimizations generally decrease the image size and increase the =
program speed, at a cost of increased link time.
By default, LINK removes unreferenced packaged functions. An object =
contains packaged functions (COMDATs) if it has been compiled with the =
/Gy option. This optimization is called transitive COMDAT elimination. =
To override this default and keep unreferenced COMDATs in the program, =
specify /OPT:NOREF. You can use the /INCLUDE option to override the =
removal of a specific symbol.
If the /DEBUG option is specified, the default for /OPT changes from REF =
to NOREF, and all functions are preserved in the image. To override this =
default and optimize a debugging build, specify /OPT:REF. The /OPT:REF =
option disables incremental linking."

>>It looks like /OPT:REF actually saved you 206656 bytes in your =
_SETUP.EXE
>>program. I'm not sure I understand your conclusion. Maybe I'm =
misreading
>>your table. Maybe you're like other people on the list who stick to a
>>20 microsecond solution when a zero-microsecond solution is available;
>>maybe 200K doesn't matter to you.

200K takes a very noticable several seconds to download. Sorry for the =
typo, here are the corrected results:

             /O2 (SPEED) /O1 (SIZE) /O2 /Gy /OPT:REF
MULTIPAD.EXE 291840      291840     291840
_SETUP.EXE   691200      684544     684544
SETUP.EXE    501250      500970     500970

>>/Gy is _included_ in /O1 and /O2 implicitly, anyway.=20

It looks like /OPT:REF is, too. Sometimes I need more than just the =
manual author's word for things.

>>That's how MFC is built, yes.  But how your own application is built
>>is up to you.

MFC and its build options dominate MULTIPAD.EXE. Anyone want to write =
MFC lite?

PJ



Mike Blaszczak -- mikeblas@nwlink.com
Tuesday, December 17, 1996

At 02:52 12/16/96 -0500, P.J.  Tezza wrote:

>This quote is from the "LINK Command-Line Options". If I had not botched =
>up my table with a typo, the build results would have supported my =
>conclusions (see below). I am fairly sure that the author means that /Gy =
>is necessary and sufficient to enable the linker's /OPT:REF =
>optimizations.

It doesn't. I'm not sure how you get anything about a connection
between the presence of /Gy and the default of /OPT:REF from the topic
you quoted. Maybe you should explain your conclusion to the folks at
the vcdocs@microsoft.com address so they can eliminate whatever ambiguity
you're seeing.

>>/Gy is _included_ in /O1 and /O2 implicitly, anyway.=20
>It looks like /OPT:REF is, too. 

Sorry, no, it isn't.  You've not provided any evidence to show that,
and you're really not making a conclusion: you're making a guess. You
can show that it isn't implicit by building a simple program like this one:

-- CLIP AND SAVE -- CLIP AND SAVE --

// compile me with
//   cl /O2 thisfile.cpp /LINK /DEBUG /MAP
// then compile it again with
//   cl /O2 thisfile.cpp /LINK /DEBUG /OPT:REF /MAP
// and again with
//   cl thisfile.cpp /LINK /DEBUG /MAP
// and again with
//   cl thisfile.cpp /LINK /DEBUG /OPT:REF /MAP

volatile n;   // the compiler won't optimize away what we're measuring

void FunctionOne()
{   n = 1;   }

void FunctionTwo()
{   n = 2;   }

void main()
{   FunctionOne();   }

-- CLIP AND SAVE -- CLIP AND SAVE --

After the each different builds, examine the thisfile.map file.  Only the
builds with /OPT:REF explicitly specified will show that FunctionTwo()
isn't in the executable image, regardless of the presence of /O2.

Like the documentation says, /OPT:REF is the default if you haven't specified
/DEBUG to the linker. /OPT:NOREF is the default if you have specified
/DEBUG to the linker. The setting of /OPT for the linker is entirely
independent of the compiler's /Gy setting.

There's nothing wrong with trying to figure out things for yourself: I
really wish more people would do it.  But if you do go down this path,
it's really important to make logical experiments--you need both logical
analysis and solid scientific method to make meaningful conclusions.

>MFC and its build options dominate MULTIPAD.EXE.

MULTIPAD isn't a very realistic example; it contains only 120 lines of
source code, 24 lines of which are copyright comments.  MFC's build 
options have a big effect because MFC contributes more than 99% of the
code in the resulting executable. Most applications aren't written like
this.

Even that said, I'm not sure that MFC's build options dominate MULTIPAD:
if you build the release target of NOTEPAD to statically link with MFC
and give /OPT:NOREF, you'll find that it is about 20% larger.  We're
changing the way MULTIPAD is linked, not the way that MFC is built, and
a 20% change is very noticable.  For MULTIPAD, it's about 60K.  By your
own metric, that comes out to be about 23 seconds on a 28.8kbps modem
connection.

.B ekiM
http://www.nwlink.com/~mikeblas/
I'm afraid I've become some sort of speed freak.
These words are my own. I do not speak on behalf of Microsoft.




P.J. Tezza -- pj@exemplarsoftware.com
Friday, December 20, 1996

>/Gy is _included_ in /O1 and /O2 implicitly, anyway.=3D20
>It looks like /OPT:REF is, too.=20

>>Sorry, no, it isn't.  You've not provided any evidence to show that,
>>and you're really not making a conclusion: you're making a guess. You
>>can show that it isn't implicit by building a simple program like this =
one:

I believe that Mike is referring to my analysis of the /OPT:REF option, =
not the /Gy option.=20
Just in case anyone is confused, here are some quotes from VC++ online =
docs:

Minimize Size   Creates the smallest code in the majority of cases. =
Command-line equivalent: /O1
 =20
The effect of using this option is the same as specifying the following =
options in the Common/Project/Source File Options text box or on the =
command line:
 =20
/Og /Os /Oy /Ob1 /Gs /Gf /Gy
 =20

Maximize Speed   Creates the fastest code in the majority of cases. =
Command-line equivalent: /O2
The effect of using this option is the same as specifying the following =
options in the Common/Project/Source File Options text box or on the =
command line:
 =20
/Og /Oi /Ot /Oy /Ob1 /Gs /Gf /Gy

>There's nothing wrong with trying to figure out things for yourself: I
>really wish more people would do it.  But if you do go down this path,
>it's really important to make logical experiments--you need both =
logical
>analysis and solid scientific method to make meaningful conclusions.

>if you build the release target of NOTEPAD to statically link with MFC
>and give /OPT:NOREF, you'll find that it is about 20% larger.

Yes, placing /DEBUG and/or /OPT:NOREF in the link command line will =
change the outcome to support your conclusions. Leaving them out, which =
is the default case for Release IDE builds and the way I conducted my =
tests, supports mine.

>MULTIPAD isn't a very realistic example

I agree, that is why I also included _SETUP.EXE, a medium sized MFC =
application, in my results. Using /O1 vs /O2 results in a 280 byte (with =
/Gy and /OPT:REF enabled) savings in the final download size.

I learned a lot about the way that these command line options work from =
this discussion.
How would you guys change the following answer to "How to Slim MFC =
applications?":

If you have not rebuilt the MFC libraries and you are using are using a =
make file created by the Visual C++ IDE, then be sure that you are using =
a Release build. You can also gain a small benefit by changing the =
Release default from "Optimize for Speed" to "Optimize for Size". The =
MFC libraries are built using "Optimize for Size". Except for "Optimize =
for Size" vs "Optimize for Speed", the defaults for Visual C++/MFC =
Release builds automatically enable all options for decreasing the size =
of MFC applications.

If you are building your own versions of the MFC libraries, using custom =
make files or specifying compiler and linker options explicitly, then be =
sure to enable the /Gy compiler option and the /OPT:REF linker option.

PJ
pj@exemplarsoftware.com



Mike Blaszczak -- mikeblas@nwlink.com
Sunday, December 22, 1996

At 13:49 12/20/96 -0500, P.J.  Tezza wrote:

>I believe that Mike is referring to my analysis of the /OPT:REF option,
>not the /Gy option. Just in case anyone is confused, here are some
>quotes from VC++ online docs:

Actually, I'm refuting your contention that /Gy in the compiler causes
/OPT:REF in the linker.  It doesn't.

What you've quoted in the documentation shows that /O1 and /O2 both
implicitly set /Gy.  And that's true; I never said it wasn't.

>Yes, placing /DEBUG and/or /OPT:NOREF in the link command line will
>change the outcome to support your conclusions. Leaving them out, which
>is the default case for Release IDE builds and the way I conducted my
>tests, supports mine.

No.  Look, I don't know how to be much clearer about this, but the
setting of the linker's /OPT switch has _nothing_ to do with any
compiler optimization or code generation option that you can set.
Period.

(Just think about it: what if you compiled one file with /Gy and
another file without /Gy and then linked them together?  What would
the linker use for its /OPT setting, then?  [ANSWER: it doesn't
matter whether /Gy was there or not--the linker doesn't know if it
was or wasn't and sets the default for /OPT based on its own rules.])

The setting of the linker's /OPT switch defaults to /OPT:REF if you
haven't given the linker the /DEBUG switch, and /OPT:NOREF if you
have provided the linker with the /DEBUG option.  If you look at
your table, what you observed is consistent with this fact.  You
haven't done enough to show that the /OPT setting is affected by /Gy,
while the experiment I suggest shows, in short order, that the
setting of /Gy and /OPT are unrelated.

>>MULTIPAD isn't a very realistic example

>I agree, that is why I also included _SETUP.EXE, a medium sized MFC
>application, in my results. Using /O1 vs /O2 results in a 280 byte (with
>/Gy and /OPT:REF enabled) savings in the final download size.

But you still drew conclusions from the observations you made with
the builds of NOTEPAD.  Since that program isn't very representative
of the way MFC's used (and you know it, you say) why did you draw any
conclusions from building it?

Is the source for _SETUP.EXE available to the general public?  From
where?  If it isn't, nobody can reproduce or verify your results, and that
means you might as well be picking numbers from the sky.  Maybe _SETUP.EXE
is an unrealistic example, too.

>I learned a lot about the way that these command line options work from
>this discussion.

That's good.  But why are you continuing to stick with a bad conclusion?

.B ekiM
http://www.nwlink.com/~mikeblas/
I'm afraid I've become some sort of speed freak.
These words are my own. I do not speak on behalf of Microsoft.




P.J. Tezza -- pj@exemplarsoftware.com
Monday, December 23, 1996

>Is the source for _SETUP.EXE available to the general public?=20

The source code to _SETUP.EXE can be downloaded from =
http://www.exemplarsoftware.com/setupdemos.htm. If you want to compile =
it, you will have to install Exemplar Setup Toolkit which can be =
obtained for free from =
http://www.exemplarsoftware.com/setuptrialprogram.htm. Exemplar Setup =
Toolkit is commercial software with a software license agreement which =
restricts redistribution.

PJ
pj@exemplarsoftware.com





| Вернуться в корень Архива |