海湾合作委员会 C++ “你好世界” 程序-> .exe 在 Windows 上编译时有 500kb 大。 我怎样才能减小它的大小?
我最近刚刚开始学习 C++ - 我在 Windows 上使用 nuwen 版本的 MingW,使用 NetBeans 作为 IDE (我还有 MSVC 2008 的 MSDN AA 版本,尽管我不经常使用它)。
编译这个简单的程序时:
#include <iostream>
using namespace std;
int dog, cat, bird, fish;
void f(int pet) {
cout << "pet id number: " << pet << endl;
}
int main() {
int i, j, k;
cout << "f(): " << (long)&f << endl;
cout << "dog: " << (long)&dog << endl;
cout << "cat: " << (long)&cat << endl;
cout << "bird: " << (long)&bird << endl;
cout << "fish: " << (long)&fish << endl;
cout << "i: " << (long)&i << endl;
cout << "j: " << (long)&j << endl;
cout << "k: " << (long)&k << endl;
} ///:~
我的可执行文件大约有 1MB 大。 当我将项目配置从“调试”更改为“发布”时,使用 -O1 -Os 标志(一路剥离调试符号),二进制大小从 1MB 减少到 544KB。
我不是一个“大小怪胎”,但我只是想知道 - 有什么办法可以进一步减小 .exe 的大小吗? 我只是认为,544KB 对于这样一个简单的应用程序来说太大了)。
I just recently started learning C++ - I am using nuwen's version of MingW on Windows, using NetBeans as an IDE (I have also MSDN AA Version of MSVC 2008, though I don't use it very often).
When compiling this simple program:
#include <iostream>
using namespace std;
int dog, cat, bird, fish;
void f(int pet) {
cout << "pet id number: " << pet << endl;
}
int main() {
int i, j, k;
cout << "f(): " << (long)&f << endl;
cout << "dog: " << (long)&dog << endl;
cout << "cat: " << (long)&cat << endl;
cout << "bird: " << (long)&bird << endl;
cout << "fish: " << (long)&fish << endl;
cout << "i: " << (long)&i << endl;
cout << "j: " << (long)&j << endl;
cout << "k: " << (long)&k << endl;
} ///:~
my executable was about 1MB big. When I changed project configuration from Debug to Release, used -O1 -Os flags ( stripping debugging symbols along the way ), binary size was reduced from 1MB to 544KB.
I am not a "size freak", but I am just wondering - is there any way, that I could reduce .exe size even more? I just think, that 544KB is just too much for such a simple application ).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
这里的问题不在于库,而在于
库已链接。 诚然,iostream 是一个相当大的库,但我不这么认为
认为它可能如此巨大以至于导致程序生成一个可执行文件
比使用
C
函数的类似函数大900KB
。 罪魁祸首不是 iostream 而是 gcc。 更准确地说,应该归咎于
静态链接
。您如何解释这些结果(用您的程序):
使用完全相同的可执行文件生成不同大小的可执行文件
构建选项。
答案在于 gcc 链接目标文件的方式。
当您比较这两个命令的输出时:
您会发现它们唯一不同的地方(除了
临时对象文件)位于所使用的选项中:
您的罪魁祸首就在顶部。
-Bstatic
是附带的选项正好在目标文件之后,可能看起来像这样:
如果您使用选项并删除“不必要的”库,
您可以将可执行文件的大小从
934KB
减少到4.5KB
最大值就我而言。 我通过使用
-Bdynamic
(-O
标志)得到了4.5KB
以及您的应用程序离不开的最重要的库,即
-lmingw32
、-lmsvcrt
、-lkernel32
。 您将获得一个25KB可执行文件观点。 将其缩减至 10KB,并UPX缩减至
4.5KB-5.5KB
左右。这是一个可以使用的 Makefile,供大家参考:
结果(YMMV):
在默认构建选项中包含
-Bstatic
的可能原因是为了更好的性能。 我尝试使用
-Bdynamic
构建astyle
并得到速度平均下降 1 秒,即使应用程序很慢
比原始版本小(UPX 后为 400KB vs 93KB)。
The problem here is not so much with the library as it is with the way the
library is linked. Granted, iostream is a moderately huge library but I don't
think it can be so huge as to cause a program to generate an executable that is
900KB
larger than a similar one that usesC
functions. The one to blameis not
iostream
butgcc
. More accurately,static linking
is to be blamed.How would you explain these results(with your program):
Different sizes of executables are being generated with exactly the same
build options.
The answer lies in the way gcc links the object files.
When you compare the outputs from these two commands:
you'll find out that the only places they differ(apart from the paths to the
temporary object files) is in the options used:
You've got your culprit right there at the top.
-Bstatic
is the option that comesexactly after the object file which may look something like this:
If you play around with the options and remove 'unnecessary' libraries,
you can reduce the size of the executable from
934KB
to4.5KB
maxin my case. I got that
4.5KB
by using-Bdynamic
, the-O
flagand the most crucial libraries that your application can't live without, i.e
-lmingw32
,-lmsvcrt
,-lkernel32
. You'll get a 25KB executable at thatpoint. Strip it to 10KB and UPX it to around
4.5KB-5.5KB
.Here's a Makefile to play with, for kicks:
Results(YMMV):
A possible reason for the inclusion of
-Bstatic
in the default build optionsis for better performance. I tried building
astyle
with-Bdynamic
and gota speed decrease of 1 second on average, even though the application was way
smaller than the original(400KB vs 93KB when UPXed).
这
导致许多标准库被链接,至少与 g++ 是一样的。 如果您确实担心可执行文件的大小,请尝试将所有 iostream 的使用替换为 printf 或类似的。 这通常会给你一个更小、更快的可执行文件(我把你的可执行文件减少到大约 6K),但代价是便利性和类型安全。
The
causes a lot of the standard library to be linked in, at least with g++. If you are really concerned about executable size, try replacing all uses of iostreams with printf or similar. This will typically give you a smaller, faster executable (I got yours down to about 6K) at the cost of convenience and type-safety.
不确定它对您有多大用处,但是 有人在减小简单 Windows .exe 的大小方面做了大量工作。
通过使用一些非常极端的方法,他们能够创建一个简单的 .exe,该文件将在 133 字节的现代 Windows 版本上执行。
Not sure how much use it will be to you, but someone has done quite a lot of work on reducing the size of a simple Windows .exe.
They were able to create a simple .exe that will execute on a modern version of Windows in 133 bytes, by using some very extreme methods.
你可以使用 -s,我相信它也内置于 mingw 中。
在 cygwin 上使用 g++ 3.4.4 编译的一个简单的 hello world 应用程序生成了 476872 字节的可执行文件,使用 -s 再次编译(删除不必要的数据),将相同的可执行文件减少到 276480 字节。
cygwin 上使用 g++ 4.3.2 的相同 hello world 应用程序生成了 16495 字节的可执行文件,使用 strip 将大小减少到 4608 字节。
据我所知,可能最好使用更新版本的 g++。
MingW 刚刚发布了 gcc 4.4.0,因此如果可执行文件大小很重要,那么我会考虑使用它。 正如它所表明的 -s 可能会帮助您去除大部分调试信息,因此仅在用于生产用途时才建议这样做。
You could use -s, which I believe is built into mingw as well.
A simple hello world application compiled using g++ 3.4.4 on cygwin produced executable that was 476872 bytes, compiling again with -s (strips unnecessary data), reduced the same executable to 276480 bytes.
The same hello world application on cygwin using g++ 4.3.2 produced an executable of 16495 bytes, using strip reduced the size to 4608 bytes.
As far as I can see, probably best to use more recent version of g++.
MingW has just released gcc 4.4.0, so if the executable size is important then I'd consider using that. As it indicates -s will probably help strip much of the debugging information out for you, that is only recommended if it is for production use.
你会得到 C++ 标准库,以及我猜想的其他东西,它们是静态链接的,因为 mingw 有自己的这些库的实现。
不用太担心,当你编写更复杂的程序时,大小不会相应增长。
You get the C++ standard library, and other stuff I guess, statically linked in as mingw has its own implementation of these libraries.
Don't worry so much about it, when you make more complex program, the size won't grow accordingly.
基本上,您实际上无法通过 mingw 的基本发行版来减少 .exe 大小。 550kb 大约是你能得到的最小的大小,因为 mingw 和 gcc/g++ 一般来说不擅长剥离未使用的函数。 其中大约 530kb 来自 msvcrt.a 库。
如果您确实想深入了解它,则可以使用 -ffunction-sections -fdata-sections 编译器选项重建 msvcrt.a 库,然后在链接应用程序时使用 -Wl,--gc-sections 链接器选项,这应该能够从那里去除很多东西。 但如果您刚刚学习 C++,重建该库可能有点高级。
或者您可以只使用 MSVC,它非常适合剥离未使用的功能。 使用 MSVC 编译的相同代码会生成一个 10kb 的 exe。
Basically, there's not really anything you can do to reduce that .exe size with a base distribution of mingw. 550kb is about as small as you can get it, because mingw and gcc/g++ in general are bad at stripping unused functions. About 530kb of that is from the msvcrt.a library.
If you really wanted to get into it, you might be able to rebuild the msvcrt.a library with -ffunction-sections -fdata-sections compiler options, and then use the -Wl,--gc-sections linker options when linking your app, and this should be able to strip a lot of that stuff out of there. But if you're just learning C++, rebuilding that library may be a bit advanced.
Or you could just use MSVC, which is great at stripping unused functions. That same bit of code compiled with MSVC produces a 10kb exe.
创建 exe 后,您始终可以在 exe 上运行 UPX 。
You could always run UPX on your exe after you have created it.
如果您需要小型可执行文件,Tiny C 将为 printf("Hello world!") 编译一个 1536 字节的可执行文件
TinyC 只是 C,而不是 C++,众所周知,它比 gcc 编译速度更快,但可执行文件速度更慢。
编辑:
我刚刚尝试了 cout<"Hello World!" 在 DevC++ 中(捆绑 Mingw 4.8 和 Ide),我得到了一个 4.5 MB 的可执行文件!
If you need small executables, Tiny C will compile a 1536 bytes executable for a printf("Hello world!")
TinyC is only C, not C++ and is known to compile faster and give slower executables than gcc.
EDITED:
I have just tried a cout<"Hello World!" in DevC++ (bundles Mingw 4.8 and an Ide) and i got a 4,5 MB executable!!
当你使用 C++ 标准库时,exe 会很快变大。 如果在剥离调试符号后,您仍然想减小软件的大小,您可以使用像 UPX。 但是,请注意,一些防病毒软件会阻止包含 UPX 的 exe,因为某些病毒很久以前就使用了它。
Well when you use C++ standard library, exe can get big really quickly. If after stripping debug symbol, you still want to reduce the size of your software, you can use a packer like UPX. But, be warned, some antivirus choke on exe packed with UPX as some virus used it a long time ago.
如果您使用“nm”实用程序或其他一些显示 .exe 中内容的程序,您会发现它包含大量某人可能想要使用的类,但您不会。
If you use the "nm" utility or some other program that shows whats in your .exe, you'll see that it contains tons of classes that someone might want to use, but that you don't.
我使用 Cygwin 和 g++ 复制了您的测试。 您的代码使用 -O2 编译为 480k。 在可执行文件上运行 strip 将其减少到 280k。
不过,总的来说,我怀疑您的问题是使用。 标头。 这会导致链接相当大的库。另外,请注意
cout << x
的作用不仅仅是打印。 有场所、溪流和各种幕后的东西。但是,如果具有较小的可执行文件大小是一个真正的关键任务目标,那么请避免它并使用 printf 或 put。 如果不是,那么我会说支付 iostream 的一次性费用并完成它。
I replicated your test using Cygwin and g++. Your code compiled to 480k with -O2. Running strip on the executable reduced it to 280k.
In general, though, I suspect your problem is the use of the <iostream> header. This causes a fairly large library to be linked in. Also, note that
cout << x
does a lot more than just printing. There are locales and streams and all sorts of under-the-hood stuff.If however, having a small executable size is a real, mission-critical objective, then avoid it and use printf or puts. If it's not, then I would say pay the one-time cost of iostream and be done with it.
为什么像 msvc8 这样的其他编译器甚至像 borland c++ 5.5.1 这样的顺序编译器能够生成非常小的可执行文件,但 mingw gcc 却不能呢?
我为以下每个项目快速编译了“hello world”
工具集并观察编译后的可执行文件的大小。 请注意,在
所有这些情况运行时库都是静态链接的并且所有调试
符号已被删除:
有趣的是 gcc 4.4.1 的更高版本生成了比 gcc3.4.5 更大的可执行文件,可能是由于 libstdc++ 版本不同。
那么mingw真的没有办法在链接阶段删除死代码吗?
How is it that other compilers like msvc8 or even an order compiler like borland c++ 5.5.1 are capable of producing very small executables but mingw gcc isn't able to?
I did a quick compile of a 'hello world' for each of the following
toolsets and observed the compiled executable size. Please note that in
all these cases the runtime library is statically linked and all debug
symbols have been stripped:
What's interesting is the later version of gcc 4.4.1 produces an even larger executable than gcc3.4.5, probably due to different version of libstdc++.
So is there really no way to remove dead code during the linking phase for mingw?
大小的主要部分源于相当广泛的运行时库的使用。
因此,在现实生活中,如果您有这样一个简单的应用程序,那么您实际上正在链接一段非常大的“死代码”。
据我所知,没有链接器标志可以跳过链接库的未使用部分。
据我所知,有两种方法可以伪造较小的应用程序:
The major part of the size stems from the use of fairly extensive runtime libraries.
So in real life you are actually linking a very large piece of 'dead code' if you have such a simple application.
As far as I know there are no linker flags to skip the unused parts of a linked library.
There are two ways I know of to fake a smaller application:
答案很晚,但可能对在这里结束搜索“减少 hello world 二进制大小”的新 C++ 用户有帮助:
这是我编译
hello_world.exe
使用 ~20KB:hello_world.cpp
g++ 命令行
UPX 将二进制文件减少约 50%:
Very late answer, but maybe helpful for new c++ users that ended here searching for "reducing hello world binary size":
Here's the steps I've done to compile a
hello_world.exe
with ~20KB:hello_world.cpp
g++ cmd line
UPX to reduce the binary in approx 50%: