繁体   English   中英

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

[英]How can I statically link standard library to my C++ program?

我正在使用带有 GNU GCC 编译器的 Code::Blocks IDE(v13.12)。

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

由于没有其他人提出答案,我会尝试一下。 不幸的是,我不知道 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 (它曾经最终代表“汇编输出”)中。

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

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

$ 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 手册

-static-libstdc++

当 g++ 程序用于链接 C++ 程序时,它通常会自动链接到 libstdc++。 如果 libstdc++ 可用作共享库,并且未使用-static选项,则此链接针对 libstdc++ 的共享版本。 这通常没问题。 但是,有时冻结程序使用的 libstdc++ 版本而不是一直到完全静态的链接很有用。 -static-libstdc++选项指示 g++ 驱动程序静态链接 libstdc++,而不必静态链接其他库。

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM