4

I was testing this simple c++ code on my Windows 8.1, Intel i7-3517U 64 bit laptop with GCC 4.8.2.

#include<iostream>

using namespace std; 

int main(int argc, char **argv){
   cout << "This test code will simply display any arguments passed." << endl ;
   for(int i=0; i<argc; i++){
      cout << argv[i] << endl ;
   }
   return 0 ;
}

Surprisingly, after compiling, the executable turned out to be of 5905KB. Out of curiosity, i tried compiling the same file with the same GCC version on Linux Fedora 20 64 bit machine. And the executable was just 9KB.

After doing various optimization using g++ -Ox -o fileWithOx.exe file.cpp (x=1,2,3,s), Windows executable were nearly same in size. After doing some research, and following MinGW's advise i tried compiling them without debugging information using strip g++ -s -o fileWithStrip.exe file.cpp, but the executable was still 597KB large.

While on the other hand, Linux executable were of just 6-13KB for same options.

Doing some experiments, some more research & stack overflowing, i was nearly convinced that the gigantic size is due to iostream linking to many other header files and/or generating some initialization code.

But my doubt is that iostream is used both in Windows as well as in Linux. Then why so much difference in size? I know that Windows and Linux executable work differently. But 655 times bigger, isn't this a bit extreme?

Community
  • 1
  • 1
hardy
  • 79
  • 5
  • 2
    If you add `-static-libstdc++` in Linux, how big is the executable? Maybe it's statically linking to the standard library on Windows? – Joseph Mansfield Jan 22 '14 at 14:18
  • 1
    BTW `-Os` is to optimize for size but most likely static linking is the reason. – Jesse Good Jan 22 '14 at 14:19
  • 2
    The explanation could lie in the way the linking is made. Linking to a DLL creates small executables that don't actually include the libraries; linking statically puts everything needed in a bigger, stand-alone file. –  Jan 22 '14 at 14:19
  • 1
    Semi-obligatory snarky "Because Windows..." – twalberg Jan 22 '14 at 15:02
  • @Joseph Mansfield - It shows ' /usr/bin/ld: cannot find -lstdc++ ' & line2 'collect2: error: ld returned 1 exit status' – hardy Jan 22 '14 at 18:37

3 Answers3

6

The difference is probably not due to compilation but to link-edition phase.

First try to compile only, stop the command using -c e.g. g++ -c code.cpp in Unix-like and find the equivalent flags in your windows environment. Then compare the object files, they should be almost the same size. These object files (.o extension) only contains the translation of your code to the machine-code. The size could be different, say a factor of 2 or 3 maybe but this is not relevant.

What happened is that your Windows's compiler probably used a static linking on some library, thus the executable file contains the code of what you use in the library. On Unix-like the compiler probably linked everything dynamically, which says that the library will be loaded at runtime and not included in the executable.

Please refer to your compilers documentation to find how to enforce static/dynamic linking. You alos should be aware that it may be possible that some environment may not provide both kind of libraries...

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
  • Yes. The object files are almost same. Strangely, the linux object file is 2.9KB, while Windows object file is 1.9KB. So like you and others said, it may be due to static linking. But cant know for sure. Thnx anyway. – hardy Jan 22 '14 at 18:49
  • 1
    You can use tools to analyze the executable file. Depends on Windows, otool on MacOSX and ldd for Linux, at least. – Jean-Baptiste Yunès Jan 22 '14 at 19:10
2

Just built your program under windows, using mingw g++ version 4.7.2 - I only get 10kb. No idea how you managed to bloat it to over 5MB. Here's the cmd line and output when I hit Ctrl-F11 in Code::Blocks 13.12:

mingw32-g++.exe -Wall -fexceptions -O2 -I"C:\Program Files (x86)\CodeBlocks\MinGW\include" -c C:\Users\enhzflep\Documents\code\001-sizeTestDeleteMe\main.cpp -o obj\Release\main.o mingw32-g++.exe -o bin\Release\001-sizeTestDeleteMe.exe obj\Release\main.o -s
Output file is bin\Release\001-sizeTestDeleteMe.exe with size 10.50 KB

enhzflep
  • 12,927
  • 2
  • 32
  • 51
1

Sorry I don't have any Windows boxes right now, but if I believe this article,

perhaps it was because your Windows executable was statically linked to libstdc++.a shipped with the Mingw compiler suite while the Linux version was dynamically linked to something like /usr/lib64/libstdc++.so.6. The latter is one of the standard components of most Linux distros and searchable by the dynamic linker, so Linux g++ can safely rely on it. But the former is not, so perhaps Mingw g++ decided to employ static linking.

The below article (on Mingw GCC 4.4) says you can tell Mingw g++ to dynamically link libstdc++.dll with the cmd line option -lstdc++_s

Just FYI, this is how a small C++ exe is dynamically linked to libstdc++.so.6 on my Debian box:

$ ldd valueInit
    linux-vdso.so.1 (0x00007fff641fe000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f20618e2000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f20615e4000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f20613cd000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2061021000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f2061c12000)
$ LANG=C ls -lH /usr/lib/x86_64-linux-gnu/libstdc++.so.6
-rw-r--r-- 1 root root 953K Jan  6 12:24 /usr/lib/x86_64-linux-gnu/libstdc++.so.6

libstdc++.so.6 does contain definitions of many iostream functions etc.

$ readelf -sW /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep stream | c++filt | head -3
   135: 0000000000084360    51 FUNC    WEAK   DEFAULT   12 std::money_get<char, std::istreambuf_iterator<char, std::char_traits<char> > >::get(std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> >, bool, std::ios_base&, std::_Ios_Iostate&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&) const@@GLIBCXX_3.4
   137: 00000000002e8ff0    24 OBJECT  WEAK   DEFAULT   23 typeinfo for std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >@@GLIBCXX_3.4
   138: 000000000009f1d0    15 FUNC    WEAK   DEFAULT   12 std::num_put<wchar_t, std::ostreambuf_iterator<wchar_t, std::char_traits<wchar_t> > >::put(std::ostreambuf_iterator<wchar_t, std::char_traits<wchar_t> >, std::ios_base&, wchar_t, void const*) const@@GLIBCXX_3.4
Community
  • 1
  • 1
nodakai
  • 7,773
  • 3
  • 30
  • 60
  • I tried with -lstdc++_s on both Windows & fedora. Says ' collect2: error: ld returned 1 exit status' . Though the info was helpful. Thnx. – hardy Jan 22 '14 at 18:58