You can try this:
Make an do-nothing program (empty main() function). Compile from command line with avr-gcc. Use the same compiler switches that Arduino uses.
Then include WProgram.h and compile again
When you include <WProgram.h> in a “normal” sketch it supplies protypes for a main() function and an init() function which will be linked into the executable, but there is no added executable code or data storage due to <WProgram.h> itself (and the headers that it includes). When you compile this sketch from a command line, it doesn’t link in the any of the core object files. (See Footnote.)
Since some of the Arduino core header files define C++ classes, the compiler/linker does put in some extra stuff for the C++ classes (stuff like vtables). This stuff is not code from the core object files; it is internal bookkeeping stuff that the linker thinks the program might need.
Try the following with any standard C++ compiler on your workstation. Compile a do-nothing C++ file (containing absolutely nothing other than an empty main() function). Then include and compile again. The resulting (do-nothing) executable is larger (probably by a few hundred bytes) when you include a header that defines C++ classes, even if your program don’t use the classes to create objects.
Footnote: The main() function for a “normal” Arduino sketch is obtained from the core function main.cpp, and contributes a few bytes since it calls three functions and has a for loop
Look at core file wiring.c to see what init() contributes.
None of the header files themselves contribute any data definitions or executable code to the .hex file. Note that even though the Arduino build process shows all of the object files from the core library files when it builds a library from the core object files, the only ones that get linked in (other than the object files from main.cpp and wiring.c) are ones that contain functions that are used by your sketch.
Bottom line: For a “normal” sketch, including <WProgram.h> always adds stuff from main.cpp and wiring.c when the sketch is linked. Other stuff is put in by the avr-gcc linker.
Postscript to bottom line:
If you want to see how many bytes are in an absolutely minimal sketch, try the following:
That’s not a misprint: The whole sketch consists of an empty main() function. (No setup(), no loop(), just this main() function.)
When Arduino links all of the files, this main() function is used (not the one from the Arduino core main.cpp), since the object file from the cpp created by the sketch has already been linked by the time that the linker encounters the library built from core object files. Therefore the resulting executable consists only of avr-gcc runtime code.
Now, even though many of the readers, if any are left, are (probably) exhausted by now, this is not an exhaustive treatment of the subject. Just a few ideas for things to try if anyone is still interested (and is still awake).