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

AmR*_*CPP 7 c++ linker static-libraries static-linking

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

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

5go*_*der 27

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

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

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

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

    $ g++ -c -Wall main.cpp
    
    Run Code Online (Sandbox Code Playgroud)

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

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

    $ g++ -o main main.o -static
    
    Run Code Online (Sandbox Code Playgroud)

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

特别是在开始时,我强烈建议"手动"做这些事情,因为这将有助于更好地理解构建工具链.

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

$ g++ -Wall -o main main.cpp -static
Run Code Online (Sandbox Code Playgroud)

任何合理的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手册:

-static-libstdc++

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

  • 只是问问而已.我简单地记得c ++标准库实现的一些单独的选项.原来它是`-static-libstdc ++`,它允许你静态链接,而不静态链接基本运行时库.文档(https://gcc.gnu.org/onlinedocs/gcc-4.9.1/gcc/Link-Options.html#Link-Options). (3认同)
  • 我想添加另一个优点:静态链接可能(通常)减少可执行文件和库的总大小,因为不会包含未使用的库函数。如果您想减小安装程序的大小并需要附带库,那么您可能需要这样做。 (2认同)