【问题标题】:Is it possible to generate small executables with MINGW g++?是否可以使用 MINGW g++ 生成小型可执行文件?
【发布时间】:2011-04-12 10:35:24
【问题描述】:

我知道 MINGW-g++ 可以编译更大的可执行文件,因为它静态链接了很多东西。另一方面,MSVC++ 动态链接来自 VCRedist 包的 DLL,这就是为什么它生成更小的可执行文件的原因。

但是,是否可以在 windows 上以类似的方式使用 g++ 进行编译?不一定是 MINGW-g++,而是我可以与 Qt Creator 一起使用的东西(我没有添加 Qt 作为标签,因为它与问题无关)。

【问题讨论】:

    标签: linker g++ compilation


    【解决方案1】:

    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 运行时?
    • MinGW 总是链接到 VC 运行时(C:\Windows\System32 中的 msvcrt.dll)。 -MD 与 MSVC 的 /MD 完全相同。我认为您误解了 MinGW 是什么/做什么:它像 Visual Studio 编译器一样构建本机可执行文件,但使用 GNU 工具链。因此,有一小部分代码没有在两者之间共享,但始终对用户隐藏。 C++ ABI 也有一点不同(g++ 链接到 GCC 的 libstdc++,而不是 MS,这与 C 库相比,这两种情况都相同),但这总结了不同之处。
    • 你试过剥离二进制文件吗?
    • 是的,我做到了。此外,UPX(也剥离)。我的问题特别是 Qt 应用程序,我看到一些预编译的示例大小约为 100K,但是当我重新编译它们时,它们大了 5-8 倍,而且没有调试版本。谢天谢地,我刚刚了解到将 MS 编译器与 Qt 一起使用只是使用 MSVC 版本 Qt SDK 的问题。
    • @Tamas:在您的情况下,很有可能您使用的 MinGW 版本只有 C++ 标准库的静态构建,这可以解释额外的膨胀。我的使用 libstdc++ 作为 dll。但事实上,将 MSVC 与 Qt 一起使用并不难。
    【解决方案2】:

    为了公平地比较使用静态链接的 VC++ 和 MinGW,我建议在上面的命令行语法中删除编译器开关 /MD。这将导致 Visual C++ 编译器与静态库进行静态链接,但 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这个网站上的讨论中得到这个想法的

    包括 Delphi 在内的大多数 Pascal 编译器也具有相同的链接功能,它被称为智能链接,但生成的静态链接可执行文件比 Visual C++ 编译器生成的要小得多。

    MinGW 使用的链接器非常愚蠢,它不知道膨胀,因此,它链接了许多静态库,包括那些包含根本未在源代码中使用的函数或例程的静态库,从而导致非常膨胀的静态链接二进制文件。

    我建议转储 MinGW 并改用 Visual C++ 编译器。即使是 MinGW 的开发人员似乎也不关心使用静态链接来减少代码膨胀。

    【讨论】:

    • MinGW 中的链接器是否有替代品?我想继续使用 g++,因为我开发的大多数应用程序都旨在交叉编译到 Linux 和 Windows。如果我在两个平台上都使用 g++,那就相对轻松了。
    • 对于插入式替换,我正在尝试在谷歌上搜索,现在,我还没有找到任何合适的答案。由于您确实希望在没有任何代码膨胀的情况下继续使用 g++,因此我建议您为此编译器使用动态链接,并在您希望将其部署到其他机器时在应用程序中包含必要的 DLL 或库以避免依赖问题(也称为Windows 环境中的 DLL 地狱。
    • 如果你将在 Linux 中开发你的应用程序,它附带的 gcc 和 g++ 编译器默认使用动态链接,据我所知,大多数 Linux 发行版都具有应用程序所需的所有运行时库您开发,因此,如果您想在使用 Linux 的其他机器上部署应用程序,则可能无需担心要包含在应用程序中的必要运行时库。
    • 是的,Qt Creator 中的默认设置也将 Qt 本身动态链接到应用程序。建议的部署方法是在应用程序目录中发送 dll。这工作正常。我不完全同意的是,与 VC++ 相比,gcc 的主要 exe 大小更大(即使两者都动态链接到 Qt)。
    • 使用 VC++ 编译的版本与使用动态构建的 MinGW 编译的版本之间的大小差异有多大?如果它很小,那么没有必要为此烦恼。
    【解决方案3】:

    您可以使用 cygwin (www.cygwin.com)。他们使用非常类似于 MSVCRT 的运行时 DLL。那么你的程序当然依赖于 cygwin 运行时(有点重言式,抱歉)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-08
      • 1970-01-01
      • 2013-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多