Include eight headers, get a 1500kb program. Is this normal?

Pages: 12
Here are the eight headers in question:

curses.h
stdexcept
Windows.h
cctype
ctime
fstream
stdexcept
string

I'm compiling with G++. Here's my compilation command:

g++.exe -I .. -I ../.. -L .. prototype.cpp -o outcome.exe -l:pdcurses.a

Nothing seems to effect the outcome. Not changing the optimization level, not whether or not I have the debug flag set, not #DEFINE WINDOWS_LEAN_AND_MEAN, as one internet denizen suggested. Of course, a 1.5MB .exe isn't exactly a big inconvenience on contemporary machines, but it strikes me as a little outsized for a 200-line console application.

Thoughts?

As an aside, the internet seems to think that what headers I include, and what libraries I link, effect the size of the result, but I don't understand why this would be. Sure, I can see why it would bloat the job of the linker/compiler, but aren't they smart enough to discard a bunch of unused declarations and definitions for the final result?
Something is up ... debug vs not and optimized or not should change the size a little at least.
but think of it like this... if its a tiny program, then the size is indeed governed by the libraries you put in.

aren't they smart enough to discard a bunch of unused declarations and definitions for the final result?

not as much as you might think. It does what it can, but this is a sore spot and most compilers struggle to get rid of stuff not needed. I do not fully understand why. I mean, give it a try yourself, add in about 10 more common headers like math and vector and algorithm etc. See if it gets bigger.

you can also make a do-nothing empty main program with the same headers and compile it, then take away headers one by one, see if a single one is pulling in a lot of crap and if you can avoid that one
Last edited on
I should have been more specific: those measures did change the size by a little bit, at most 10%, but some of them actually made the problem 10% worse.

jonnin, those are some good ideas, I'll try them.
> g++.exe -I .. -I ../.. -L .. prototype.cpp -o outcome.exe -l:pdcurses.a
At the moment, you're statically linking with the library.

If you were to dynamically link with the library, your executable would get smaller, but you'd be dependent on a dynamic library being loaded at run-time.
Whether you count this as making your program 'smaller' is debatable.

> As an aside, the internet seems to think that what headers I include, and what libraries I link, effect the size of the result,
Unnecessary headers mostly just waste compilation time. It's not so much of a problem in a single source file, but if you have 100's of .cpp files all with #include everything, then build times are going to suffer.
Later, they waste the time of future porters and maintainers of the code.

Linkers usually are smart enough to discard unused stuff.
Did you strip the executable (pass -s to gcc)?

I don't doubt the 1.5MiB figure is absurd, but it really depends what is in the binary.

What is the size of the binary when you just do
int main() { } as your program?
Just because you include 8 headers doesn't mean there are not more headers being added to the mix by the C++ implementation. Likely there are dozens, maybe several hundred, being implicitly included.

The number of headers included has nothing to do with what the size of the executable will be. That is determined by the linker. And somewhat if the linking is static or dynamic.
Indeed, libgcc being statically linked adds a lot to the build size.

Certain headers that have global variables like <iostream> can also add to the size, even if you don't use cout/cin (I know that's not being used in this specific instance; just an example).
Last edited on
Same code compiled as a 64-bit app will be larger than a 32-bit app as well.

It's a funny thing about GCC compared to the same code compiled by VS, both statically linked. GCC produces an exe that is around the size the OP mentions, VS a shade less than 300KB.

Even a statically linked app on Windows still has links to DLLs. For the VS app it kernel32.dll only. On Win10 there are a lot of secondary DLLs loaded by kernel32.dll, though.

GCC compiled and the same code gets linked with kernel32.dll and MSVCRT.DLL. The Windows NT C runtime dll. WHOA! So a larger static linked size with more DLLs used.

Link the code in VS to use runtime libraries and it adds dynamic links to the VS runtime libraries, while shrinking the exe size to around 10-15KB.
non-windows (no windows.h) g++ on my machine make about 20k .exe files. Without that .s, its ~10x larger(!). I don't think I have ever generated > mb for a small console program... will be interesting to hear back where its coming from ... all static linkage or something with a compiler flag or that specific compiler... etc?
I'm back:

A completely empty program yields a 37KB executable.

A completely empty program with all the originally listed header files (and libraries) included yields a 37KB executable.

Curiously, I found that adding ten std::strings (about seventy characters each) to the global scope bumped the size of that otherwise empty program up to 331KB.

Compiling my original program with -s passed to GCC yields a 598KB program. (there's some improvement)

Off to learn about what "static" and "dynamic" linking are...

> Curiously, I found that adding ten std::strings (about seventy characters each) to the global scope
> bumped the size of that otherwise empty program up to 331KB.

The string literals themselves and the (inline) code generated for construction/destruction of the std::string objects can contribute to the size of the executable.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <string>

int foo()
{
    // the two string literals and the computation can be optimised away
    return "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
           "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"[0] -
           "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
           "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"[0] ; // return 'a' - 'A'
}

int bar()
{
    // the two string literals and inline construction/destruction of the std::string
    // objects are typically part of the generated code 
    const std::string str1 = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
                             "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" ;
    const std::string str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
                             "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ" ;
    return str1[0] - str2[0] ; // return 'a' - 'A'
}


https://gcc.godbolt.org/z/Yqqve3sM4
Off to learn about what "static" and "dynamic" linking are...

https://www.learncpp.com/cpp-tutorial/a1-static-and-dynamic-libraries/

The app needs code to hook into the OS that runs the app. With Windows that is code that links into at least kernel32.dll for a static linked app. For a dynamic linked app that would include the Windows C runtime DLL(s).

See also: https://stackoverflow.com/questions/1993390/static-linking-vs-dynamic-linking
Last edited on
Thanks, George. I think I'm going to stick with static linking, not only because it is easier, but because I do need this to be multi-platform.

I found that adding those same 700 characters in std::strings increased the size of the executable by only 2kb. Exactly the size of those characters stored in a simple text file.

Adding just a single empty STD::string to an otherwise empty program yielded 331KB. So maybe my compiler is somehow incorporating every part of every library I reference?

I tried filling that otherwise-empty program with calls to the functions and classes that I used in my original program. So, basically, a main method with just fifteen useless method calls, mostly to the pdcurses library. And guess what? I came to about the same size as my original program (1470KB).
it sounds too big, like the compiler/linker isnt configured right.
what was your *exact* build string?
I think I'm going to stick with static linking, not only because it is easier, but because I
do need this to be multi-platform.

Whether you use static or dynamic linking for cross platform uses is really irrelevant. A Windows compiled app will not run natively on a Mac or *nix platform, the source needs to be compiled for the specific platform you want to target.

Well written code that uses only the C++ libraries, no OS hacks, will compile for any platform that has a compiler.

You are seeing a freshly mowed grass lawn and calling it a forest.

Whether I routinely use static or dynamic linking I leave to the tools I use, their default. Visual Studio does dynamic linking.

The number of for sale software packages, games and productivity office apps, that use custom libraries are numerous.
it sounds too big, like the compiler/linker isnt configured right.
what was your *exact* build string?

Here's the most recent one I used:

C:/raylib/w64devkit/bin/g++.exe -s -O2 -I .. -I ../.. -L .. prototype.cpp -o outcome.exe -l:pdcurses.a

This produces a 608KB executable.
Last edited on
'Just wanted to give this a bump, since this project is now pretty much finished but the compiler is still serving me 600kb executables.
Try Os and O3 where you have O2, see if either makes any difference.
One way to proceed now would be to inspect the binaries. Maybe share your source code?
Pages: 12