MINGW g++是否能生成小型可执行文件?

3
我知道MINGW-g++编译的可执行文件比较大,因为它静态链接了许多东西。另一方面,MSVC++动态链接VCRedist包中的DLL,这就是它生成更小可执行文件的原因。
然而,在Windows上是否有可能以类似的方式使用g++进行编译呢?不一定是MINGW-g++,而是我可以在Qt Creator中使用的其他编译器(我没有将Qt作为标签添加,因为它与问题无关)。
3个回答

6

MinGW可以完全能够动态链接到msvcrt运行时。通过这种方式,您无法摆脱的唯一混乱是GCC / MinGW启动代码,它并不是很大。

一个小的C ++测试程序(简单的iostream hello world程序,注意:我对于普通的C printf版本得到了相同的结果)。

#include <iostream>

using namespace std;

int main()
{
cout << "Hello World!" << endl;
return 0;
}

命令行:

g++ main.cpp -MD -Os -s -o test.exe
cl /MD /Os main.cpp /link /out:test2.exe

可执行文件大小:

GCC: 13kB

MSVC: 6kB

虽然这是双倍,但所有必要的启动代码占据了巨大的差异;对于更大的程序,差异微不足道。


使用-MD开关是否会使其链接到VC运行时? - Tamás Szelei
2
MinGW总是链接到VC运行时(C:\ Windows \ System32中的msvcrt.dll)。-MD与MSVC的/MD完全相同。我认为你误解了MinGW的作用:它使用GNU工具链构建本地可执行文件,就像Visual Studio编译器一样。因此,两者之间存在一小部分代码不共享,但所有这些都始终对用户隐藏。此外,C ++ ABI有所不同(g ++链接到GCC的libstdc ++,而不是MS的,与C库相反,在两种情况下都是相同的),但这大致概括了差异。 - rubenvb
你尝试过剥离二进制文件吗? - matejk
是的,我做到了。此外,还使用了UPX(也可以去除)。我的问题特别出现在Qt应用程序上,我发现一些预编译的示例大小约为100K,但当我重新编译它们时,它们的大小增加了5-8倍,并且不是调试版本。幸运的是,我刚刚学到,使用MS编译器与Qt只需要使用MSVC版本的Qt SDK即可。 - Tamás Szelei
@Tamas:在你的情况下非常可能是你使用的MinGW版本只有C++标准库的静态构建,这可能解释了额外的膨胀。我的使用libstdc++作为dll。但确实,使用MSVC和Qt并不难。 - rubenvb

3
为了公平地比较VC++和MinGW的静态链接,建议在上面的命令行语法中删除编译器开关/MD。这将导致Visual C++编译器使用静态库进行静态链接,但是仍然会生成比使用MinGW编译的静态链接可执行文件要小得多的可执行文件。
因为Visual C++编译器使用的链接器具有称为函数级链接的功能,因此链接器仅基于代码中使用的函数链接必要的库。任何未引用或未使用的函数都不会链接到生成的最终可执行文件中,从而导致更小的静态链接二进制文件。
回到上面的例子,使用Visual C++编译器并使用静态链接,命令行语法如下:
cl /Os main.cpp /link /out:test2.exe 您可以注意到,我已删除/MD开关,以便编译器使用静态链接而不是动态链接。
现在,为了使静态链接可执行文件更小,建议使用以下命令行语法:
cl /Ox main.cpp /link /FILEALIGN:512 /OPT:REF /OPT:ICF /INCREMENTAL:NO /out:test2.exe 如果检查生成的二进制文件,您会发现它要小得多,这又是一个静态链接的可执行文件。
实际上,我从http://www.catch22.net/tuts/minexe网站上的讨论中得到了这个想法。
大多数Pascal编译器,包括Delphi,也具有相同的链接功能,称为智能链接,但生成的静态链接可执行文件比Visual C++编译器生成的要小得多。
MinGW使用的链接器非常愚蠢,不知道代码膨胀,因此它链接许多静态库,包括那些不在源代码中使用任何函数或例程的库,导致非常臃肿的静态链接二进制文件。
我建议放弃MinGW并改用Visual C++编译器。即使是MinGW的开发人员似乎也不关心如何通过静态链接减少代码膨胀。

在MinGW中是否有链接器的替代品?我想继续使用g++,因为我开发的大多数应用程序是要进行Linux和Windows的交叉编译。如果我在两个平台上都使用g++,那就相对容易些。 - Tamás Szelei
对于这个可插拔的替代方案,我目前正在尝试在谷歌上搜索,但是我还没有找到合适的答案。既然你真的想继续使用g++而不带任何代码膨胀,我建议你为这个编译器使用动态链接,并在你的应用程序中包含必要的DLL或库,如果你希望将其部署到其他机器上,以避免依赖问题,也就是Windows环境中所谓的DLL地狱。 - NEL
如果您要在Linux上开发应用程序,它自带的gcc和g++编译器默认使用动态链接。据我所知,大多数Linux发行版都具备了您开发应用程序所需的所有运行时库,因此,如果您想在其他使用Linux的机器上部署应用程序,可能无需担心必须包含哪些运行时库。 - NEL
是的,在Qt Creator中的默认设置也会将Qt本身动态链接到应用程序中。建议的部署方法是将dll文件一起打包到应用程序目录中。这种方法可以正常工作。但我不太满意的是,使用gcc编译时主exe文件的大小比VC++大(尽管两者都动态链接到Qt)。 - Tamás Szelei
据我所知,MinGW编译器会向您的应用程序添加必要的启动代码,这也会导致即使在动态构建中,可执行文件也变得更大。实际上,其他编译器也会这样做,包括Microsoft编译器。最可能的是,MinGW编译器添加的启动代码可能与Microsoft编译器使用的代码不同,这就是为什么即使在动态构建中,MinGW可执行文件仍然比Microsoft大的原因。 - NEL
显示剩余4条评论

1

你可以使用cygwin(www.cygwin.com)。它们使用类似于MSVCRT的运行时DLL。然后你的程序当然依赖于cygwin运行时(有点自指,抱歉)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接