如何将标准库静态链接到我的c ++程序?

时间:2014-09-29 15:53:56

标签: c++ linker static-libraries static-linking

我使用Code :: Blocks IDE(v13.12)和GNU GCC编译器。

  1. 我希望链接器为我的程序链接所需运行时库的静态版本,我该怎么做?
  2. 我已经知道我的可执行文件大小会增加,请您告诉我其他缺点吗?
  3. 如何在Visual C ++ Express中执行此操作?

2 个答案:

答案 0 :(得分:24)

由于还没有其他人提出答案,我会试一试。不幸的是,我不知道Code :: Blocks IDE所以我的回答只是部分的。

1如何使用GCC创建静态链接的可执行文件

这不是IDE特定的,但一般适用于GCC(以及许多其他编译器)。假设您在main.cpp中有一个简单的“hello,world”程序(除了标准库和运行时库之外没有外部依赖项)。您可以通过以下方式编译并静态链接它:

  1. main.cpp编译为main.o(输出文件名是隐式的):

    $ g++ -c -Wall main.cpp
    

    -c告诉GCC在编译步骤后停止(不运行链接器)。 -Wall打开大多数诊断消息。如果新手程序员会更频繁地使用它并且更加关注它,那么本网站上的许多问题就不会被问到。 ; - )

  2. 链接main.o(可以列出多个目标文件)静态提取标准和运行时库并将可执行文件放在文件main中:

    $ g++ -o main main.o -static
    

    如果不使用-o main开关,GCC会将最终的可执行文件放在命名不太好的文件a.out中(最终代表“汇编输出”)。

    < / LI>

    特别是在开始时,我强烈建议“手工”做这些事情,因为它有助于更​​好地理解构建工具链。

    事实上,上述两个命令可以合并为一个:

    $ g++ -Wall -o main main.cpp -static
    

    任何合理的IDE都应该有指定此类编译器/链接器标志的选项。

    2静态链接的优点和缺点

    静态链接的原因

    • 您可以将一个文件复制到具有兼容的体系结构和操作系统的任何计算机上,无论安装哪个版本的库,它都可以正常工作。

    • 您可以在共享库不可用的环境中执行该程序。例如,将静态链接的CGI可执行文件放入chroot() jail可能有助于减少Web服务器上的攻击面。

    • 由于不需要动态链接,程序启动可能更快。 (我确信在某些情况下情况正好相反,特别是如果共享库已经为另一个进程加载了。)

    • 由于链接器可以对函数地址进行硬编码,因此函数调用可能更快。

    • 在安装了多个版本的公共库(例如LAPACK)的系统上,静态链接可以帮助确保始终使用特定版本而不必担心正确设置LD_LIBRARY_PATH 。显然,这也是一个缺点,因为现在你无法再选择库而无需重新编译。如果您一直想要相同的版本,为什么首先要安装多个版本?

    原因反对静态链接:

    • 正如您已经提到的,可执行文件的大小可能会急剧增加。这当然主要取决于您链接的库。

    • 如果多个进程同时需要库,操作系统可能足够聪明,只能将共享库的文本部分加载到RAM中一次。通过静态链接,您可以消除此优势,系统可能会更快地运行内存不足。

    • 您的计划不再从图书馆升级中获利。系统管理员不必简单地用一个(希望与ABI兼容)更新的版本替换一个共享库,而是必须重新编译并重新安装使用它的每个程序。这是我认为最严重的缺点。

      例如考虑OpenSSL库。今年早些时候发现并修复了Heartbleed错误时,系统管理员可以安装修补版本的OpenSSL并重新启动所有服务,以便在修补程序发布后的一天内修复漏洞。也就是说,如果他们的服务是动态地与OpenSSL链接。对于那些已经静态链接的人来说,它需要几周时间才能修复到最后一个,并且我非常确定在野外还有专有的“一体化”软件没有看到修复现在。

    • 您的用户无法动态更换共享库。例如,torsocks脚本(和关联的库)允许用户(通过适当地设置LD_PRELOAD)将网络系统库替换为通过Tor网络路由其流量的网络系统库。这甚至适用于那些开发人员从未想过这种可能性的程序。 (这是否安全且好主意是无关辩论的主题。)另一个常见的用例是通过用专用版本替换malloc等来调试或“强化”应用程序。

    在我看来,静态连接的缺点超过了所有但非常特殊情况下的优点。根据经验,如果可以的话,动态链接,如果必须,则动态链接。

    附录

    正如Alf指出的那样(参见注释),有一个特殊的GCC选项可以静态选择性地链接C ++标准库,但不能静态链接整个程序。来自GCC manual

      

    -static-libstdc++

         

    当使用g ++程序链接C ++程序时,它通常会自动链接到libstdc ++。如果libstdc ++作为共享库提供,并且未使用-static选项,那么这将链接到libstdc ++的共享版本。这通常很好。但是,冻结程序使用的libstdc ++版本有时很有用,而不会一直到完全静态链接。 -static-libstdc++选项指示g ++驱动程序静态链接libstdc ++,而不必静态链接其他库。

答案 1 :(得分:1)

在Visual C ++中,/ MT选项执行静态链接,/ MD选项执行动态链接。 (见http://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx

我建议使用/ MD并重新分发C ++运行时,可以从Microsoft免费获得。安装C ++运行时后,任何需要运行时的程序都将继续工作。您需要传递正确的选项以告诉编译器使用哪个运行时。这里有一个很好的解释,Should I compile with /MD or /MT?

在Linux上,我建议重新分发libstdc ++而不是静态链接。如果他们的系统libstdc ++有效,我会让用户使用它。系统库(例如libpthread和libgcc)应该只使用系统默认值。这需要在系统上编译程序,其符号与您要分发的所有Linux版本兼容。

在Mac OS X上,只需使用动态链接重新分发应用程序到libstdc ++。使用相同操作系统版本的任何人都应该能够使用您的程序。