[英]How can i link my c++ program statically with libstdc++ on osx using clang?
[英]How can I statically link standard library to my C++ program?
我正在使用带有 GNU GCC 编译器的 Code::Blocks IDE(v13.12)。
由于没有其他人提出答案,我会尝试一下。 不幸的是,我不知道 Code::Blocks IDE,所以我的回答只是部分的。
这不是特定于 IDE 的,但通常适用于 GCC(和许多其他编译器)。 假设您在main.cpp
中有一个简单的“hello, world”程序(除了标准库和运行时库之外没有外部依赖项)。 您将通过以下方式编译并静态链接它:
将main.cpp
编译为main.o
(输出文件名是隐式的):
$ g++ -c -Wall main.cpp
-c
告诉 GCC 在编译步骤之后停止(不运行链接器)。 -Wall
打开大多数诊断消息。 如果新手程序员会更频繁地使用它并更多地关注它,那么这个网站上的许多问题都不会被问到。 ;-)
链接main.o
(可以列出多个目标文件)静态拉入标准和运行时库,并将可执行文件放在文件main
中:
$ g++ -o main main.o -static
如果不使用-o main
开关,GCC 会将最终的可执行文件放在名称不太好的文件a.out
(它曾经最终代表“汇编输出”)中。
特别是在开始时,我强烈建议“手动”做这些事情,因为这将有助于更好地理解构建工具链。
事实上,以上两个命令可以合并为一个:
$ g++ -Wall -o main main.cpp -static
任何合理的 IDE 都应该具有指定此类编译器/链接器标志的选项。
静态链接的原因:
您有一个文件,可以将其复制到具有兼容架构和操作系统的任何机器上,并且无论安装什么版本的库,它都可以正常工作。
您可以在共享库不可用的环境中执行程序。 例如,将静态链接的 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.